data.table 中的分组因子水平
Grouping factor levels in a data.table
我正在尝试在 data.table
中组合因子水平并想知道是否有 data.table
-y 方法可以做到这一点。
示例:
DT = data.table(id = 1:20, ind = as.factor(sample(8, 20, replace = TRUE)))
我想说类型1,3,8在A组; 2和4在B组; 5,6,7在C组
这是我一直在做的,在完整版的问题中速度相当慢:
DT[ind %in% c(1, 3, 8), grp := as.factor("A")]
DT[ind %in% c(2, 4), grp := as.factor("B")]
DT[ind %in% c(5, 6, 7), grp := as.factor("C")]
this 相关问题建议的另一种方法,我猜会这样翻译:
DT[ , grp := ind]
levels(DT$grp) = c("A", "B", "A", "B", "C", "C", "C", "A")
或者(鉴于我有 65 个基础组和 18 个聚合组,这感觉更整洁)
DT[ , grp := ind]
lev <- letters(1:8)
lev[c(1, 3, 8)] <- "A"
lev[c(2, 4)] <- "B"
lev[5:7] <- "C"
levels(DT$grp) <- lev
这两个看起来都很笨重;在 data.table
中,这看起来是合适的方法吗?
作为参考,我用 10,000,000 个观察值和更多 subgroup/supergroup 级别对这个增强版本进行了计时。我最初的方法是最慢的(必须 运行 所有这些逻辑检查的成本很高),第二快,第三快。但我更喜欢这种方法的可读性。
(在搜索之前键入 DT
可以加快速度,但与后两种方法相比,它只减少了一半的差距)
更新:
我最近从 问题中了解到一种更简单的方法来重新关联因子水平,并仔细阅读了 ?levels
。无需合并、通信 table 等,只需将命名的 list
传递给 levels
:
levels(DT$ind) = list(A = c(1, 3, 8), B = c(2, 4), C = 5:7)
原答案:
根据@Arun 的建议,我们可以选择将对应关系创建为单独的 data.table
,然后将其与原始对应关系连接起来:
match_dt = data.table(ind = as.factor(1:12),
grp = as.factor(c("A", "B", "A", "B", "C", "C",
"C", "A", "D", "E", "F", "D")))
setkey(DT, ind)
setkey(match_dt, ind)
DT = match_dt[DT]
我们也可以用(我认为的)更易读的方式来做到这一点(边际速度成本):
levels <- letters[1:12]
levels[c(1, 3, 8)] <- "A"
levels[c(2, 4)] <- "B"
levels[5:7] <- "C"
levels[c(9, 12)] <- "D"
levels[10] <- "E"
levels[11] <- "F"
match_dt <- data.table(ind = as.factor(1:12),
grp = as.factor(levels))
setkey(DT, ind)
setkey(match_dt, ind)
DT = match_dt[DT]
我正在尝试在 data.table
中组合因子水平并想知道是否有 data.table
-y 方法可以做到这一点。
示例:
DT = data.table(id = 1:20, ind = as.factor(sample(8, 20, replace = TRUE)))
我想说类型1,3,8在A组; 2和4在B组; 5,6,7在C组
这是我一直在做的,在完整版的问题中速度相当慢:
DT[ind %in% c(1, 3, 8), grp := as.factor("A")]
DT[ind %in% c(2, 4), grp := as.factor("B")]
DT[ind %in% c(5, 6, 7), grp := as.factor("C")]
this 相关问题建议的另一种方法,我猜会这样翻译:
DT[ , grp := ind]
levels(DT$grp) = c("A", "B", "A", "B", "C", "C", "C", "A")
或者(鉴于我有 65 个基础组和 18 个聚合组,这感觉更整洁)
DT[ , grp := ind]
lev <- letters(1:8)
lev[c(1, 3, 8)] <- "A"
lev[c(2, 4)] <- "B"
lev[5:7] <- "C"
levels(DT$grp) <- lev
这两个看起来都很笨重;在 data.table
中,这看起来是合适的方法吗?
作为参考,我用 10,000,000 个观察值和更多 subgroup/supergroup 级别对这个增强版本进行了计时。我最初的方法是最慢的(必须 运行 所有这些逻辑检查的成本很高),第二快,第三快。但我更喜欢这种方法的可读性。
(在搜索之前键入 DT
可以加快速度,但与后两种方法相比,它只减少了一半的差距)
更新:
我最近从 ?levels
。无需合并、通信 table 等,只需将命名的 list
传递给 levels
:
levels(DT$ind) = list(A = c(1, 3, 8), B = c(2, 4), C = 5:7)
原答案:
根据@Arun 的建议,我们可以选择将对应关系创建为单独的 data.table
,然后将其与原始对应关系连接起来:
match_dt = data.table(ind = as.factor(1:12),
grp = as.factor(c("A", "B", "A", "B", "C", "C",
"C", "A", "D", "E", "F", "D")))
setkey(DT, ind)
setkey(match_dt, ind)
DT = match_dt[DT]
我们也可以用(我认为的)更易读的方式来做到这一点(边际速度成本):
levels <- letters[1:12]
levels[c(1, 3, 8)] <- "A"
levels[c(2, 4)] <- "B"
levels[5:7] <- "C"
levels[c(9, 12)] <- "D"
levels[10] <- "E"
levels[11] <- "F"
match_dt <- data.table(ind = as.factor(1:12),
grp = as.factor(levels))
setkey(DT, ind)
setkey(match_dt, ind)
DT = match_dt[DT]