2016-02-27 45 views
2

我對這些數據有一個新的問題。因爲我的完整的數據具有這樣參考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 A倍數值的數量/衣櫃前一行C,只要B是不是0.例如,在第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 

任何人都知道這裏的問題是什麼?錯誤是較長的對象長度不是較短的對象長度的倍數。

+0

什麼將是d的第一個元素的輸出? – akrun

+0

D的第一個元素的輸出是NA –

回答

3

我們可以將'B','C'中對應'B'中'0'值的元素替換爲NA。使用na.locfzoo替換那些NA值與先前的非NA元素,shift元素(默認情況下,它給出lag爲1),將修改的列'B'除以'C',然後乘以'A' 。將輸出分配(:=)到新列'D'。

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),檢查'B'中的'0'元素,將其轉換爲1s和NA的向量(NA^),與列'B'和'C'相乘,以便1被替換爲這些列中的相應元素,而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

謝謝。你真的解決了我的問題。它也非常緊湊。 –

+0

嗨,@akrun,請你看一下嗎? –

+0

@ThanhQuang YOu可能需要'... na.locf(i1 * B),na.rm = FALSE)/ shift(na.locf(i1 * C,na.rm = FALSE)...' – akrun

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