【问题标题】:Reshape long to wide and keep duplicated rows将长形改成宽形并保留重复的行
【发布时间】:2018-06-04 08:30:48
【问题描述】:

对于给定的数据集,我想将我的数据集从长格式转换为宽格式。我已经使用重塑功能来做到这一点。

id  status      timestamp   
1   assigned   2017-01-02  
1   done       2017-01-03  
1   locked     2017-01-04   
2   assigned   2017-01-02   
2   done       2017-01-03  
2   assigned   2017-01-03  
2   done       2017-01-04 
2   locked     2017-01-05  
3   assigned   2017-01-02  
3   done       2017-01-03 
3   locked     2017-01-04 
...

# reshape function to convert long format to Wide.
temp <- reshape(temp, idvar = "id", timevar = "status", direction = "wide")

结果:

id timestamp.assigned timestamp.done timestamp.locked
1 2017-01-02 2017-01-03 2017-01-04
2 2017-01-02 2017-01-03 2017-01-05
3 2017-01-02 2017-01-03 2017-01-04

当我这样做时,它会删除一些行,例如:对于 id 2,status=assigned 有多行匹配,它占用第一行。

如何在不删除行的情况下转换为宽。基本上,我不想丢失任何数据。

预期结果:
id timestamp.assigned timestamp.done timestamp.locked
1 2017-01-02 2017-01-03 2017-01-04
2 2017-01-02 2017-01-03 2017-01-05
2 2017-01-03 2017-01-04 2017-01-05
3 2017-01-02 2017-01-03 2017-01-04

id timestamp.assigned timestamp.done timestamp.locked
1 2017-01-02 2017-01-03 2017-01-04
2 2017-01-02 2017-01-03 NA
2 2017-01-03 2017-01-04 2017-01-05
3 2017-01-02 2017-01-03 2017-01-04

【问题讨论】:

  • 重复行有什么用?
  • 您的答案是什么?
  • @Onyambu 我已经更新了描述并添加了预期的结果。
  • @hpesoj626 我需要它,因为状态可以再次回到分配状态。时间戳不同,因此需要计算状态之间的周转时间。

标签: r reshape


【解决方案1】:

1。 cumsum()

Esther's approach 为每个新任务编号是可行的方法。

但是,R 已经有 cumsum() 函数可以用于此目的:

temp$key <- cumsum(temp$status == "assigned")
reshape(temp, idvar = c("key", "id"), timevar = "status", direction = "wide")
   id key timestamp.assigned timestamp.done timestamp.locked
1:  1   1         2017-01-02     2017-01-03       2017-01-04
2:  2   2         2017-01-02     2017-01-03             <NA>
3:  2   3         2017-01-03     2017-01-04       2017-01-05
4:  3   4         2017-01-02     2017-01-03       2017-01-04

2。分组cumsum()

尽管这解决了 OP 的原始问题,key 只是在 all ids 中编号 all 分配。如果 OP 希望为每个 id 单独编号分配,我们需要应用按 id 分组的 cumsum()

实现此目的的一种方法是使用data.table 语法:

library(data.table)
setDT(temp)[, key := cumsum(status == "assigned"), by = id]
dcast(temp, id + key ~ status, value.var = "timestamp")
   id key   assigned       done     locked
1:  1   1 2017-01-02 2017-01-03 2017-01-04
2:  2   1 2017-01-02 2017-01-03       <NA>
3:  2   2 2017-01-03 2017-01-04 2017-01-05
4:  3   1 2017-01-02 2017-01-03 2017-01-04

dcast() 是基本 R 的 reshape(..., direction = "wide") 函数的替代品,该函数可从 reshape2data.table 包中获得。

3。分组cumsum() 即时

data.tabledcast()的公式接口也接受表达式。有了这个,没有必要修改temp,通过在整形之前添加key之前。相反,这可以在 重塑时即时完成:

dcast(temp, id + ave(key <- status == "assigned", id, FUN = cumsum) ~ 
        paste0("timestamp.", status))
   id key timestamp.assigned timestamp.done timestamp.locked
1:  1   1         2017-01-02     2017-01-03       2017-01-04
2:  2   1         2017-01-02     2017-01-03             <NA>
3:  2   2         2017-01-03     2017-01-04       2017-01-05
4:  3   1         2017-01-02     2017-01-03       2017-01-04

数据

library(data.table)
temp <- fread(
  "id  status      timestamp   
1   assigned   2017-01-02  
1   done       2017-01-03  
1   locked     2017-01-04   
2   assigned   2017-01-02   
2   done       2017-01-03  
2   assigned   2017-01-03  
2   done       2017-01-04 
2   locked     2017-01-05  
3   assigned   2017-01-02  
3   done       2017-01-03 
3   locked     2017-01-04 ")

【讨论】:

    【解决方案2】:

    您可以做的一件事是添加一个变量,该变量为每个新分配提供一个唯一值。然后你可以用它来塑造你的数据

    i <- 0
    
    temp$key <- sapply(temp$status, function(x) {
      if(x == "assigned") {i <<- i+1; i}
      else {i}
    })
    
    temp
    
       id   status  timestamp key
    1   1 assigned 2017-01-02   1
    2   1     done 2017-01-03   1
    3   1   locked 2017-01-04   1
    4   2 assigned 2017-01-02   2
    5   2     done 2017-01-03   2
    6   2 assigned 2017-01-03   3
    7   2     done 2017-01-04   3
    8   2   locked 2017-01-05   3
    9   3 assigned 2017-01-02   4
    10  3     done 2017-01-03   4
    11  3   locked 2017-01-04   4
    
    temp2 <- reshape(temp, idvar = c("key", "id"), timevar = "status", direction = "wide")
    
    temp2
    
      id key timestamp.assigned timestamp.done timestamp.locked
    1  1   1         2017-01-02     2017-01-03       2017-01-04
    4  2   2         2017-01-02     2017-01-03             <NA>
    6  2   3         2017-01-03     2017-01-04       2017-01-05
    9  3   4         2017-01-02     2017-01-03       2017-01-04
    

    【讨论】:

    • 不错的方法,但 cumsum() 函数已经可以满足您的需求:temp$key &lt;- cumsum(temp$status == "assigned")
    猜你喜欢
    • 1970-01-01
    • 2019-06-13
    • 2021-05-03
    • 2023-01-15
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 2014-07-19
    • 2021-07-23
    相关资源
    最近更新 更多