我的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
现在我想计算&#34; Var1&#34;的出现次数和比例。正在&#34;是&#34;对于所有可能的功能组合,&#34; Var2&#34;正在&#34;是&#34;通过这些组合等我需要计算以及每个组合再次使用&#34; yes&#34; -answers的比例。
计算一个变量很容易。由于我不想删除任何组合,因此我使用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
- 循环?另外,我如何从这里获得比例?例如,对于特征的组合&#34;是,是,是&#34;,Var1是&#34;是&#34;两次&#34;没有&#34;曾经,所以我想在相应的行中获得另一个名为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]
这里出了什么问题?
答案 0 :(得分:3)
您不必将列转换为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
是必要的,因为联接会在联接max(nrow(x), nrow(i))
中产生比x[i]
更多的行。有关allow.cartesian
的更多信息,请阅读this post。
现在我们已经完成了所有组合,我们可以分组/聚合它们,以便以您需要的方式获得结果。
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
这个怎么样?