2017-10-14 55 views
3

我有一個數據幀,看起來像這樣:替代for循環創建連勝列

x <- data.frame("Name" = c("Jorge", "Jorge", "Jorge", "Tom", "Tom", "Jerry", "Tom", "Tom", "Jorge"), 
       "Date" = c("10-13-2017", "10-12-2017", "10-11-2017", "10-10-2017", "10-09-2017", 
          "10-08-2017", "10-07-2017", "10-06-2017", "10-05-2017")) 

我想作一列數是在「條紋」,一個名字是名字柱。最終的結果,我想是這樣的:

Name  Date Streak 
Jorge 10-13-2017  3 
Jorge 10-12-2017  2 
Jorge 10-11-2017  1 
Tom 10-10-2017  2 
Tom 10-09-2017  1 
Jerry 10-08-2017  1 
Tom 10-07-2017  2 
Tom 10-06-2017  1 
Jorge 10-05-2017  1 

我現在擁有的是:

streak <- 1 
for(i in NROW(x):2){ 

j <- i - 1 

if(as.character(x[i, "Name"]) == as.character(x[j, "Name"])){ 
streak = streak + 1 
x[i, "Streak"] = streak 
} 

else{ 
x[i, "Streak"] = 1 
streak <- 1 
} 
} 

這給:

Name  Date Streak 
Jorge 10-13-2017  3 
Jorge 10-12-2017  3 
Jorge 10-11-2017  2 
Tom 10-10-2017  1 
Tom 10-09-2017  2 
Jerry 10-08-2017  1 
Tom 10-07-2017  1 
Tom 10-06-2017  2 
Jorge 10-05-2017  1 

這是不對的,我很努力弄清楚如何獲得預期的輸出。理想情況下,我不需要使用for循環,因爲這是一個包含數萬行的大型數據集,所以它非常緩慢。

所以我的問題:

有沒有辦法做到這一點,而無需使用一個for循環?
2.如何從底部開始計數以便輸出反映所需的條紋?

謝謝你的幫助。

回答

4

可以與rle功能(行程長度編碼)基礎R做到這一點...

x$Streak <- unlist(sapply(rle(as.character(x$Name))$lengths, seq, 1, -1)) 

x 
    Name  Date Streak 
1 Jorge 10-13-2017  3 
2 Jorge 10-12-2017  2 
3 Jorge 10-11-2017  1 
4 Tom 10-10-2017  2 
5 Tom 10-09-2017  1 
6 Jerry 10-08-2017  1 
7 Tom 10-07-2017  2 
8 Tom 10-06-2017  1 
9 Jorge 10-05-2017  1 

這需要每個名稱的遊程長度,產生一個序列計數對於他們中的每一個來說都是一個,然後(通過非列表)將它們變成一個向量。

1

我們可以使用data.table。將'data.frame'轉換爲'data.table'(setDT(x)),按'Name'的遊程長度ID(rleid)分組,獲取行數序列的反向並分配(:=)創建「條紋」列

library(data.table) 
setDT(x)[, Streak := rev(seq_len(.N)), rleid(Name)] 
x 
# Name  Date Streak 
#1: Jorge 10-13-2017  3 
#2: Jorge 10-12-2017  2 
#3: Jorge 10-11-2017  1 
#4: Tom 10-10-2017  2 
#5: Tom 10-09-2017  1 
#6: Jerry 10-08-2017  1 
#7: Tom 10-07-2017  2 
#8: Tom 10-06-2017  1 
#9: Jorge 10-05-2017  1