/ / Comment grouper par colonne? - r, agrégation

Comment regrouper par colonne? - r, agrégation

J'ai une base de données des scores des étudiants, au lieu dePour obtenir un résultat moyen global pour chaque élève, je dois obtenir le résultat moyen par "type de cours" pour chaque élève. Par exemple, les cours a, c, d sont du même type et les cours b, e sont du même type. Je le fais par le code suivant, mais ce n'est pas assez "R":

x <- data.frame(a=c(1,2,3), b=c(4,5,6), c=c(6,7,8),
d=c(7,8,9), e=c(10, 11, 12))
group <- data.frame(no=c(1,2,1,1,2), name=c("a", "b", "c", "d","e"))

> x
a b c d  e
1 1 4 6 7 10
2 2 5 7 8 11
3 3 6 8 9 12

> group
no name
1  1    a
2  2    b
3  1    c
4  1    d
5  2    e

Je pense que c'est un peu stupide:

x.1 <- x[,as.character(group$name[group$no==1])]
x.2 <- x[,as.character(group$name[group$no==2])]
mean.by.no <- data.frame(x.1.mean=apply(x.1, 1, mean),
x.2.mean=apply(x.2, 1, mean))

Réponses:

3 pour la réponse № 1

Si mean.by.no est le résultat attendu, nous pourrions split la colonne "name" par "no" (ensemble de données "group") pour obtenir une liste. En utilisant l'un desapply fonctions familiales (lapply/sapply/vapply), nous pouvons utiliser la sortie comme index de colonne pour le "x" et obtenir la moyenne pour chaque ligne (rowMeans).

 vapply(with(group, split(as.character(name), no)),
function(y) rowMeans(x[y]), numeric(nrow(x)))
#            1 2
#[1,] 4.666667 7
#[2,] 5.666667 8
#[3,] 6.666667 9

Ou en utilisant tapply, on peut avoir le mean en utilisant l'index de regroupement pour la ligne et la colonne.

indx <- xtabs(no~name, group)[col(x)]
t(tapply(as.matrix(x), list(indx, row(x)), FUN=mean))
#         1 2
#1 4.666667 7
#2 5.666667 8
#3 6.666667 9

Ou une autre option serait de convertir le format "x" du format "large" au format "long" en utilisant melt de data.table après avoir converti "data.frame" en "data.table" (setDT). Définissez la colonne clé comme "nom" (setkey(..) et obtenez le mean regroupés par "no" et "rn" (colonne de numéro de ligne créée par keep.rownames=TRUE). Si nécessaire, la sortie peut être reconvertie au format "large" à l'aide de dcast.

library(data.table)#v1.9.5+
dL <- setkey(melt(setDT(x, keep.rownames=TRUE), id.var="rn",
variable.name="name")[, name:= as.character(name)],
name)[group[2:1]][,mean(value) , by=list( no, rn)]
dcast(dL, rn~paste0("mean",no), value.var="V1")[,rn:=NULL][]
#      mean1 mean2
#1: 4.666667     7
#2: 5.666667     8
#3: 6.666667     9

1 pour la réponse № 2

Il y a probablement une manière plus élégante de cela, mais:

library(reshape)
library(plyr)
x <- data.frame(a=c(1,2,3), b=c(4,5,6), c=c(6,7,8), d=c(7,8,9), e=c(10, 11, 12))
group <- data.frame(no=c(1,2,1,1,2), name=c("a", "b", "c", "d","e"))

a<-melt(x)
names(a)<-c("name", "score")
b<-merge(a, group, by="name")
c<-ddply(b, c("no"), summarize, meanscore=mean(score))
c

> c
no meanscore
1  1  5.666667
2  2  8.000000