92 votes

Utiliser une valeur de la ligne précédente dans un calcul R data.table

Je veux créer une nouvelle colonne dans un data.table calculée à partir de la valeur actuelle d'une colonne et de la précédente d'une autre. Est-il possible d'accéder aux lignes précédentes?

Par exemple:

 > DT <- data.table(A=1:5, B=1:5*10, C=1:5*100)
> DT
   A  B   C
1: 1 10 100
2: 2 20 200
3: 3 30 300
4: 4 40 400
5: 5 50 500
> DT[, D := C + BPreviousRow] # What is the correct code here?
 

La bonne réponse devrait être

 > DT
   A  B   C   D
1: 1 10 100  NA
2: 2 20 200 210
3: 3 30 300 320
4: 4 40 400 430
5: 5 50 500 540
 

114voto

Arun Points 41689

Ancienne solution:

 DT[, D := C + c(NA, B[1:(.N-1)])][]  # the last [] is to print the result
 

Modifier:

 # following nice point by @mnel in comments to use seq_len to avoid 1:0 issue
DT[, D := C + c(NA, B[seq_len(.N-1)])][]  # the last [] is to print the result

#    A  B   C   D
# 1: 1 10 100  NA
# 2: 2 20 200 210
# 3: 3 30 300 320
# 4: 4 40 400 430
# 5: 5 50 500 540
 

24voto

dnlbrky Points 891

Plusieurs personnes ont répondu à la question spécifique. Voir le code ci-dessous pour une fonction générale que j'utilise dans des situations comme celle-ci qui peuvent être utiles. Plutôt que de simplement obtenir la ligne précédente, vous pouvez aller autant de lignes dans le "passé" ou le "futur" que vous le souhaitez.

 rowShift <- function(x, shiftLen = 1L) {
  r <- (1L + shiftLen):(length(x) + shiftLen)
  r[r<1] <- NA
  return(x[r])
}

# Create column D by adding column C and the value from the previous row of column B:
DT[, D := C + rowShift(B,-1)]

# Get the Old Faithul eruption length from two events ago, and three events in the future:
as.data.table(faithful)[1:5,list(eruptLengthCurrent=eruptions,
                                 eruptLengthTwoPrior=rowShift(eruptions,-2), 
                                 eruptLengthThreeFuture=rowShift(eruptions,3))]
##   eruptLengthCurrent eruptLengthTwoPrior eruptLengthThreeFuture
##1:              3.600                  NA                  2.283
##2:              1.800                  NA                  4.533
##3:              3.333               3.600                     NA
##4:              2.283               1.800                     NA
##5:              4.533               3.333                     NA
 

13voto

Gary Weissman Points 1370

D'après le commentaire de @Steve Lianoglou ci-dessus, pourquoi ne pas simplement:

 DT[, D:= C + c(NA, B[.I - 1]) ]
#    A  B   C   D
# 1: 1 10 100  NA
# 2: 2 20 200 210
# 3: 3 30 300 320
# 4: 4 40 400 430
# 5: 5 50 500 540
 

Et évitez d’utiliser seq_len ou head ou toute autre fonction.

9voto

Ryogi Points 1542

Après la solution d'Arun, des résultats similaires peuvent être obtenus sans se référer à .N

 > DT[, D := C + c(NA, head(B, -1))][]
   A  B   C   D
1: 1 10 100  NA
2: 2 20 200 210
3: 3 30 300 320
4: 4 40 400 430
5: 5 50 500 540
 

1voto

geneorama Points 620

J'ai ajouté un argument de remplissage, modifié certains noms et appelé shift . https://github.com/geneorama/geneorama/blob/master/R/shift.R

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X