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?
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)))
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.
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.
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 shift
data.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 the
décalage(
majby default gives the
décalageas
type = "gal"`). Supprimer le premier observation, c.-à-d. élément NA.
library(data.table)
setDT(df)[, lapply(.SD, function(x) (x- shift(x))[-1])]
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
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