2017-10-05 52 views
-2

考慮測試數據集更新列值

test = data.table("a"=c(NA,NA, 0, NA, NA), "b"=c(1,3,4,7,8), "c"=c(NA, 2,1,3,1), "group"=c(1,1,1,1,1)) 
    a b c group 
1: NA 1 NA 1 
2: NA 3 2 1 
3: 0 4 1 1 
4: NA 7 3 1 
5: 0 8 1 1 
6: NA 9 1 1 

我想更新一列的值,使得:

t = a_{i-1}+c_i 
    if(is.na(a_i)) { 
    a_i = t  
    } 

這將導致以下數據集:

a b c group 
1: NA 1 NA 1 
2: NA 3 2 1 
3: 0 4 1 1 
4: 3 7 3 1 
5: 0 8 1 1 
6: 1 9 1 1 

我將這個例子簡化爲一個組,但可以有多個。我寧願避免使用循環解決方案,因爲我的實際數據集有數百萬行。

+1

這是因爲'NA'加上任何東西仍然是'NA'。第4行評估「0 + 3 = 3」,第5行評估第4行(它還沒有被替換)中的「NA」加上1,併產生「NA」。如果你想按順序更新*,你不能使用':='或'* apply'結構,你將不得不使用'for'循環或類似的。 – JDL

+1

爲什麼a行在第3行保持等於0?爲什麼不是所有的「NA」? – eddi

回答

0

當我在第一個非NAa之前有NA的值時,我不清楚邏輯是什麼。我認爲它是保持當前值a。在這種情況下,那麼這可能是你正在尋找前鋒:

> library(zoo) 
> test = data.table("a"=c(NA,NA, 0, NA, NA, 1, 2), 
+     "b"=c(1,3,4,7,8, 9, 10), 
+     "c"=c(NA, 2,1,3,1, 1, 2), 
+     "group"=c(1,1,1,1,1,1, 1)) 
> test 
    a b c group 
1: NA 1 NA  1 
2: NA 3 2  1 
3: 0 4 1  1 
4: NA 7 3  1 
5: NA 8 1  1 
6: 1 9 1  1 
7: 2 10 2  1 
> 
> test[, `:=`(tmp_idx = shift(cumsum(!is.na(a)), fill = 0) > 0)][ 
+ , c_cum := cumsum(c), by = tmp_idx][ 
+  tmp_idx == 0, c_cum := 0][ 
+  tmp_idx == TRUE, a := NA][ 
+   , a := na.locf(a, na.rm = FALSE)] 
> test 
    a b c group tmp_idx c_cum 
1: NA 1 NA  1 FALSE  0 
2: NA 3 2  1 FALSE  0 
3: 0 4 1  1 FALSE  0 
4: 0 7 3  1 TRUE  3 
5: 0 8 1  1 TRUE  4 
6: 0 9 1  1 TRUE  5 
7: 0 10 2  1 TRUE  7 
> 
> test[, a := ifelse(is.na(shift(a)), a, shift(a)) + c_cum][ 
+ , `:=`(tmp_idx = NULL, c_cum = NULL)] 
> test 
    a b c group 
1: NA 1 NA  1 
2: NA 3 2  1 
3: 0 4 1  1 
4: 3 7 3  1 
5: 4 8 1  1 
6: 5 9 1  1 
7: 7 10 2  1 

如果你有多個組,然後使用上述上.SD[.data.table裏面調用一個by說法。

+0

有可能更聰明的方法來填寫第一個非'NA'值,然後使用上面的'zoo :: na.locf'函數。 –

+0

感謝本傑明的回覆。我犯了一個錯誤,沒有具體說明如果你有NA,然後再添加一些數字會發生什麼。在你的情況下繼續計數,在我的例子中,我想用NA之後的值重新啓動計數器。在這種情況下你的解決方案將無法工作:( – user1217406