【问题标题】:Analyzing repeated categories from multiple columns in R分析 R 中多列的重复类别
【发布时间】:2015-09-04 09:53:11
【问题描述】:

我有一个按类别分组的公司数据集。一些公司有多个类别,可以在多个列中重复。我想知道如何根据类别(例如每个类别的平均值)来分析它们。这是一个示例 data.frame

a <- factor(c("cat1", "cat2", "cat3", "cat4", "cat2"))
b <- factor(c("cat5", "cat4", "cat2", "cat1", "NA"))
comp <- factor(c("company1", "company2", "company3", "company4","company5"))
score <- c(1, -1, 2, -2, 1.5) 
df <- data.frame(a, b, comp, score)

#     a    b     comp score
#1 cat1 cat5 company1   1.0
#2 cat2 cat4 company2  -1.0
#3 cat3 cat2 company3   2.0
#4 cat4 cat1 company4  -2.0
#5 cat2   NA company5   1.5

我想知道的一项任务是每个类别的平均值。通过查看这个简单的数据集,我知道 cat1 的平均值为 -0.5。我有一些粗略的方法,但在任务中没有任何后续:

  1. 我考虑过将 melt 应用于 data.frame,以便类别因子的每个实例都有自己的行(在这种情况下,维度将为 10x1,每行的每个类别分数对) .

  2. 我还考虑过使用 dplyr 并按唯一名称进行分组,例如

    mynames <- unique(c(levels(a), levels(b)))
    

但是,dplyr 需要将分组作为 data.frame 中的一个向量(除非有某种方法可以按我不知道的模式或因子级别进行分组,这会很棒!)

  1. 最后,我可能不需要制作单独的数据框。也许有一种方法可以使用 apply 将函数(例如均值)应用于唯一的类别级别。

感谢您的帮助!

【问题讨论】:

  • 您是否担心在实际数据集上融合为长格式会花费太长时间?看起来这个任务在长格式数据集上真的很容易......

标签: r


【解决方案1】:

按照您获取所有类别的想法,我们可以为每个类别创建布尔列,它们仅取具有该类别的那些的平均值。例如:

a <- factor(c("cat1", "cat2", "cat3", "cat4", "cat2"))
b <- factor(c("cat5", "cat4", "cat2", "cat1", NA)) #NA, not "NA" or it will be a new level
score <- c(1, -1, 2, -2, 1.5) 
df <- data.frame(a, b, score)

我们创建一个包含所有类别的向量:

cats <- unique(c(levels(df$a), levels(df$b)))

然后,对于我们检查的每个类别,对于每一行,该类别是否存在于ab 中:

catcols <- sapply(cats, function(i) {
  sapply(1:nrow(df), function(j) {
    return(i %in% df$a[j] | i %in% df$b[j])
  })
})

这会返回一个矩阵,我们可以将其添加到我们的数据框中:

> catcols
      cat1  cat2  cat3  cat4  cat5
[1,]  TRUE FALSE FALSE FALSE  TRUE
[2,] FALSE  TRUE FALSE  TRUE FALSE
[3,] FALSE  TRUE  TRUE FALSE FALSE
[4,]  TRUE FALSE FALSE  TRUE FALSE
[5,] FALSE  TRUE FALSE FALSE FALSE

> df2 <- cbind(df, catcols)

现在我们只需要为每个类别取平均值,只对类别为 TRUE 的行进行子集化:

means <- sapply(cats, function(i) {
  mean(df2[df2[,i],"score"])
})

means

#       cat1       cat2       cat3       cat4       cat5 
# -0.5000000  0.8333333  2.0000000 -1.5000000  1.0000000 

编辑

我想不出更好的替代方案,但能够稍微改进代码。使用您提到的大小的随机数据:

ncats <- 500
allcats <- paste0("cat", 1:ncats)
nrow <- 50000
ncol <- 26
set.seed(1)
bigdf <- data.frame(replicate(ncol, sample(allcats, nrow, replace = TRUE)), score=rnorm(nrow))

代码:

scorecol <- which(names(bigdf) == "score")

catcols <- data.frame(sapply(allcats, function(i) {
  apply(bigdf[,-scorecol], 1, function(j) i %in% j)
}))

means <- sapply(allcats, function(i) {
  mean(bigdf[catcols[,i],"score"])
})

这对我来说花费了 195 秒,大约是之前方法的 30%(使用较小数据进行微基准测试)。结果是:

> head(means)
        cat1         cat2         cat3         cat4         cat5         cat6 
0.0019851051 0.0006465704 0.0066345735 0.0126089999 0.0135545455 0.0253983216 

我尝试寻找dplyr 替代方案,但找不到任何有用的东西。我确信使用data.table 有一种更快的方法,但我对这个包还不是很好。

【讨论】:

  • 好棒!我可能应该更清楚地说明这是针对更大的数据集(50K 行)。我试用了你的函数 catcols,它一直在运行——这仅适用于 2 个类别。我在整个数据集中有大约 26 列和 500 个级别。所以,你肯定解决了示例 df,但我在应用它时遇到了问题 :) 我如何将它应用到更大的数据集?
  • @tom 嵌套循环显然不是处理大数据的好方法。我看看能不能想出更好的办法。
  • @tom 我添加了一个替代方案,但也好不到哪里去。
【解决方案2】:

使用 melt 和 ddply 函数:

df_melt <- melt(df, id.vars = c("comp", "score"), measure.vars = c("a", "b"))
ddply( .data = df_melt, .variables = .(value), summarise, mean = round(mean(score), digits = 2) )

通过这种方式,还可以轻松计算其他汇总统计信息。

对于根据 Molx 的更大数据集:

# adding a hypothetical company column so that we do not deviate from the smaller dataset case above:
bigdf$comp <- paste("company", 1:50000, sep = "")

measure_vars <- names(bigdf)[-c(dim(bigdf)[2]-1, dim(bigdf)[2])]
bigdf_melt <- melt(bigdf, id.vars = c("comp", "score"), measure.vars = measure_vars)
# transform value column to an ordered factor so that ddply returns result in an ordered category fashion
bigdf_melt$value <- factor(bigdf_melt$value, levels = paste0("cat", 1:ncats), ordered = TRUE)

bigdf_mean <- ddply( .data = bigdf_melt, .variables = .(value), summarise, mean = round(mean(score), digits = 4) )
bigdf_mean

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    相关资源
    最近更新 更多