web-dev-qa-db-fra.com

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
70
Corone

Avec shift() implémenté dans v1.9.6 , cela est assez simple.

DT[ , D := C + shift(B, 1L, type="lag")]
# or equivalently, in this case,
DT[ , D := C + shift(B)]

De NOUVELLES :

  1. La nouvelle fonction shift() implémente rapidement lead/lag De vector , list , data.frames ou data.tables . Il faut un argument type qui peut être soit "lag" (par défaut) ou "lead ". Il permet une utilisation très pratique avec := Ou set(). Par exemple: DT[, (cols) := shift(.SD, 1L), by=id]. Veuillez consulter ?shift Pour plus d'informations.

Voir l'historique pour les réponses précédentes.

91
Arun

En utilisant dplyr vous pourriez faire:

mutate(DT, D = lag(B) + C)

Qui donne:

#   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
26
Steven Beaupré

Plusieurs personnes ont répondu à la question spécifique. Voir le code ci-dessous pour une fonction à usage général 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
19
dnlbrky

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.

12
Gary Weissman

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
9
Ryogi

Voici ma solution intuitive:

#create data frame
df <- data.frame(A=1:5, B=seq(10,50,10), C=seq(100,500, 100))`
#subtract the shift from num rows
shift  <- 1 #in this case the shift is 1
invshift <- nrow(df) - shift
#Now create the new column
df$D <- c(NA, head(df$B, invshift)+tail(df$C, invshift))`

Ici, invshift, le nombre de lignes moins 1, est 4. nrow(df) vous donne le nombre de lignes dans un cadre de données ou dans un vecteur. De même, si vous souhaitez conserver des valeurs antérieures, soustrayez à nrow 2, 3, ... etc., et insérez également NA au début.

1
Abdullah Al Mahmud

J'ai ajouté un argument de remplissage et changé quelques noms et je l'ai appelé shift. https://github.com/geneorama/geneorama/blob/master/R/shift.R

1
geneorama