在 R 中使用 dplyr 和 reshape2 为列范围内的每个因子水平生成表

Generating tables for each factor level over a range of columns, in R with dplyr and reshape2

对于数据框中的一系列列(变量),我需要为每个变量的每个级别生成 tables。我创建了一个函数,用于查找范围 (Q1a) 中的第一列,然后为之后的每一列运行一个 for 循环。该循环查找每一列中的级别数,然后第二个 for 循环应该生成 table 并将其保存为具有唯一文件名的 .csv。

示例数据框:

df <- data.frame(Organization = c("A", "B", "C", "D"), Gender = c("Male", "Female", "Male", "Female"), Q1a = c(1, 2, 3, 4), Q1b = c(1, 2, 1, 2))

df Returns:

  Organization Gender Q1a Q1b
1            A   Male   1   1
2            B Female   2   2
3            C   Male   3   1
4            D Female   4   2

这是我写的函数:

library(dplyr)
library(reshape2)
f = function(df) {
  a <- which(colnames(df) == "Q1a")
  for(i in colnames(df[, a:length(df)])) {
      levelsList <- as.list(levels(i))
      for(j in levelsList) {
          temp <- subset(df, i == j, select = c(Organization, Gender, i))
          temp <- group_by(temp, Organization, Gender)
          table <- summarize(temp, count = n())
          table <- dcast(table, Organization ~ Gender)
          table <- mutate(table, Total = Female + Male)
          write.csv(table, paste0(i, "_", j, ".csv"))
      }
   }
}

较大数据集的预期输出如下所示:

    Organization    Female  Male    Total
1          A          366    259      625
2          B          30     35       65
3          C          83     61       144
4          D          55     58       113

我可以用几行代码正确地生成一个像上面那样的 table。问题是该函数不生成任何文件。我在正确的轨道上吗?有没有更简单的方法使用应用来做到这一点?

我修改的几个问题。查看循环中 i 的值。它是来自 df 的列名的字符串值。当传递给 levels() 时,您将永远得到 NULL。如果您真的想使用 levels(),您需要将这些列转换为因子,或者替换为 unique()

请参阅 ?subset 下的警告部分以了解如何使用此函数,我已将代码更改为使用 [ 对数据框进行子集化。

此外,我假设您打算将 table 输出到 CSV,而不是您的示例中不存在的 org.sum

library(dplyr)
library(reshape2)

df <- data.frame(Organization = c("A", "A", "B", "C", "D"), Gender = c("Male", "Female", "Female", "Male", "Female"), Q1a = as.factor(c(1, 1, 2, 3, 4)), Q1b = as.factor(c(1, 1, 2, 1, 2)))
f = function(df) {
  a <- which(colnames(df) == "Q1a")
  for(i in colnames(df[, a:length(df)])) {
    levelsList <- levels(df[,i])
    for(j in levelsList) {
      temp <- df[df[,i] == j, c('Organization', 'Gender', i)] 
      temp <- group_by(temp, Organization, Gender)
      table <- summarize(temp, count = n())
      table <- dcast(table, Organization ~ Gender, value.var='count')
      if (dim(table)[2] > 2) {table$Total <- rowSums(table[,c('Male', 'Female')])}
      else {table$Total <- table[,2]}
      write.csv(table, paste0(i, "_", j, ".csv"), row.names = F)
    }
  }
}

f(df)