分析R中多个列的重复类别

时间:2015-06-18 16:22:50

标签: r

我有按类别分组的公司数据集。有些公司有多个类别,可以跨多个列重复。我想知道如何根据类别(例如每个类别的平均值)对它们进行分析。这是一个示例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. 我考虑过将fusion应用于data.frame,以便类别因子的每个实例都有自己的行(在这种情况下,维度为10x1,每行的每个类别得分对) 。

  2. 我还考虑过使用dplyr和按唯一名称分组,比如

    mynames <- unique(c(levels(a), levels(b)))
    
  3. 但是,dplyr要求分组成为data.frame中的一个向量(除非有某种方法按照我不知道的模式或因子级别进行分组,这会很棒!)

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

2 个答案:

答案 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)))

然后,对于我们检查的每个类别,对于每一行,该类别是否存在于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有更快的方法,但我对这个包还不是很好。

答案 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