R Comment puis-je calculer la différence entre les lignes dans une base de données

Voici un exemple simple de mon problème:

> df <- data.frame(ID=1:10,Score=4*10:1)
> df
       ID Score
    1   1    40
    2   2    36
    3   3    32
    4   4    28
    5   5    24
    6   6    20
    7   7    16
    8   8    12
    9   9     8
    10 10     4
    > diff(df)

Error in r[i1] - r[-length(r):-(length(r) - lag + 1L)] : 
  non-numeric argument to binary operator

quelqu'un Peut-il me dire pourquoi cette erreur se produit?

20
demandé sur A5C1D2H2I1M1N2O1R2T1 2013-04-25 14:15:05

6 réponses

diff veut une matrice ou un vecteur plutôt qu'une base de données. Essayez

data.frame(diff(as.matrix(df)))
28
répondu aPaulT 2015-09-22 13:43:00

peut-être vous cherchez quelque chose comme ceci:

> tail(df, -1) - head(df, -1)
   ID Score
2   1    -4
3   1    -4
4   1    -4
5   1    -4
6   1    -4
7   1    -4
8   1    -4
9   1    -4
10  1    -4

vous pouvez soustraire ou ajouter deux data.frame s ensemble s'il s'agit des mêmes dimensions. Donc, ce que nous faisons ici est d'en soustraire un data.frame il manque la première ligne (tail(df, -1)) et celui qui manque la dernière rangée (head(df, -1)) et les soustraire.

20
répondu A5C1D2H2I1M1N2O1R2T1 2013-04-25 10:24:07

parce que df fonctionne sur vecteur ou matrice. Vous pouvez utiliser à appliquer la fonction à travers les colonnes de la sorte:

 apply( df , 2 , diff )
   ID Score
2   1    -4
3   1    -4
4   1    -4
5   1    -4
6   1    -4
7   1    -4
8   1    -4
9   1    -4
10  1    -4

il semble peu probable que vous vouliez calculer la différence en IDs séquentiels, donc vous pourriez choisir de l'appliquer sur toutes les colonnes sauf le premier:

apply( df[-1] , 2 , diff )

Ou vous pouvez utiliser data.table (pas que ça ajoute quoi que ce soit ici, j'ai juste vraiment envie de commencer à l'utiliser!), et je présume à nouveau que vous ne voulez pas postuler diff de la colonne ID:

DT <- data.table(df)
DT[ , list(ID,Score,Diff=diff(Score))  ]
    ID Score Diff
 1:  1    40   -4
 2:  2    36   -4
 3:  3    32   -4
 4:  4    28   -4
 5:  5    24   -4
 6:  6    20   -4
 7:  7    16   -4
 8:  8    12   -4
 9:  9     8   -4
10: 10     4   -4

et grâce à @AnandaMahto une syntaxe alternative qui donne plus de flexibilité pour choisir quelles colonnes l'exécuter pourrait être:

DT[, lapply(.SD, diff), .SDcols = 1:2]

Ici .SDcols = 1:2 signifie que vous voulez appliquer le diff fonction aux colonnes 1 et 2. Si vous avez 20 colonnes et ne veulent pas l'appliquer à ID vous pouvez utiliser .SDcols=2:20 comme un exemple.

8
répondu Simon O'Hanlon 2013-04-25 10:53:44

une autre option utilisant dplyr utiliser mutate_each pour faire une boucle dans toutes les colonnes, obtenir la différence de la colonne (.) avec lag de la colonne (.) et supprimer L'élément NA en haut avec na.omit()

library(dplyr)
df %>%
    mutate_each(funs(. - lag(.))) %>%
    na.omit() 

Ou shiftdata.table. Convertissez les données.image' à 'des données.table' (setDT(df)), boucle à travers les colonnes (lapply(.SD, ..)) and get the difference between the column ( x) and thedécalage(majby default gives thedécalageastype = "gal"`). Supprimer le premier observation, c.-à-d. élément NA.

library(data.table)
setDT(df)[, lapply(.SD, function(x) (x- shift(x))[-1])]
5
répondu akrun 2016-08-05 08:40:09

ajouter ceci quelques années plus tard pour être complet - vous pouvez utiliser un simple [.data.frame subseting pour atteindre ce trop

df[-1, ] - df[-nrow(df), ]
#    ID Score
# 2   1    -4
# 3   1    -4
# 4   1    -4
# 5   1    -4
# 6   1    -4
# 7   1    -4
# 8   1    -4
# 9   1    -4
# 10  1    -4
4
répondu David Arenburg 2016-08-05 08:25:30

je voudrais montrer une autre façon de faire ce genre de choses, même si souvent j'ai le sentiment que ce n'est pas apprécié de faire ça de cette façon: utiliser sql.

sqldf(paste("SELECT a.ID,a.Score"
            ,"      , a.Score - (SELECT b.Score"
            ,"                   FROM df b"
            ,"                   WHERE b.ID < a.ID"
            ,"                   ORDER BY b.ID DESC"
            ,"                   ) diff"
            ," FROM df a"
            )
      )

le code semble compliqué mais il ne l'est pas et il a un certain avantage, comme vous pouvez le voir aux résultats:

    ID Score diff
 1   1    40 <NA>
 2   2    36 -4.0
 3   3    32 -4.0
 4   4    28 -4.0
 5   5    24 -4.0
 6   6    20 -4.0
 7   7    16 -4.0
 8   8    12 -4.0
 9   9     8 -4.0
 10 10     4 -4.0

un avantage est que vous utilisez la base de données originale (sans conversion dans d'autres classes) et vous obtenez une base de données (mettez - la dans res< -....). Un autre avantage est que vous avez toujours toutes les rangées. Et le troisième avantage est que vous pouvez facilement envisager de regrouper les facteurs. Par exemple:

df2 <- data.frame(ID=1:10,grp=rep(c("v","w"), each=5),Score=4*10:1)

sqldf(paste("SELECT a.ID,a.grp,a.Score"
            ,"      , a.Score - (SELECT b.Score"
            ,"                   FROM df2 b"
            ,"                   WHERE b.ID < a.ID"
            ,"                         AND a.grp = b.grp"
            ,"                   ORDER BY b.ID DESC"
            ,"                   ) diff"
     ," FROM df2 a"
     )
)


   ID grp Score diff
1   1   v    40 <NA>
2   2   v    36 -4.0
3   3   v    32 -4.0
4   4   v    28 -4.0
5   5   v    24 -4.0
6   6   w    20 <NA>
7   7   w    16 -4.0
8   8   w    12 -4.0
9   9   w     8 -4.0
10 10   w     4 -4.0
3
répondu giordano 2015-03-16 17:22:39