2017-06-12 37 views
0

我有3列,大約是這樣的數據:轉換for循環到-apply函數,其中輸入是數據幀不矢量

uid <- c(1,1,1,1,1,1,2,2,2) 
sale <- c(0,1,1,0,0,0,0,1,0) 
e <- as.data.frame(cbind(uid, sale)) 
e$uid <- as.factor(e$uid) 
e$sincesale <- NA 

對於每一個唯一的ID,我想申請相同的程序 - 計算自上次銷售以來的天數。

我可以很容易地想出可以做到這一點的for-loop。問題是我有數百萬行。所以,完成這個過程需要很長時間。我想在e$uid上使用tapply。但是,tapply只接受向量作爲輸入。

可以使用什麼方法(比循環更快)?

我的for循環:

for (i in 2:length(e$uid)){ 
    #working within the good with the same unique id (uid) 
    if (e$uid[i] == e$uid[i-1]){ 
    if (e$sale[i]==1){ 
     sincesale[i] <- sincesale[i-1]+1 
    } 
    if (e$sale[i]==0){ 
     #if sale just ended, number of days since sale is 1 
     if (e$sale[i-1]==1){ 
     e$sincesale[i] <- 1 
     } 
     #if sale ended a few periods ago add 1 to previous value of "sincesale" 
     if (e$sale[i-1] == 0){ 
     e$sincesale[i] <- e$sincesale[i-1] + 1 
     } 
    } 
    } 
} 

UPD:

好吧,老實說,我嘗試了我自己過去在早上和晚上的工作,但不能拿出解決的新問題。我嘗試使用建議的方法,但是一個小問題是他們從第一行開始計算「sincesale」(因爲即使銷售不從頭開始,銷售== 0對於第一行也是如此)。下面的例子中輸入生成具有for循環(「sincesale」)的結果,並使用建議dplyr(「sincesale4」):

uid <- c(1,1,1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4) 
sale <- c(0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0) 
e <- as.data.frame(cbind(uid, sale)) 
e$uid <- as.factor(e$uid) 

    uid sale first sincesale sincesale4 
1 1 0  1  NA   0 
2 1 0  1  NA   1 
3 1 1  0  NA   1 
4 1 0  0   1   2 
5 1 0  0   2   3 
6 1 0  0   3   4 
7 2 0  1  NA   0 
8 2 1  1  NA   0 
9 2 0  0   1   1 
10 2 1  0  NA   1 
11 3 0  1  NA   0 
12 3 0  1  NA   1 
13 3 0  0  NA   2 
14 3 0  0  NA   3 
15 3 0  0  NA   4 
16 3 0  0  NA   5 
17 3 1  0  NA   5 
18 3 1  0  NA   5 
19 3 0  0   1   6 
20 4 0  1  NA   0 
21 4 0  1  NA   1 
22 4 0  0  NA   2 
+0

只是'e < - data.frame(uid,sale); e $ uid < - as.factor(e $ uid); e $ sincesale < - NA'應該對其進行分類,我相信。 – thelatemail

回答

3

使用ave看每個uid組內,並獲得的所述累加值cumsum非銷售天:

e$sincesale2 <- ave(!e$sale, e$uid, FUN=cumsum)-1 

# uid sale sincesale sincesale2 
#1 1 0  NA   0 
#2 1 1  NA   0 
#3 1 1  NA   0 
#4 1 0   1   1 
#5 1 0   2   2 
#6 1 0   3   3 
#7 2 0  NA   0 
#8 2 1  NA   0 
#9 2 0   1   1 

翻譯成data.table這將是:

library(data.table) 
setDT(e) 
e[, sincesale3 := cumsum(!sale)-1, by=uid] 

或者dplyr與@RonakShah的帽子提示:

library(dplyr) 
e %>% 
    group_by(uid) %>% 
    mutate(sincesale4 = cumsum(!sale)-1)