【问题标题】:Calculating count and proportion of a certain value for a number of variables subsetted by other variables计算由其他变量子集的多个变量的某个值的计数和比例
【发布时间】:2014-05-28 14:15:44
【问题描述】:

我有一个看起来像这样的data.table

DT <- data.table(Feature1 = c("yes", "yes", "yes", "no", "no"),
                 Feature2 = c("yes", "yes", "yes", "yes", "no"),
                 Feature3 = c("yes", "yes", "yes", "yes", "no"),
                 Var1 = c("yes", "yes", "no", "yes", "no"),
                 Var2 = c("yes", "yes", "yes", "yes", "yes"))


DT

##   Feature1 Feature2 Feature3 Var1 Var2
##1:       no       no       no   no  yes
##2:       no      yes      yes  yes  yes
##3:      yes      yes      yes  yes  yes
##4:      yes      yes      yes  yes  yes
##5:      yes      yes      yes   no  yes

现在我想计算所有可能的功能组合的“Var1”为“是”的发生率和比例,“Var2”在这些组合中为“是”等。我需要一个计数以及每个组合再次回答“是”的比例。

获取一个变量的计数很容易。因为我不想放弃任何组合,所以我使用CJ 而不是by

DT[,`:=`(Feature1 = as.factor(Feature1),
         Feature2 = as.factor(Feature2),
         Feature3 = as.factor(Feature3))]

(顺便说一句,有没有更好的方法一次将多个列设置为因子?)

setkeyv(DT, c("Feature1", "Feature2", "Feature3", "Var1"))
DT2 <- DT[CJ(levels(Feature1), levels(Feature2), levels(Feature3), "yes"),
          list(Var1.count = .N)]
DT2[, Var1 := NULL]

但是,使用CJ 意味着我必须为每个变量设置一个新键。如果我有 100 个呢?有没有比设置for-loop 更好的方法来做到这一点?另外,我如何从这里得到比例?例如,对于“是、是、是”特征的组合,Var1 两次是“是”,一次是“否”,所以我想在相应行中获得另一列名为 Var1.prop 的值为 0.66。

本质上,这就是我的目标:

   Feature1 Feature2 Feature3 Var1 Var1.count Var1.prop Var2.count Var2.prop
1:       no       no       no  yes          0        NA         1        1.00
2:       no       no      yes  yes          0        NA         0        NA
3:       no      yes       no  yes          0        NA         0        NA
4:       no      yes      yes  yes          1        1.00       1        1.00
5:      yes       no       no  yes          0        NA         0        NA
6:      yes       no      yes  yes          0        NA         0        NA
7:      yes      yes       no  yes          0        NA         0        NA
8:      yes      yes      yes  yes          2        0.66       3        1.00

解决方案应该针对大量不同的功能和变量进行扩展。我更喜欢使用data.table,因为它比普通的data.frame 操作要快得多,而且我发现与dplyr 相比,它更易于在函数中使用。话虽如此,我也会接受data.frame 的简洁且不太低效的解决方案。


@Arun 回答后更新。这真的很简洁,但它不能很好地扩展到,比如说,100 个变量。我一直在尝试以这种方式构建 Arun 的答案,但它只返回一个空的 data.table 以及一个警告:

vars <- c("Var1", "Var2")
tmps <- paste0(vars, ".tmp")

ans <- DTn[, { for (var in vars){
  assign(paste0(var, ".tmp"), sum(var == "yes", na.rm = TRUE));
  list(assign(paste0(var, ".count"), get(paste0(var, ".tmp"))),
       assign(paste0(var, ".prop"), get(paste0(var, ".tmp"))/.N)
  )
}}, by = key(DT), with = FALSE]

这里出了什么问题?

【问题讨论】:

    标签: r dataframe data.table


    【解决方案1】:

    您不必将列转换为factors。事实上,data.table 建议尽可能避免因素,因为它也会提高速度。但是,我将说明如何在未来更轻松地转换为 factor

    sd_cols = c("Feature1", "Feature2", "Feature3")
    DT[, c(sd_cols) := lapply(.SD, as.factor), .SDcols=sd_cols]
    

    好的,现在开始解决问题。当然,我们需要在这里使用CJ,因为您还需要获得缺席组合。所以,我们必须先生成它。

    uvals = c("no", "yes")
    setkey(DT, Feature1, Feature2, Feature3)
    DTn = DT[CJ(uvals, uvals, uvals), allow.cartesian=TRUE]
    

    allow.cartesian=TRUE 是必需的,因为在连接 x[i] 中,连接将导致比 max(nrow(x), nrow(i)) 更多的行。阅读this post了解更多关于allow.cartesian的信息。

    现在我们已经有了所有的组合,我们可以对它们进行分组/聚合,从而以您需要的方式获得结果。

    ans = DTn[, { tmp1 = sum(Var1 == "yes", na.rm=TRUE);
                 tmp2 = sum(Var2 == "yes", na.rm=TRUE);
               list(Var1.count = tmp1, 
                    Var1.prop  = tmp1/.N, 
                    Var2.count = tmp2,
                    Var2.prop  = tmp2/.N * 100)
               }, by=key(DT)]
    
    #    Feature1 Feature2 Feature3 Var1.count Var1.prop Var2.count Var2.prop
    # 1:       no       no       no          0 0.0000000          1         1
    # 2:       no       no      yes          0 0.0000000          0         0
    # 3:       no      yes       no          0 0.0000000          0         0
    # 4:       no      yes      yes          1 1.0000000          1         1
    # 5:      yes       no       no          0 0.0000000          0         0
    # 6:      yes       no      yes          0 0.0000000          0         0
    # 7:      yes      yes       no          0 0.0000000          0         0
    # 8:      yes      yes      yes          2 0.6666667          3         1
    

    我认为您可以尝试将值设为 NA 而不是 0,如果这真的那么重要吗?


    在得到DTn之后,在评论+编辑下关注OP的问题:

    vars = c("Var1", "Var2")
    ans = DTn[, c(N=.N, lapply(.SD, function(x) sum(x=="yes", na.rm=TRUE))), 
                   by=key(DTn), .SDcols=vars]
    N = ans$N
    ans[, N := NULL]
    ans[, c(paste(vars, "prop", sep=".")) := .SD/N, .SDcols=vars]
    setnames(ans, vars, paste(vars, "count", sep="."))
    
    ans
    #    Feature1 Feature2 Feature3 Var1.count Var2.count Var1.prop Var2.prop
    # 1:       no       no       no          0          1 0.0000000         1
    # 2:       no       no      yes          0          0 0.0000000         0
    # 3:       no      yes       no          0          0 0.0000000         0
    # 4:       no      yes      yes          1          1 1.0000000         1
    # 5:      yes       no       no          0          0 0.0000000         0
    # 6:      yes       no      yes          0          0 0.0000000         0
    # 7:      yes      yes       no          0          0 0.0000000         0
    # 8:      yes      yes      yes          2          3 0.6666667         1
    

    这个怎么样?

    【讨论】:

    • 谢谢,这很有帮助!但是,我想使用具有大量变量和功能的代码,因此我想尽可能避免输入冗余。理想情况下,我只会提供一个变量向量,然后一个循环就可以完成这项工作。我已经通过(失败的)尝试扩展您的代码更新了 OP,希望得到进一步的帮助。
    • 还有一个问题:为什么需要使用c() 将列转换为因子? sd_cols 已经是一个向量了,为什么还要再转换一次呢?我刚刚对某些列进行了log-transformation,但由于内存溢出,我的机器在没有c() 的情况下不断崩溃(没有任何错误消息,它只是完全崩溃了)。使用c(),它运行良好。为什么会这样?
    • @AnjaM,你可能不需要c,但你需要(),所以LHS被认为是一个表达式并被评估以获得存储在向量中的值。因为data.table 也允许DT[, col := value],其中col 只是一个列名。
    • 我真的不知道该怎么解释。 vars = c("a", "b", "c"); DT[, vars := "bla"]。在这里,我定义了一个变量vars,但是如果我不想想要创建列a,b,c,而是创建一个名为vars 的列。默认情况下,它不应该评估,这不是错误,因为这是完全有效的。如果您对此有强烈的感觉,请在邮件列表中开始讨论并参考这篇文章。
    • 好的,现在我明白你的意思了。当我输入DT[, sd_cols := lapply(.SD, log), .SDcols=sd_cols] 时,它会尝试创建一个名为sd_cols 的新列,但会得到一个长度=整个表的行数的几个向量的列表。然后它尝试为新列的每个条目分配一个列表元素(巨大的向量),但是整个事情变得太大并且系统崩溃。非常感谢您的解释和耐心!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    相关资源
    最近更新 更多