有条件,请参阅R中data.table中的上一行

时间:2016-02-27 09:42:27

标签: r data.table

我对这些数据有新的问题。因为我的完整数据有这样的形式

a=data.table(A=c(1:10),B=c(1,2,0,2,0,0,3,4,0,2),C=c(2,3,1,4,5,3,6,7,2,2),D=c(1,1,1,1,1,2,2,2,2,2)) 


#     A B C D  
# 1:  1 1 2 1  
# 2:  2 2 3 1  
# 3:  3 0 1 1  
# 4:  4 2 4 1  
# 5:  5 0 5 1  
# 6:  6 0 3 2  
# 7:  7 3 6 2  
# 8:  8 4 7 2  
# 9:  9 0 2 2  
#10: 10 2 2 2  

现在,我想创建一个新列,只要B不是0,就可以计算一个具有B / C的前一行的A倍数值。例如,在第2行,我可以计算d = 2 *(1/2)。但是,在第4行,它必须是4 *(2/3),它不能是4 *(0/1)。 我用

a[, D:= {i1 <- (NA^!B)
list( A*shift(na.locf(i1*B))/shift(na.locf(i1*C)))},by=d]
正如Akrun昨天所推荐的那样。当我按组计算它时,它不起作用。结果就像这样

    A B C d        D
# 1:  1 1 2 1       NA
# 2:  2 2 3 1 1.000000
# 3:  3 0 1 1 2.000000
# 4:  4 2 4 1 2.666667
# 5:  5 0 5 1 2.500000
# 6:  6 0 3 2       NA
# 7:  7 3 6 2 3.500000
# 8:  8 4 7 2 4.571429
# 9:  9 0 2 2 5.142857
# 10: 10 2 2 2       NA

有谁知道这里有什么问题?错误是较长的对象长度不是较短对象长度的倍数。

2 个答案:

答案 0 :(得分:3)

我们可以替换&#39; B&#39; C&#39; C&#39;对应于&#39; 0&#39; 0 &#39; B&#39;作为NA。使用na.locf中的zoo将这些NA值替换为之前的非NA元素,shift元素(默认情况下,它给出的lag为1),除以修改后的列&#39; B&#39;用&#39; C&#39;然后乘以&#39; A&#39;。将输出分配(:=)到新列&#39; D&#39;。

 library(zoo)
 a[B==0, c('B', 'C'):=list(NA, NA)]
 a[, c('B', 'C'):= na.locf(.SD), .SDcols=B:C]
 a[,  D:= {tmp <- shift(.SD[, 2:3, with=FALSE])
           A*(tmp[[1]]/tmp[[2]])}]

或者我们可以使它紧凑。我们得到一个逻辑向量(!B)来检查&#39; 0&#39; &#39; B&#39;中的元素,将其转换为1s和NA(NA^)的向量,乘以列&#39; B&#39;和&#39; C&#39;因此,1s被那些列中的相应元素替换,而NA保持原样。执行na.locf(和以前一样),shift,然后执行乘法/除法。

a[, D:= {i1 <- (NA^!B)
   list( A*shift(na.locf(i1*B))/shift(na.locf(i1*C)))}]

或者不是两次致电shift/na.locf

a[,  D:= {i1 <- (NA^!B)
      tmp <- shift(na.locf(i1*.SD))
      a[['A']]*(tmp[[1]]/tmp[[2]])}, .SDcols=B:C]

答案 1 :(得分:3)

这可以通过滚动连接来完成:

a[, row := .I]
a[, B/C, by=row][V1 != 0][a, A*shift(V1), on="row", roll=TRUE]
# [1]       NA 1.000000 2.000000 2.666667 2.500000 3.000000 3.500000 4.000000
# [9] 5.142857 5.714286