2016-05-27 25 views
1

我有一個隨機「日期」上的「運動員」在比賽中玩「匹配」(「匹配」== 1)的數據集。例如:相對於R中某個特定條件的行位置

df <- data.frame(matrix(nrow = 80, ncol = 5)) 
colnames(df) <- c("Athlete", "Date", "Match", "DaysAfter", "DaysBefore") 
df[,"Athlete"] <- c(rep(1, 20), rep(2,20), rep(3, 20), rep(4, 20)) 
df[,"Date"] <- rep(1:20, 4) 
df[,"Match"] <- c(0,0,0,0,1,0,0,1,0,0) 

我想用兩個變量:

df$DaysAfter <- # number of days after last "Match" (for each "Athlete"). 
df$DaysBefore <- # number of days before next "Match" (for each "Athlete"). 

PS!當「匹配」== 1時,則「DaysAfter」和「DaysBefore」應爲0. 當「DaysAfter」之前和「DaysBefore」之後沒有匹配時,顯示NA(請參閱示例)。

我想要的數據集看起來像這樣:

Ath Dat Mat DA DB 
1 1 0 NA -4 
1 2 0 NA -3 
1 3 0 NA -2 
1 4 0 NA -1 
1 5 1 0 0 
1 6 0 1 -2 
1 7 0 2 -1 
1 8 1 0 0 
1 9 0 1 -4 
1 10 0 2 -3 
1 11 0 3 -2 
1 12 0 4 -1 
1 13 1 0 0 
1 14 0 1 -2 
1 15 0 2 -1 
1 16 1 0 0 
1 17 0 1 NA 
1 18 0 2 NA 
1 19 0 3 NA 
1 20 0 4 NA 
2 1 0 NA -4 
2 2 0 NA -3 
etc. 

我怎樣才能做到這一點?

回答

2

我們可以使用data.table。將'data.frame'轉換爲'data.table'(setDT(df)),按'運動員'分組,另一個分組變量基於'Match' 1)DA - 因爲我們需要NA,直到匹配中的第一個元素爲止,創建一個邏輯條件爲if/else,這樣all'Match'中的0元素將乘以'NA'(NA * any號碼返回NA)。當我們按照cumsum進行分組時,只有第一組的所有元素都爲0,因此部分得到了解決。 else條件獲取行的序列並從中減去1(`.seq_len(.N)-1)。 2)DB - 我們將'匹配'與行數(.N)相乘,然後從相反序列中減去(.N:1)。一旦我們完成了這一步,最後一部分就是在'匹配'中的最後1之後爲列中的元素創建NA。按'運動員'分組,我們得到'Match'(下一個元素)中的最後1到行數(.N)之間的序列的行索引(.I),並將'DB'分配給基於NA的序列(:=)在那個指數上。

library(data.table) 
df1 <- setDT(df)[, c("DA", "DB") := list(if(all(!Match)) NA*Match else 
    seq_len(.N)-1,Match*(.N) -(.N:1)) , by = .(cumsum(Match==1), Athlete)] 
df1[df1[, .I[(max(which(Match==1))+1):.N] , by = Athlete]$V1, DB:= NA][] 
# Athlete Date Match DA DB 
# 1:  1 1  0 NA -4 
# 2:  1 2  0 NA -3 
# 3:  1 3  0 NA -2 
# 4:  1 4  0 NA -1 
# 5:  1 5  1 0 0 
# 6:  1 6  0 1 -2 
# 7:  1 7  0 2 -1 
# 8:  1 8  1 0 0 
# 9:  1 9  0 1 -6 
#10:  1 10  0 2 -5 
#11:  1 11  0 3 -4 
#12:  1 12  0 4 -3 
#13:  1 13  0 5 -2 
#14:  1 14  0 6 -1 
#15:  1 15  1 0 0 
#16:  1 16  0 1 -2 
#17:  1 17  0 2 -1 
#18:  1 18  1 0 0 
#19:  1 19  0 1 NA 
#20:  1 20  0 2 NA 
#21:  2 1  0 NA -4 
#22:  2 2  0 NA -3 
#23:  2 3  0 NA -2 
#24:  2 4  0 NA -1 
#25:  2 5  1 0 0 
#26:  2 6  0 1 -2 
#27:  2 7  0 2 -1 
#28:  2 8  1 0 0 
#29:  2 9  0 1 -6 
#30:  2 10  0 2 -5 
#31:  2 11  0 3 -4 
#32:  2 12  0 4 -3 
#33:  2 13  0 5 -2 
#34:  2 14  0 6 -1 
#35:  2 15  1 0 0 
#36:  2 16  0 1 -2 
#37:  2 17  0 2 -1 
#38:  2 18  1 0 0 
#39:  2 19  0 1 NA 
#40:  2 20  0 2 NA 
#41:  3 1  0 NA -4 
#42:  3 2  0 NA -3 
#43:  3 3  0 NA -2 
#44:  3 4  0 NA -1 
#45:  3 5  1 0 0 
#46:  3 6  0 1 -2 
#47:  3 7  0 2 -1 
#48:  3 8  1 0 0 
#49:  3 9  0 1 -6 
#50:  3 10  0 2 -5 
#51:  3 11  0 3 -4 
#52:  3 12  0 4 -3 
#53:  3 13  0 5 -2 
#54:  3 14  0 6 -1 
#55:  3 15  1 0 0 
#56:  3 16  0 1 -2 
#57:  3 17  0 2 -1 
#58:  3 18  1 0 0 
#59:  3 19  0 1 NA 
#60:  3 20  0 2 NA 
#61:  4 1  0 NA -4 
#62:  4 2  0 NA -3 
#63:  4 3  0 NA -2 
#64:  4 4  0 NA -1 
#65:  4 5  1 0 0 
#66:  4 6  0 1 -2 
#67:  4 7  0 2 -1 
#68:  4 8  1 0 0 
#69:  4 9  0 1 -6 
#70:  4 10  0 2 -5 
#71:  4 11  0 3 -4 
#72:  4 12  0 4 -3 
#73:  4 13  0 5 -2 
#74:  4 14  0 6 -1 
#75:  4 15  1 0 0 
#76:  4 16  0 1 -2 
#77:  4 17  0 2 -1 
#78:  4 18  1 0 0 
#79:  4 19  0 1 NA 
#80:  4 20  0 2 NA 
+0

這並不完全顯示希望的結果。第19行和第20行有錯誤的結果。NA將是正確的 19:1 19 0 1 NA 1 -2 20:1 20 0 2 NA 2 -1 21:2 1 0 NA -4 NA -4 22:2 0 0 NA -3 NA - 3 –

+0

@Oto_K您能否確認輸出是否更新正確 – akrun

+1

現在是正確的。 –

1

此代碼應工作:

unique_list<-(unique(df$Athlete)) 
for(k in (1:length(unique_list))){ 
index<-c(1:dim(df)[1])[df$Athlete==unique_list[k]] 
count=NA 
for(j in index){ 
    if(df$Mat[j]==1){ 
     count=0 
     }else{ 
    count=count+1 
    } 
    df$DaysAfter[j]=count 
    } 
    count=NA 
    for(j in index[c(length(index):1)]){ 
    if(df$Mat[j]==1){ 
     count=0 
     }else{ 
    count=count-1 
    } 
    df$DaysBefore[j]=count 
    } 

} 
+0

謝謝。這幾乎是正確的。我需要爲每個運動員單獨運行代碼,以便運動員之間不會發生重疊。可能嗎? – havard

+0

現在工作嗎? –

0

我曾經寫過以下功能:

cumsum.r <- function (vals, restart) 
{ 
    if (!is.vector(vals) || !is.vector(restart)) 
     stop("expect vectors") 
    if (length(vals) != length(restart)) 
     stop("different length") 
    len = length(vals) 
    restart[1] = T 
    ind = which(restart) 
    ind = rep(ind, c(ind[-1], len + 1) - ind) 
    vals.c = cumsum(vals) 
    vals.c - vals.c[ind] + vals[ind] 
} 

它執行cumsum,但從零開始重新啓動時= TRUE。

對於 「天后」,你需要

new.ath <- c(TRUE, df$Ath[-1]==df$Ath[-length(df$Ath)]) 
restart <- df$Math==1 | new.ath 
days.after <- cumsum.r(1-restart, restart) 

爲days.before你需要

rr <- rev(restart) 
days.before <- -rev(cumsum.r(1-rr, rr)) 

(這不把來港定居,但你也可以使用這個cumsum.r對於NAS )

相關問題