我有按类别分组的公司数据集。有些公司有多个类别,可以跨多个列重复。我想知道如何根据类别(例如每个类别的平均值)对它们进行分析。这是一个示例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。我有一些粗略的方法,但在任务中没有任何内容:
我考虑过将fusion应用于data.frame,以便类别因子的每个实例都有自己的行(在这种情况下,维度为10x1,每行的每个类别得分对) 。
我还考虑过使用dplyr和按唯一名称分组,比如
mynames <- unique(c(levels(a), levels(b)))
但是,dplyr要求分组成为data.frame中的一个向量(除非有某种方法按照我不知道的模式或因子级别进行分组,这会很棒!)
感谢您的帮助!
答案 0 :(得分:2)
根据您获取所有类别的想法,我们可以为每个类别创建布尔列,并且它们仅取具有该类别的那些列的平均值。例如:
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)))
然后,对于我们检查的每个类别,对于每一行,该类别是否存在于a
或b
:
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
有更快的方法,但我对这个包还不是很好。
答案 1 :(得分:1)
使用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