2017-08-08 8 views
6

問題:条件付きグループ別にオカレンスから逆の値を入力したいと思います。私は希望の出力で列Cを生成しようとしています。条件付きグループ別に値を入力してください。

BとC等しくなるように設定し、Aは= 35 <であれば、下位1を記入し、もしA>は35

埋める停止私はdplyrを使用してこのタスクを完了しようとしています。

私の前の質問に似たものにビル:Fill value backwards from occurence by group

入力:

DAT_in = data.frame(ID=c(1,1,1,1, 
         2,2,2, 
         3,3,3, 
         4,4,4,4,4), 
        time=c(1,2,3,4, 
         1,2,3, 
         1,2,3, 
         1,2,3,4,5), 
        A=c(100,35,25,0, 
         100,75,55, 
         100,28,25, 
         100,30,45,25,0), 
        B=c(0,0,0,1, 
         0,0,0, 
         0,0,1, 
         0,0,0,0,1)) 

所望の出力(C):

DAT_out = data.frame(ID=c(1,1,1,1, 
        2,2,2, 
        3,3,3, 
        4,4,4,4,4), 
       time=c(1,2,3,4, 
        1,2,3, 
        1,2,3, 
        1,2,3,4,5), 
       A=c(100,35,25,0, 
        100,75,55, 
        100,28,25, 
        100,30,45,25,0), 
       B=c(0,0,0,1, 
        0,0,0, 
        0,0,1, 
        0,0,0,0,1), 
       C=c(0,1,1,1, 
        0,0,0, 
        0,1,1, 
        0,0,0,1,1)) 
+0

ライブラリーとしてdplyrで修正しましたか? –

+0

私は希望の出力データフレーム 'DAT_out'が間違っていると思います。列Aについては、35があるはずの30の値があります。 – roarkz

+0

あなたの出力にエラーがあります:Aは35(ID 4、時間2の場合) –

答えて

9

これは動作するようです:

それは最後のピリオドからソート後方

  • 仕組み
    library(data.table) 
    setDT(DAT_in) 
    
    DAT_in[order(ID, -time), C := as.integer(cumsum(A > 35) == 0L), by=ID][] 
    
    all.equal(DAT_in$C, DAT_out$C) # TRUE 
    

  • 1としてA > 35までのマーク。

DT[i, v := ..., by=g]カラムvへの割り当て時iによってのみオーダー。初期ソート順はDTです。

as.integerをtrueに設定します。 0にFALSEしてください。

+1

です(OPはdplyrが好きですが、その列は「列の割り当て中に一時的に注文する」をサポートしていませんので、これが言及する価値があると思いました) – Frank

+1

ありがとう、nice @Frank – BEMR

2

最初にこの質問はdplyrを対象としていましたので、ここでは私が思い付いた解決策を紹介します。dplyr Frankのソリューションよりもはるかにエレガントではありませんが、私はすでにそれを行っていますので、「後世のために」書き留めてみてください。

Dat_out_step1 <- DAT_in %>% 
    group_by(ID) %>% 
    filter(B==1) %>% 
    select(-A,-B) %>% 
    summarize(max.time = min(time)) %>% 
    full_join(DAT_in, by = "ID") 


Dat_out_step2 <- Dat_out_step1 %>% 
    group_by(ID) %>% 
    filter(A>35 & time < max.time) %>% 
    select(-A, -B, -max.time) %>% 
    group_by(ID) %>% 
    summarize(min.time = max(time)) 

DAT_out_step3 <- Dat_out_step1 %>% 
    left_join(Dat_out_step2) %>% 
    mutate(C = ifelse(is.na(max.time), 0, 
        (time > min.time & time <= max.time)*1)) %>% 
    select(-max.time, -min.time) 

EDIT:フランクの提案には、代わりにあなたが(最後のブロックで)使用することができますifelse()を使用しての

DAT_out_step3 <- Dat_out_step1 %>% 
    left_join(Dat_out_step2) %>% 
    mutate(C = replace((time > min.time & time <= max.time)*1 ,is.na(max.time), 0)) %>% 
    select(-max.time, -min.time) 

ifelse()習慣は難しい死ぬ...おかげでフランクいることをスポッティング1アウト。

+0

Fyi、 'ifelse 、y) 'は' y *!x'になります。 'ifelse'はそれほど偉大でないという評判を持っているので、私は言います:https://stackoverflow.com/questions/16275149/does-ifelse-really-calculate-both-of-its-vectors-every-time-is- it-slow 'replace(y、x、0)'は私の乗算よりも読みやすい方法です。 – Frank

+0

dplyrオプションありがとう – BEMR

1

dplyrソリューションをお探しの場合は、これが動作しますか?

DAT_in2 <- DAT_in %>% 
    mutate(C = ifelse(A <= 35 & lead(A) <= 35, 1, B)) %>% 
    mutate(C = ifelse(row_number() == n(), B, C)) 

# Check if DAT_in2 and DAT_out are the same 
identical(DAT_in2, DAT_out) 
[1] TRUE 
関連する問題