Modifier - Cette question était initialement intitulée << Remodelage des données longues à larges dans R >>
J'apprends juste le R et j'essaie de trouver des moyens de l'appliquer pour aider les autres dans ma vie. En tant que test, je travaille à remodeler certaines données et j'ai du mal à suivre les exemples que j'ai trouvés en ligne. Ce que je commence ressemble à ceci:
ID Obs 1 Obs 2 Obs 3
1 43 48 37
1 27 29 22
1 36 32 40
2 33 38 36
2 29 32 27
2 32 31 35
2 25 28 24
3 45 47 42
3 38 40 36
Et ce que je veux finir ressemblera à ceci:
ID Obs 1 mean Obs 1 std dev Obs 2 mean Obs 2 std dev
1 x x x x
2 x x x x
3 x x x x
Et ainsi de suite. Ce dont je ne suis pas sûr, c'est de savoir si j'ai besoin d'informations supplémentaires dans mes données détaillées ou quoi. J'imagine que la partie mathématique (trouver la moyenne et les écarts-types) sera la partie facile, mais je n'ai pas été en mesure de trouver un moyen qui semble fonctionner pour remodeler correctement les données pour commencer ce processus.
Merci beaucoup pour toute aide.
Il s'agit d'un problème d'agrégation, pas d'un problème de remodelage comme la question l'avait suggéré à l'origine - nous souhaitons agréger chaque colonne en une moyenne et un écart type par ID. Il existe de nombreux packages qui gèrent ces problèmes. Dans la base de R, cela peut être fait en utilisant aggregate
comme ceci (en supposant que DF
est la trame de données d'entrée):
ag <- aggregate(. ~ ID, DF, function(x) c(mean = mean(x), sd = sd(x)))
Note 1: Un intervenant a souligné que ag
est un bloc de données pour lequel certaines colonnes sont des matrices. Bien que cela puisse sembler étrange au départ, en fait, cela simplifie l'accès. ag
a le même nombre de colonnes que l'entrée DF
. Sa première colonne ag[[1]]
Est ID
et la ième colonne du reste ag[[i+1]]
(Ou de façon équivalente ag[-1][[i]]
) Est la matrice de statistiques de la ième colonne d'observation d'entrée . Si l'on souhaite accéder à la jième statistique de la ième observation c'est donc ag[[i+1]][, j]
Qui peut aussi s'écrire ag[-1][[i]][, j]
.
Par contre, supposons qu'il y ait k
colonnes statistiques pour chaque observation dans l'entrée (où k = 2 dans la question). Ensuite, si nous aplatissons la sortie, pour accéder à la jième statistique de la ième colonne d'observation, nous devons utiliser la ag[[k*(i-1)+j+1]]
ou l'équivalent ag[-1][[k*(i-1)+j]]
plus complexe.
Par exemple, comparez la simplicité de la première expression par rapport à la seconde:
ag[-1][[2]]
## mean sd
## [1,] 36.333 10.2144
## [2,] 32.250 4.1932
## [3,] 43.500 4.9497
ag_flat <- do.call("data.frame", ag) # flatten
ag_flat[-1][, 2 * (2-1) + 1:2]
## Obs_2.mean Obs_2.sd
## 1 36.333 10.2144
## 2 32.250 4.1932
## 3 43.500 4.9497
Note 2: L'entrée sous forme reproductible est:
Lines <- "ID Obs_1 Obs_2 Obs_3
1 43 48 37
1 27 29 22
1 36 32 40
2 33 38 36
2 29 32 27
2 32 31 35
2 25 28 24
3 45 47 42
3 38 40 36"
DF <- read.table(text = Lines, header = TRUE)
Voici probablement la façon la plus simple de s'y prendre (avec un exemple reproductible ):
library(plyr)
df <- data.frame(ID=rep(1:3, 3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9))
ddply(df, .(ID), summarize, Obs_1_mean=mean(Obs_1), Obs_1_std_dev=sd(Obs_1),
Obs_2_mean=mean(Obs_2), Obs_2_std_dev=sd(Obs_2))
ID Obs_1_mean Obs_1_std_dev Obs_2_mean Obs_2_std_dev
1 1 -0.13994642 0.8258445 -0.15186380 0.4251405
2 2 1.49982393 0.2282299 0.50816036 0.5812907
3 3 -0.09269806 0.6115075 -0.01943867 1.3348792
EDIT: L'approche suivante vous permet d'économiser beaucoup de frappe lorsque vous traitez plusieurs colonnes.
ddply(df, .(ID), colwise(mean))
ID Obs_1 Obs_2 Obs_3
1 1 -0.3748831 0.1787371 1.0749142
2 2 -1.0363973 0.0157575 -0.8826969
3 3 1.0721708 -1.1339571 -0.5983944
ddply(df, .(ID), colwise(sd))
ID Obs_1 Obs_2 Obs_3
1 1 0.8732498 0.4853133 0.5945867
2 2 0.2978193 1.0451626 0.5235572
3 3 0.4796820 0.7563216 1.4404602
Il existe plusieurs façons de procéder. reshape2
est un package utile. Personnellement, j'aime utiliser data.table
Ci-dessous, une étape par étape
Si myDF
est votre data.frame
:
library(data.table)
DT <- data.table(myDF)
DT
# this will get you your mean and SD's for each column
DT[, sapply(.SD, function(x) list(mean=mean(x), sd=sd(x)))]
# adding a `by` argument will give you the groupings
DT[, sapply(.SD, function(x) list(mean=mean(x), sd=sd(x))), by=ID]
# If you would like to round the values:
DT[, sapply(.SD, function(x) list(mean=round(mean(x), 3), sd=round(sd(x), 3))), by=ID]
# If we want to add names to the columns
wide <- setnames(DT[, sapply(.SD, function(x) list(mean=round(mean(x), 3), sd=round(sd(x), 3))), by=ID], c("ID", sapply(names(DT)[-1], paste0, c(".men", ".SD"))))
wide
ID Obs.1.men Obs.1.SD Obs.2.men Obs.2.SD Obs.3.men Obs.3.SD
1: 1 35.333 8.021 36.333 10.214 33.0 9.644
2: 2 29.750 3.594 32.250 4.193 30.5 5.916
3: 3 41.500 4.950 43.500 4.950 39.0 4.243
En outre, cela peut être utile ou non
> DT[, sapply(.SD, summary), .SDcols=names(DT)[-1]]
Obs.1 Obs.2 Obs.3
Min. 25.00 28.00 22.00
1st Qu. 29.00 31.00 27.00
Median 33.00 32.00 36.00
Mean 34.22 36.11 33.22
3rd Qu. 38.00 40.00 37.00
Max. 45.00 48.00 42.00
J'ajoute la solution dplyr
.
set.seed(1)
df <- data.frame(ID=rep(1:3, 3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9))
library(dplyr)
df %>% group_by(ID) %>% summarise_each(funs(mean, sd))
# ID Obs_1_mean Obs_2_mean Obs_3_mean Obs_1_sd Obs_2_sd Obs_3_sd
# (int) (dbl) (dbl) (dbl) (dbl) (dbl) (dbl)
# 1 1 0.4854187 -0.3238542 0.7410611 1.1108687 0.2885969 0.1067961
# 2 2 0.4171586 -0.2397030 0.2041125 0.2875411 1.8732682 0.3438338
# 3 3 -0.3601052 0.8195368 -0.4087233 0.8105370 0.3829833 1.4705692
Voici une autre version du data.table
réponses, en utilisant les données de @ Carson, c'est un peu plus lisible (et aussi un peu plus rapide, grâce à l'utilisation de lapply
au lieu de sapply
):
library(data.table)
set.seed(1)
dt = data.table(ID=c(1:3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9))
dt[, c(mean = lapply(.SD, mean), sd = lapply(.SD, sd)), by = ID]
# ID mean.Obs_1 mean.Obs_2 mean.Obs_3 sd.Obs_1 sd.Obs_2 sd.Obs_3
#1: 1 0.4854187 -0.3238542 0.7410611 1.1108687 0.2885969 0.1067961
#2: 2 0.4171586 -0.2397030 0.2041125 0.2875411 1.8732682 0.3438338
#3: 3 -0.3601052 0.8195368 -0.4087233 0.8105370 0.3829833 1.4705692