我有一个学生分数的数据框,而不是每个学生的总体平均分数,我需要为每个学生获得“课程类型”的平均分数,例如,课程a,c,d是相同的类型,和课程b,e是相同的类型。我通过以下代码执行此操作,但它不够“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
我认为这有些愚蠢:
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))
答案 0 :(得分:3)
如果mean.by.no
是预期结果,我们可以split
使用“{1}}名称&#39;专栏&#39; no&#39; (&#39; group&#39;数据集)获取列表。使用apply
系列函数之一(lapply/sapply/vapply
),我们可以将输出用作&#39; x&#39;的列索引,并获取每行的均值(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
或者使用tapply
,我们可以使用行和列的分组索引获取mean
。
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
或另一种选择是转换&#39; x&#39;来自&#39; wide&#39;长期&#39;转换&#39; data.frame&#39;后,使用melt
中的data.table
格式化到&#39; data.table&#39; (setDT
)。将键列设置为&#39; name&#39; (setkey(..
),并将mean
分组为&#39; no&#39;和&#39;&#39; (由keep.rownames=TRUE
创建的行号列)。如果需要,可以将输出转换回“广泛”状态。格式使用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 :(得分:1)
这可能是一种更优雅的方式,但是:
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