【问题标题】:Compare consecutive rows in data.table and replace row values比较 data.table 中的连续行并替换行值
【发布时间】:2014-06-24 19:24:05
【问题描述】:

我在 R 中有一个 data.table,其中包含在不同时间点收集的每个用户的多个状态值。我想比较连续时间点的状态值,并在状态发生变化时用标志更新行。请参阅下面的示例

DT_A <- data.table(sid=c(1,1,2,2,2,3,3), date=as.Date(c("2014-06-22","2014-06-23","2014-06-22","2014-06-23", "2014-06-24","2014-06-22","2014-06-23")), Status1 = c("A","B","A","A","B","A","A"), Status2 = c("C","C","C","C","D","D","E"))
DT_A_Final <- data.table(sid=c(1,1,2,2,2,3,3), date=as.Date(c("2014-06-22","2014-06-23","2014-06-22","2014-06-23", "2014-06-24","2014-06-22","2014-06-23")), Status1 = c("0","1","0","0","1","0","0"), Status2 = c("0","0","0","0","1","0","1"))

原始数据表DT_A是

    sid date    Status1 Status2
1   1   2014-06-22  A   C
2   1   2014-06-23  B   C
3   2   2014-06-22  A   C
4   2   2014-06-23  A   C
5   2   2014-06-24  B   D
6   3   2014-06-22  A   D
7   3   2014-06-23  A   E

最终需要的数据表是DT_A_final

    sid date    Status1 Status2
1   1   2014-06-22  0   0
2   1   2014-06-23  1   0
3   2   2014-06-22  0   0
4   2   2014-06-23  0   0
5   2   2014-06-24  1   1
6   3   2014-06-22  0   0
7   3   2014-06-23  0   1

请帮助我如何实现这一目标?

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    这是一个选项:

    DT_A[, 
      c("S1Change", "S2Change") := 
        lapply(.SD, function(x) c(0, head(x, -1L) != tail(x, -1L))),
      .SDcols=c("Status1", "Status2"),   # .SD contains just these columns
      by=sid
    ]
    

    在这里,我们创建了两个新列,我们用lapply 填充.SD(定义为仅包含Status1Status2)。该函数将除第一个列之外的所有值与同一列除最后一个之外的所有值进行比较。每当列发生更改时,这将返回 TRUE。我们在开头添加 0,因为第一个值永远不会改变;这也将结果强制转换为数字向量(感谢 eddi)。

    然后,我们只需 by sid,瞧:

       sid       date Status1 Status2 S1Change S2Change
    1:   1 2014-06-22       A       C        0        0
    2:   1 2014-06-23       B       C        1        0
    3:   2 2014-06-22       A       C        0        0
    4:   2 2014-06-23       A       C        0        0
    5:   2 2014-06-24       B       D        1        1
    6:   3 2014-06-22       A       D        0        0
    7:   3 2014-06-23       A       E        0        1
    

    如果需要,您可以轻松地将其子集以删除原始状态列。无法重复使用它们,因为结果的数据类型与原始数据类型不同(数字与字符)。

    【讨论】:

    • 你可以用as.integer(c(FALSE, ...代替c(0L, ...来达到同样的效果
    【解决方案2】:

    dplyr 方法也适用于此。首先创建一个函数,将向量中的所有元素与第一个元素进行比较,然后将其应用于所有“状态”变量:

    library(dplyr)
    library(magrittr)
    
    equal_first <- function(x) {
      x %>% equals(x[1]) %>% not %>% as.numeric
    }
    
    DT_A %>%
      group_by(sid) %>%
      mutate_each(funs(equal_first),starts_with("Status"))
      sid       date Status1 Status2
    1   1 2014-06-22       0       0
    2   1 2014-06-23       1       0
    3   2 2014-06-22       0       0
    4   2 2014-06-23       0       0
    5   2 2014-06-24       1       1
    6   3 2014-06-22       0       0
    7   3 2014-06-23       0       1
    

    如果您对每个用户有多个状态更改,您希望与之前的值进行比较,而不是第一个:

    equal_prev <- function(x) {
      x %>% equals(lag(x, default = x[1])) %>% not %>% as.numeric
    }
    
    DT_A %>%
      group_by(sid) %>%
      mutate_each(funs(equal_prev),starts_with("Status"))
    

    【讨论】:

    • 安德鲁,不能让它与dplyr 0.2 一起工作(eval(expr,envir,enclos)中的错误:找不到函数“equals”)。我认为这可能无法识别状态的多个变化(想象一下,对于一个特定的sid,序列 A A B B C C,应该返回 0 0 1 0 1 0,我认为这将返回 0 0 1 1 1 1,但不能检查)。
    • @BrodieG 你说得对,函数equals== 的别名,来自magrittr。已编辑!
    • @BrodieG 实际上这种方法只会标记一个状态变化。如果需要更通用,我想我会以不同的方式来解决它——也许通过lag
    • 谢谢,成功了。我有一个没有别名的旧版本 magrittr
    • @BrodieG 很酷。我再次编辑以展示我将如何使用lag 来观察多个状态变化。
    【解决方案3】:

    一种使用set的方法

    for(col in c('Status1','Status2')){
      ones <-  DT_A[, .I[1L]  ,by=c('sid',col)][,V1[-1L],by=sid][['V1']]
    
      set(DT_A, j=col,value='0')
      set(DT_A, j=col,i=ones,value='1')
    
    }
    

    注意我保留了Status1/Status2 作为字符变量,要创建整数变量,请使用

    for(col in c('Status1','Status2')){
      ones <-  DT_A[, .I[1L]  ,by=c('sid',col)][,V1[-1L],by=sid][['V1']]
      set(DT_A, j=col, value=NULL)
      set(DT_A, j=col,value=0L)
      set(DT_A, j=col,i=ones,value=1L)
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-03
      • 1970-01-01
      • 1970-01-01
      • 2020-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多