【问题标题】:Applying function on iterative combinations of columns in data frame in R在R中数据框中的列的迭代组合上应用函数
【发布时间】:2018-04-04 19:18:10
【问题描述】:

我想构建一个特定的函数,它将整个数据框中不同列组合的行求和。

示例 - 我有一个数据框,其中第一个描述性列和 20 个列(v1、v2、v3、...)从 1 到 20,其中只有可能的值是 1 或 0。我想要一个函数,我可以根据特定出现对列中的值求和。如果将每个示例函数设置为 3,那么我需要将前 3 列(v1、v2 和 v3)汇总到第一个新创建的变量(v1s)中,然后将接下来的 3 列汇总在一起(v2、v3、 v4) 在下一个新创建的变量 (v2s) 等中。

可重现的例子:

set.seed(300) 
db <- matrix(sample(0:1,5*20, replace=TRUE),5,20)
us <- c("A","B","C","D","E")
db <- as.data.frame(cbind(us,db))

所以我想控制定义我想要总结多少列(通过控制我的意思是每个示例将其更改为 5 列应该不难)。在 3 列的情况下,我想创建 18 个附加变量(从第一个到最后一个 3 个变量的所有连续组合),其中包含 3 列的行总和。

我尝试了几个选项,但是我真的想不出简单的方法来做到这一点。我正在考虑一个函数,它将列数作为输入,然后对值进行行求和并遍历所有组合,但是我无法破解这个。请帮忙!

【问题讨论】:

  • cbind(us, db) 不幸地创建了一个矩阵,其中所有值都被强制转换为字符。 db &lt;- cbind(us, as.data.frame(db)) 保留整数值。

标签: r function dataframe multiple-columns apply


【解决方案1】:

可能有更简单的方法。无论如何,这是我的方法:

代码:

grp_colsum <- function(df, n) {
  # generate the set of indices 123, 234, 345, ...
  idx <- sapply(1:n, `+`, 0:(ncol(df)-n))
  # for each set of indices
  res <- apply(idx, 1, function(x) {
    rowSums(df[,x])
  })
  colnames(res) <- paste0("v", 1:ncol(res), "s")
  res
}
grp_colsum(db[,-1], 3)

输出:

    v1s v2s v3s v4s v5s v6s v7s v8s v9s v10s v11s v12s v13s v14s v15s v16s v17s v18s
[1,]   2   2   3   2   2   1   1   1   1    2    1    2    2    2    2    1    2    1
[2,]   2   2   1   2   2   2   1   1   2    2    2    1    2    1    1    1    1    2
[3,]   2   2   2   2   2   3   3   2   2    2    3    3    2    2    1    2    2    2
[4,]   2   2   2   2   1   2   2   2   2    2    2    2    1    1    1    2    3    3
[5,]   3   3   2   1   0   1   1   2   2    2    1    1    2    3    2    1    1    1

【讨论】:

    【解决方案2】:

    如果我正确理解了这个问题,则可以通过将数据从宽格式重新整形为长格式,对每个组 id us 的滚动窗口求和并重新整形为宽格式来获得结果:

    library(data.table)
    # define number of columns to sum over
    width <- 3L
    # reshape from wide to long format
    melt(setDT(db), id = "us")[
      # make sure that column values can be added
      , value := as.integer(value)][
        # sum across a rolling window for each group
        , Reduce("+", shift(value, n = 0:(width - 1L), type = "lead")), by = us][
          # remove rows from incomplete window sizes
          !is.na(V1)][
            # reshape to wide format again
            , dcast(.SD, us ~ sprintf("S%02i", rowid(us)))]
    

    返回

       us S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S17 S18
    1:  A   2   2   3   2   2   1   1   1   1   2   1   2   2   2   2   1   2   1
    2:  B   2   2   1   2   2   2   1   1   2   2   2   1   2   1   1   1   1   2
    3:  C   2   2   2   2   2   3   3   2   2   2   3   3   2   2   1   2   2   2
    4:  D   2   2   2   2   1   2   2   2   2   2   2   2   1   1   1   2   3   3
    5:  E   3   3   2   1   0   1   1   2   2   2   1   1   2   3   2   1   1   1
    

    对于n &lt;- 5L,我们得到

       us S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16
    1:  A   4   3   4   3   2   2   2   2   2   3   3   3   3   3   3   2
    2:  B   3   3   3   3   2   3   3   2   3   3   3   2   2   2   2   2
    3:  C   3   3   4   4   4   4   4   4   4   4   4   4   3   3   3   3
    4:  D   3   3   3   3   3   3   3   4   3   3   3   2   2   3   3   4
    5:  E   4   3   2   2   1   2   3   3   2   3   3   3   3   3   3   2
    

    作为先决条件,db 不得包含任何 NA 值。

    【讨论】:

    • 解决方案非常有趣,但是我没有提到我的原始数据集非常大,所以我更喜欢不会将我的数据集重塑为长格式的方法。谢谢。
    • @gaspers 您的生产数据集有多少行和多少列?
    • 算法会动态运行,所以我不能肯定。大约 700 万行和 90 列。
    猜你喜欢
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 2018-03-16
    相关资源
    最近更新 更多