【问题标题】:Create a data frame with unique combo generated from nested for loops创建具有从嵌套 for 循环生成的唯一组合的数据框
【发布时间】:2025-12-26 02:50:07
【问题描述】:

我有一个这样的数据框:

  Feature ID Sub Value
1       A T1  B1  5.87
2       B T1  B2  3.99
3       C T1  B3 12.57
4       A T1  B2  9.22
5       B T1  B3  7.89
6       C T1  B1  4.76
7       A T2  B1  4.56
8       B T2  B2  9.26
9       C T2  B2  7.44

我想要做的是在这个数据集中运行一个因子方差分析,因子是“子”。我想遍历每个功能并遍历每个 ID。基本上,我正在计算“Sub”之间的 ID 内每个特征的方差。

我已经生成了下面的代码,但它似乎没有工作。

datalist <- list()

for (i in unique(data1$Feature)) {
  for (j in unique(data1$ID)) {
    A1 <- summary(aov(data1$value ~ as.factor(data1$Sub), data=data1))
    datalist[[j]] <- A1
  }
}

big_data <- do.call(rbind, datalist)

我最终得到了 big_data,它是一个由 36 个列表组成的矩阵。我无法访问 Anova 输出。它不一定是数据框。即使它是循环中的“write.csv()”,也会产生不同的输出。最终,我只需要 Anova 输出的“between”因子参数来生成绘图,因此如果这也可以合并到代码中,那将有很大帮助。

【问题讨论】:

    标签: r dataframe loops nested anova


    【解决方案1】:

    当前设置的几个问题:

    • 您实际上并未在 anova 调用中使用 ij,因此所有嵌套的 for 循环迭代将返回在整个数据帧上运行的完全相同的结果。快速修复:subset 数据帧由第 i 个和第 j 个值组成。

      anova(value ~ Sub, data = subset(data1, Feature == i & ID == j))
      
    • 您仅将列表元素保存在j 值下,而不是同时保存ij,因此迭代将重复重新分配并且仅保存j 项的最后遍。快速修复:添加第 i 个和第 j 个值的命名元素。

      datalist[[paste0(i, "_", j)]] <- A1
      
    • 您正在尝试rbind 列出对象,而不是矩阵或数据框,因为summary.anova 返回结果列表。对于您的用例,调用 str 会显示您的结果包含 1 的列表:

      str(summary(aov(data1$value ~ as.factor(data1$Sub), data = data1)))
      List of 1
      $ :Classes ‘anova’ and 'data.frame': 2 obs. of  5 variables:
        ..$ Df     : num [1:2] ...
        ..$ Sum Sq : num [1:2] ...
        ..$ Mean Sq: num [1:2] ...
        ..$ F value: num [1:2] ...
        ..$ Pr(>F) : num [1:2] ...
      - attr(*, "class")= chr [1:2] "summary.aov" "listof"
      

      快速修复:索引第一项。

      summary(anova(...))[[1]]
      

    但是,考虑使用bytapply 的面向对象的包装器)的 apply 系列解决方案,并避免在嵌套的for 循环中进行初始化列表和迭代分配的簿记。具体来说,by 可以将数据帧按一个或多个组拆分,并对子集运行操作以返回等于所有可能的组唯一值的列表。另外,考虑使用定义的方法来封装每个子集上的所有处理。

    # USER-DEFINED METHOD
    run_anova <- function(sub_df) {
      # RAW RESULTS
      anova_raw <- summary(aov(value ~ Sub, data = sub_df))[[1]]
    
      # CLEAN UP DATA WITH IDENTIFIERS
      anova_df <- data.frame(
        within(anova_raw, {Feature <- sub_df$Feature[1]; ID <- sub_df$ID[1]}),
        row.names = NULL,
        check.names = FALSE
      )
      
      return(anova_df)
    }
    
    datalist <- by(data1, data1[c("Feature", "ID")], run_anova)
      
    big_data <- do.call(rbind, unname(datalist))
    

    【讨论】: