具有75万行和近200列的大型 ish 数据表,但这可以做到:
dt <- data.table(id = 1:15,
outcome = factor(c(0, 0, 0, 1, 1, 3, 3, 3, 3, 3, 0, 3, 1, 1, 3),
labels = c("F0","F1","F3")),
var1 = c(0, 0, 0, 1, 1, 2, 2, 2, NA, NA, 0, 0, 0, 0, 0),
var2 = c(0, 0, NA, NA, NA, 0, 0, 0, 0, 0, 6, 6, 4, 4, 4))
我想根据结果变量中的条件来更改/分组变量var1,var2(以及任何其他变量)的“标签”。一张桌子直观地说明了我要更改的内容
xtabs(~var1+outcome, dt, addNA = TRUE)
xtabs(~var2+outcome, dt, addNA = TRUE)
当没有结果== F1时,应将var1,var2和其他任何变量的标签分组。从第一张表:更改2;在第二个表中,组0和6。
如果级别和变量的数量很少,我可以用一个衬里手工做:
dt$var1[dt$var1==2] <- "nF" #data frame way
dt[, var1 := as.character(var1)][var1 == "2", var1 := "nF"] #data.table way
xtabs(~var1+outcome, dt, addNA = TRUE) #check
outcome
var1 F0 F1 F3
0 4 2 2
1 0 2 0
nF 0 0 3
<NA> 0 0 2
这两个一个内衬都可以工作,但是正如您可以想象的那样,如果有200列和一些具有上千个水平的变量,这是不可能的。
所以我想出了一个主意:
第1步
#rebuild dt to try this
(temp1 <- dcast(data = dt,
formula = var2 ~ outcome,
value.var = "outcome",
fun.aggregate = length))
第2步
tempvar <- temp1[F1==0 & var2!="NA", var2]
第3步
dt[, var2 := ifelse(var2 %in% tempvar, "nF", var2)]
xtabs(~var2+outcome, dt, addNA = TRUE) #check
outcome
var2 F0 F1 F3
4 0 2 1
nF 3 0 6
<NA> 1 2 0
这也有效,并且我避免必须遍历所有这些标签。所以我用一个很酷的计数器= p
# Initialize
tabs <- c()
temp <- c()
counter <- 0
for (i in colnames(dt[, c("var1", "var2")])) {
# counter & progress
counter <- counter + 1
cat("Variable: ", counter, "of", ncol(dt), " ", i, "\n")
# build tables for each variable with dcast
tabs[[i]] <- dcast(data = dt,
formula = dt[[i]] ~ outcome,
value.var = "outcome",
fun.aggregate = length)
# temp: labels to group & set name
temp[[i]] <- data.table(tabs[[i]][F1==0 & dt!="NA", dt],
"nF")
colnames(temp[[i]])[1] <- i
}
# Names of the 1st column for each tabs (for some reason, I couldn't do it inside the loop)
for(i in 1:length(tabs)) {colnames(tabs[[i]])[1] <- names(tabs[i])}
目前为止效果很好。现在让我们看一下临时选项卡:
#temp has the labels to be changed for each variable
temp
#tabs has the tables for each variable with respect to the outcome
tabs
就是这样。我被困住了,已经呆了2天了,几乎所有Stackoverflow链接都是紫色的。现在我不知道该怎么做了。
谢谢, 奥尔多
答案 0 :(得分:1)
如果我理解正确, 这就是您想要的:
library(data.table)
dt <- data.table(id = 1:15,
outcome = factor(c(0, 0, 0, 1, 1, 3, 3, 3, 3, 3, 0, 3, 1, 1, 3),
labels = c("F0","F1","F3")),
var1 = as.character(c(0, 0, 0, 1, 1, 2, 2, 2, NA, NA, 0, 0, 0, 0, 0)),
var2 = as.character(c(0, 0, NA, NA, NA, 0, 0, 0, 0, 0, 6, 6, 4, 4, 4)))
long <- melt(dt, "outcome", setdiff(names(dt), c("id", "outcome")))
to_group <- long[, .(dummy = .N), by = .(outcome, variable, value)
][, .(value = setdiff(value, c(NA, value[outcome == "F1"]))), by = "variable"]
for (var in unique(to_group$variable)) {
dt[list(to_group[variable == var, value]), (var) := "nF", on = var]
}
dt[]
id outcome var1 var2
1: 1 F0 0 nF
2: 2 F0 0 nF
3: 3 F0 0 <NA>
4: 4 F1 1 <NA>
5: 5 F1 1 <NA>
6: 6 F3 nF nF
7: 7 F3 nF nF
8: 8 F3 nF nF
9: 9 F3 <NA> nF
10: 10 F3 <NA> nF
11: 11 F0 0 nF
12: 12 F3 0 nF
13: 13 F1 0 4
14: 14 F1 0 4
15: 15 F3 0 4
使用melt
更改为长格式可以更轻松地为每个var*
列应用后续逻辑。
对于您的演示数据,
long
看起来像这样:
> head(long)
outcome variable value
1: F0 var1 0
2: F0 var1 0
3: F0 var1 0
4: F1 var1 1
5: F1 var1 1
6: F3 var1 2
因此,您可以将[, .(dummy = .N), by = .(outcome, variable, value)]
框架视为“不同的”操作。
它将创建类似于xtabs
的内容,但不将0添加到不存在的组合中。
下一帧仅获取每个var*
的所有值的集合,并删除与outcome == "F1"
同时出现的那些值,
以及NA
。
这就像为outcome
为F1
时永远不会出现的值计算0计数一样。
for循环中的代码使用secondary indices notation。
对于每个var*
列,
它搜索值与to_group$value
中存在的值匹配的行,
并将这些值替换为"nF"
。
我不确定这是否是最有效的,
但由于您说过您想修改原始的dt
(可能保留id
),
这就是我想出的。
您可能最后想rm(long)
。