R 基于(部分)匹配的列名计算行平均值

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)

我从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)


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"