【问题标题】:Calculate row means based on (partial) matching column names根据(部分)匹配的列名计算行均值
【发布时间】:2012-09-12 22:57:39
【问题描述】:

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

这就是我的数据框最终的样子:

  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
1 2001     1     2     1     1     1     2     1     1     1     2     1     1
2 2002     2     4     3     2     2     4     3     2     2     4     3     2
3 2003     3     6     5     3     3     6     5     3     3     6     5     3
4 2004     4     8     7     4     4     8     7     4     4     8     7     4

我的目标是计算每个数据表中每个匹配列的行均值。所以在这种情况下,我希望所有以 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

所以我的问题是,如何根据列名中的部分匹配来计算行均值?

谢谢

【问题讨论】:

  • 我们可以假设我们不能依赖列的位置顺序吗?即“匹配”列可能是不规则间隔的?
  • 不,我们不能依赖位置排序。而且我正在使用的实际数据集有更多列,因此指定列定位会很麻烦

标签: r


【解决方案1】:
colnames = c("V1", "V2", "V3", "V4")
res <- 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

R grep 函数返回一个整数向量,用于从较大的数据帧中选择性地“拉”包含单个“V”列名称的列。

如果您需要自动生成名称:

> unique(sapply(strsplit(names(DF)[-1], ".", fixed=TRUE), "[", 2) )
[1] "V1" "V2" "V3" "V4"

【讨论】:

  • res 未分配任何值
  • 好收获。我想我是在没有分配的情况下运行它,直到我得到正确的预期结果,但后来忘记了分配。现在修复。
【解决方案2】:
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

【讨论】:

    【解决方案3】:

    您可以使用grepvalue = T 来获取适当的名称,然后在jj 组件中创建对eval 的调用

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

    【讨论】:

    • 这种折磨似乎是由@Vinterwoo 将两种分类类型合并为一个列名向量引起的。在data.table 中,我们将其保留为长格式,然后简单地执行:DT[,mean(var),by="A,V"]。其中一些问题我很想回答“为什么?” DWin 的方法,但在带有 with=FALSE 的 data.table 上可能更简单。
    【解决方案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 对与子字符串部分匹配的所有列进行计算。

    使用do.callcbind(如DWin 建议的那样),我们连接各个列。 最后,我们从原始数据框的Date 列设置列名。

    可以更优雅、更高效地解决问题,请参阅 DWin 和 Maiasaura 的解决方案。

    【讨论】:

    • 这是一条相当曲折的完成之路,尤其是 for 循环,可以只替换为:do.call(cbind, means)
    • 合理建议,相应更新帖子。我已经有一段时间很少使用 R 了,但我仍然很难做到 :)。顺便说一句,喜欢你和@Maiasaura 的解决方案。
    猜你喜欢
    • 2017-03-07
    • 1970-01-01
    • 2017-12-23
    • 2021-11-09
    • 2021-03-26
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多