R 基于(部分)匹配的列名计算行平均值
我从3个名为A1、A2、A3的大型数据表开始。每个表有4个数据列V1-V4,1个数据列(在所有三个表中都是常量)和数千行 下面是一些近似于我的表的虚拟数据R 基于(部分)匹配的列名计算行平均值,r,R,我从3个名为A1、A2、A3的大型数据表开始。每个表有4个数据列V1-V4,1个数据列(在所有三个表中都是常量)和数千行 下面是一些近似于我的表的虚拟数据 A1.V1<-c(1,2,3,4) A1.V2<-c(2,4,6,8) A1.V3<-c(1,3,5,7) A1.V4<-c(1,2,3,4) A2.V1<-c(1,2,3,4) A2.V2<-c(2,4,6,8) A2.V3<-c(1,3,5,7) A2.V4<-c(1,2,3,4)
A1.V1<-c(1,2,3,4)
A1.V2<-c(2,4,6,8)
A1.V3<-c(1,3,5,7)
A1.V4<-c(1,2,3,4)
A2.V1<-c(1,2,3,4)
A2.V2<-c(2,4,6,8)
A2.V3<-c(1,3,5,7)
A2.V4<-c(1,2,3,4)
A3.V1<-c(1,2,3,4)
A3.V2<-c(2,4,6,8)
A3.V3<-c(1,3,5,7)
A3.V4<-c(1,2,3,4)
Date<-c(2001,2002,2003,2004)
DF<-data.frame(Date, A1.V1,A1.V2,A1.V3,A1.V4,A2.V1,A2.V2,A2.V3,A2.V4,A3.V1,A3.V2,A3.V3,A3.V4)
我的目标是计算每个数据表中每个匹配列的行平均值。所以在本例中,我希望所有以V1结尾的列、所有以V2结尾的列、所有以V3结尾的列和所有以V4结尾的列的行表示
最终的结果是这样的
V1 V2 V3 V4
2001 1 2 1 1
2002 2 4 3 2
2003 3 6 5 3
2004 4 8 7 4
所以我的问题是,如何根据列名中的部分匹配来计算行平均值
谢谢我相信它可以做得更优雅,但这是一种似乎可行的可能性
# declare the column names
colnames = c("V1", "V2", "V3", "V4")
# calculate the means
means = lapply(colnames, function(name) { apply(DF[,grep(name, names(DF))], 1, mean) })
# build the result
result = do.call(cbind, means)
result = as.data.frame(t(result))
rownames(result) = DF$Date
我也应该描述一下,我做了什么
首先,我声明列名部分匹配
然后,使用grep命令部分选择数据帧中与特定子字符串匹配的列。apply命令计算平均值,lapply对子字符串部分匹配的所有列进行计算
使用DWin建议的do.call和cbind,我们连接各个列。
最后,我们根据原始数据帧的日期列设置列名
这个问题可以更方便、更有效地解决,请参见Drwin和Maiasaura的解决方案。您可以使用grep with value=T来获取适当的名称,然后在data.table的j组件中创建对eval的调用
library(plyr)
ddply(DF, .(Date), function(x) {
foo <- melt(x, id.vars = 1)
foo$variable <- substr(foo$variable, 4, 6)
return(dcast(foo, Date ~ variable, mean))
})
Date V1 V2 V3 V4
1 2001 1 2 1 1
2 2002 2 4 3 2
3 2003 3 6 5 3
4 2004 4 8 7 4
我们能不能假设我们不能依赖于列的位置顺序?i、 e.匹配列的间距可能不规则?不,我们不能依赖位置顺序。而我正在使用的实际数据集有更多的列,因此指定列位置将是一个难题,这是一个相当曲折的完成过程,尤其是for循环,它可以替换为:do.callcbind,意思是合理的建议,相应地更新了帖子。我已经有一段时间很少使用R了,但我仍然用艰难的方式做事。顺便说一句,我喜欢你和@Maiasaura的解决方案。这种折磨似乎是由@Vinterwoo将两种分类类型合并成一个列名称向量引起的。在data.table中,我们将以长格式保存它,然后简单地执行:DT[,meanvar,by=A,V]。有些问题我很想回答为什么?DWin的方法,但在data.table上with=FALSE可能更简单。
library(plyr)
ddply(DF, .(Date), function(x) {
foo <- melt(x, id.vars = 1)
foo$variable <- substr(foo$variable, 4, 6)
return(dcast(foo, Date ~ variable, mean))
})
Date V1 V2 V3 V4
1 2001 1 2 1 1
2 2002 2 4 3 2
3 2003 3 6 5 3
4 2004 4 8 7 4
library(data.table)
# convert to a data.table
DT <- data.table(DF)
# the indices we wish to group
.index <- paste0('V',1:3)
# a list containing the names
name_list <- mapply(grep, pattern = as.list(.index ),
MoreArgs = list(x= names(DT),value=T ), SIMPLIFY=F)
# create the expression
.e <- parse(text=sprintf('list( %s)', paste(mapply(sprintf, .index, lapply(name_list, paste, collapse = ', '),
MoreArgs = list(fmt = '%s = mean(c(%s), na.rm = T)')), collapse = ',')))
DT[, eval(.e),by=Date]
## Date V1 V2 V3
## 1: 2001 1 2 1
## 2: 2002 2 4 3
## 3: 2003 3 6 5
## 4: 2004 4 8 7
# what .e looks like
.e
## expression(list( V1 = mean(c(A1.V1, A2.V1, A3.V1), na.rm = T),V2 = mean(c(A1.V2, A2.V2, A3.V2), na.rm = T),V3 = mean(c(A1.V3, A2.V3, A3.V3), na.rm = T)))
colnames = c("V1", "V2", "V3", "V4")
sapply(colnames, function(x) rowMeans(DF [, grep(x, names(DF))] ) )
rownames(res) <- DF$Date
res
V1 V2 V3 V4
2001 1 2 1 1
2002 2 4 3 2
2003 3 6 5 3
2004 4 8 7 4
> unique(sapply(strsplit(names(DF)[-1], ".", fixed=TRUE), "[", 2) )
[1] "V1" "V2" "V3" "V4"