2016-01-27 3 views
2

Je suis nouveau à R. J'ai une trame de données dans R comme suitRésumant les comptes dans une trame de données en utilisant la fenêtre coulissante

df <- data.frame(ID=c(rep("A1",10),rep("A2",13),rep("A3",12)), 
       Values=c(10,2,4,23,10,5,20,15,13,21,15,9,19,5,14,25,18,19,31,26,4,21,4,6,7,12,15,18,25,20,16,29,21,19,10)) 

Pour chaque ID, je voudrais résumer les comptes dans la colonne « Valeurs » dans une fenêtre coulissante pour toutes les 3 positions. Voici la trame de données est un extrait de df qui ne comprend que les enregistrements correspondant à A1:

ID Values 
A1  10 
A1  2 
A1  4 
A1  23 
A1  10 
A1  5 
A1  20 
A1  15 
A1  13 
A1  21 

Je voudrais prendre 3 entrées à temps et somme et passer à 3 prochaines entrées. Lorsque les fenêtres glissantes ne peuvent pas accueillir 3 entrées, je passe ces valeurs.

Pour un exemple, Window_1 commence à partir de la première valeur (10), tandis que window_2 commence à partir de la deuxième valeur (2) et window_3 commence à partir de la troisième valeur (4).

window_1 = [10+2+4] + [23+10+5] + [20+15+13] = 102 
window_2 = [2+4+23] + [10+5+20] + [15+13+21] = 113 
window_3 = [4+23+10] + [5+20+15] = 77 

et de faire rapport dans une trame de données comme suit:

ID Window_1 Window_2 Window_3 
A1 102  113  77 

De même, je voudrais somme les chefs d'accusation dans la colonne Values pour everyid dans la trame de données « df » et faire rapport dans un data.frmae comme suit:

ID window_1 window_2 window_3 
A1  102  113   77 
A2  206  195   161 
A3  198  163   175 

J'ai essayé le code suivant

sum_win_3=0 
sum_win_2=0 
sum_win_1=0 
win_1_counts=0 
win_2_counts=0 
win_3_counts=0 

for (i in seq(1,length(df$Values),3)) 
{ 

    if((i+i+1+i+2) %% 3 == 0) 
    { 
    win_1_counts=df$Values[i]+df$Values[i+1]+df$Values[i+2] 
    win_1_counts[is.na(win_1_counts)]=0 
    #print(win_1_counts) 
    } 
    sum_win_1=sum_win_1+win_1_counts 
} 
#print(sum_win_1) 

for (j in seq(2,length(df$Values),3)) 
{ 
    if((j+j+1+j+2) %% 3 == 0) 
    { 
    win_2_counts=df$Values[j]+df$Values[j+1]+df$Values[j+2] 
    win_2_counts[is.na(win_2_counts)]=0 
    #print(win_2_counts) 
    } 
    sum_win_2=sum_win_2+win_2_counts 
} 
#print(sum_win_2) 

for (k in seq(3,length(df$Values),3)) 
{ 
    if((k+k+1+k+2) %% 3 == 0) 
    { 
    win_3_counts=df$Values[k]+df$Values[k+1]+df$Values[k+2] 
    win_3_counts[is.na(win_3_counts)]=0 
    #print(win_3_counts) 
    } 
    #sum_win_3=sum_win_3+win_3_counts 
} 
print(sum_win_3) 
output=data.frame(ID=df[1],Window_1=sum_win_1,Window_2=sum_win_2,Window_3=sum_win_3) 

Le code ci-dessus résume les comptes de window_1, windows_2 et window_3 en regroupant tous les ID au lieu de les traiter séparément.
Veuillez me guider pour obtenir la sortie dans le format désiré indiqué ci-dessus. Merci à l'avance

+0

Les positions de début/fin et la longueur des fenêtres de même pour chaque ID? – beetroot

+1

Vous pourriez regarder le paquet 'zoo' qui a quelques fonctions d'application de roulement. Cela peut être moins douloureux que d'écrire vos propres boucles (lentes). Pensez également à rechercher des fonctions qui calculent les moyens de déplacement. Vous pouvez convertir une moyenne mobile en une somme mobile en multipliant la moyenne par le nombre d'observations qui y sont entrées. – russellpierce

+1

Pourquoi dans la troisième fenêtre pour 'A1' vous n'incluez pas aussi 13 et 21? –

Répondre

8

Utilisation du data.table package, je l'aborder comme suit:

library(data.table) 
setDT(df)[, .(w1 = sum(Values[1:(3*(.N%/%3))]), 
       w2 = sum(Values[2:(3*((.N-1)%/%3)+1)]), 
       w3 = sum(Values[3:(3*((.N-2)%/%3)+2)])), by = ID] 

qui donne:

ID w1 w2 w3 
1: A1 102 113 77 
2: A2 206 195 161 
3: A3 198 163 175 

Ou pour éviter la répétition (à @ Thanx Cath):

setDT(df)[, lapply(1:3, function(i) {sum(Values[i:(3*((.N-i+1)%/%3)+(i-1))])}), by = ID] 

whi ch donne:

ID V1 V2 V3 
1: A1 102 113 77 
2: A2 206 195 161 
3: A3 198 163 175 

Si vous souhaitez renommer le V1, V2 & V3 variables, vous pouvez le faire par la suite, mais vous pouvez aussi le faire:

cols <- c("w1","w2","w3") 
setDT(df)[, (cols) := lapply(1:3, function(i) {sum(Values[i:(3*((.N-i+1)%/%3)+(i-1))])}), by = ID] 
+0

plus directement:' setDT (df) [, lapidaire (1: 3, la fonction (i) {sum (Val ues [i: (3 * ((.N-i + 1)% /% 3) + (i-1))])}), par = ID] '(et en évitant la répétition ;-)) – Cath

5

Cela semble fonctionner:

library(zoo) 
wins = function(x, w) 
    rollapply(x, width = w*((length(x)-seq(w)+1) %/% w), align = "left", sum) 

aggregate(Values ~ ID, df, wins, 3) 
# ID Values.1 Values.2 Values.3 
# 1 A1  102  113  77 
# 2 A2  206  195  161 
# 3 A3  198  163  175 

C'est la seule réponse jusqu'à présent pour effectuer le calcul sur une base de roulement, ce qui est généralement plus efficace.

5

Cela pourrait se faire en utilisant tapply et aggregate

sumf <- function(x1){ 
      sum(tapply(x1, 
         (seq_along(x1) -1) %/%3, 
         function(x) ifelse(length(x) == 3, sum(x), 0))) 
     } 

aggregate(Values ~ ID, data = df, 
      FUN = function(y){ 
       cbind(sumf(y), sumf(y[-1]), sumf(y[-c(1,2)])) 
      }) 

# Group.1 x.1 x.2 x.3 
#1  A1 102 113 77 
#2  A2 206 195 161 
#3  A3 198 163 175 

Cela peut aussi être fait en utilisant filter

sum.filter <- function(z) tapply(head(tail(as.numeric(
    filter(z, c(1,1,1))),-1), -1), 
    0:(length(z)-3) %% 3 +1, sum) 

aggregate(Values ~ ID, data = df, FUN = function(y){ cbind(sum.filter(y))})