data.table

时间:2018-01-15 04:10:00

标签: r loops data.table

我有一个数据表“DT”。现在,我想使列A1:B3等于前一行,然后根据条件更新值,给出整个第一行。每列中没有模式。

       ID title action  value   A1  A2  A3  B1  B2  B3
 1:    1   A3     1       15    7   9   15  45  20  62 
 2:    2   A1     0       22    NA  NA  NA  NA  NA  NA 
 3:    3   B2     1       92    NA  NA  NA  NA  NA  NA 
 4:    4   A2     0       17    NA  NA  NA  NA  NA  NA 
 5:    8   B1     1       55    NA  NA  NA  NA  NA  NA
 6:    6   B3     1       37    NA  NA  NA  NA  NA  NA 
 7:   12   B2     0       16    NA  NA  NA  NA  NA  NA
 8:    8   A1     1       35    NA  NA  NA  NA  NA  NA
 9:    9   B3     1       13    NA  NA  NA  NA  NA  NA

从第2行到第9行,我想为每一行j,我想

 DT[j, A1:B3]=DT[j-1, A1:B3]

然后根据每个相应行中的值更新A1:B3。要更新的元素来自名为“title”的相应列。

对于第2行,从A1B3,从前一行复制7 9 15 45 20 62,然后更改A1DT[2, title]提供此信息),{ {1}}为DT[2, action],因此我们将0插入22,然后将A1移至7,将A2移至{{} 1}},删除原始9A3变为A3(以DT[2, A1:B3]开头的列名称无法推送到22 7 9 45 20 62。)。如果'A''B',则只需替换。

处理完毕后,所需的输出应如下所示:

DT[2, action]

我现在正在使用一个循环来执行此操作,但它非常慢,并且仅在1时才有效,当 ID title action value A1 A2 A3 B1 B2 B3 1: 1 A3 1 15 7 9 15 45 20 62 2: 2 A1 0 22 22 7 9 45 20 62 3: 3 B2 1 92 22 7 9 45 92 62 4: 4 A2 0 17 22 17 7 45 92 62 5: 8 B1 1 55 22 17 7 55 92 62 6: 6 B3 1 37 22 17 7 55 92 37 7: 12 B2 0 16 22 17 7 55 16 92 8: 8 A1 1 35 35 17 7 55 16 92 9: 9 B3 1 13 35 17 7 55 16 13 时,我不确定如何挤入新值。< / p>

action == 1

action == 0for (j in 2:nrow(DT)){ DT[j, A1:B3] <- DT[j-1, A1:B3] if(DT$action[j] == 1) { position <- which.first(colnames(DT) == DT$title[j], use.names = TRUE) DT[j,position] <- DT$value[j] } } 时,它很简单,当action1时,可能会造成混淆。

随时留下评论或参考所需的输出。我很乐意做更多的解释。

1 个答案:

答案 0 :(得分:1)

由于以下几个原因,这是一个棘手的问题:

  1. 迭代地将值从一行复制到下一行,从而应用不同的操作,
  2. 其中一个操作是插入一个值并在列之间移动剩余的值。
  3. 下面的方法将数据从宽格式转换为长格式,因为(2.)使我们能够使用append()函数插入值列式。它使用for循环,因为(1.)和set()函数通过引用更新,即不复制整个数据对象:

    # append row number, then reshape from wide to long format 
    long <- melt(DT[, rn := .I], measure.vars = patterns("^[AB]\\d"), value.name = "val")[order(rn)]
    for (i in seq_len(nrow(DT) - 1L) + 1L){
      # copy the row values from previous row
      set(long, long[rn == i, which = TRUE], "val", long[rn == (i - 1L), .(val)])
      # update values depending on action indicator
      if (long[rn == i, first(action) == 1]) {
        # replace selected value
        idx <- long[rn == i & variable == title, which = TRUE]
        set(long, idx, "val", long[idx[1L], value])
      } else {
        # insert selected value
        pat <- paste0("^", long[rn == i, stringi::stri_sub(first(title), 1L, 1L)])
        idx <- long[rn == i & variable %like% pat, which = TRUE]
        set(long, idx, "val", 
            head( # drop last element after insert
              append(long[idx, val], long[idx[1L], value], 
                     after = long[idx[1L], as.integer(stringi::stri_sub(title, 2L)) - 1L]), 
              -1L))
      }
    }
    # reshape back to wide format
    dcast(long, rn + ... ~ variable, value.var = "val")[, rn := NULL][]
    
       ID title action value A1 A2 A3 B1 B2 B3
    1:  1    A3      1    15  7  9 15 45 20 62
    2:  2    A1      0    22 22  7  9 45 20 62
    3:  3    B2      1    92 22  7  9 45 92 62
    4:  4    A2      0    17 22 17  7 45 92 62
    5:  8    B1      1    55 22 17  7 55 92 62
    6:  6    B3      1    37 22 17  7 55 92 37
    7: 12    B2      0    16 22 17  7 55 16 92
    8:  8    A1      1    35 35 17  7 55 16 92
    9:  9    B3      1    13 35 17  7 55 16 13