求高效实现:为data.table中条目匹配对应小写形式的code
高效处理大样本data.table的low_code列生成需求
问题背景
我有一个约200万行、包含entry和code两列的data.table x。entry列的字符值可能存在对应的小写形式条目,也存在仅为小写或仅为非小写的条目,每行的code唯一。
可复现示例
library(data.table) x <- data.table(entry = c("Aaa", "Bbb", "Ccc", "aaa", "bbb", "ddd"), code = c(1, 2, 3, 4, 5, 6))
目标需求
新增low_code列:若entry存在对应小写形式条目,则填入其code;否则保留自身code,预期结果如下:
entry code low_code 1: Aaa 1 4 2: Bbb 2 5 3: Ccc 3 3 4: aaa 4 4 5: bbb 5 5 6: ddd 6 6
当前低效实现
我当前使用sapply逐行处理,在200万行数据上速度极慢,推测是逐行索引导致的:
x$low_code <- sapply(x$entry, USE.NAMES = F, FUN = function (e) { low_e <- tolower(e) ret <- x[x$entry == low_e,][["code"]] if (length(ret) == 0) { ret <- x[x$entry == e,][["code"]] } stopifnot(length(ret) %in% c(0, 1)) ret })
高效data.table实现方案
简洁版代码
# 提取所有小写entry及其对应的code lower_map <- x[tolower(entry) == entry, .(low_entry = entry, low_code = code)] # 通过entry的小写形式关联映射表,填充low_code x[lower_map, low_code := i.low_code, on = .(entry = tolower(low_entry))] # 对没有匹配到小写条目的行,用自身code填充 x[is.na(low_code), low_code := code]
详细说明
- 批量处理替代逐行操作:完全避免
sapply的逐行索引,利用data.table的分组和连接特性,所有操作都是批量完成,这是大样本下性能提升的关键。 - 构建小写映射表:先筛选出所有本身就是小写的
entry及其code,形成一个映射关系表。 - 高效关联填充:使用data.table的更新连接(
on = .(entry = tolower(low_entry))),将原表中每个entry的小写形式与映射表匹配,直接填充对应的low_code。 - 补全缺失值:对于没有对应小写条目的行(比如
Ccc和ddd),直接用自身的code填充low_code。
稳健版代码(适用于复杂场景)
如果担心存在多个非小写条目对应同一个小写的情况,这个版本更稳妥:
# 按entry的小写形式分组,优先取小写自身的code,否则取分组内第一个code low_map <- x[, .( target_code = ifelse(tolower(entry) == entry, code, NA) ), by = entry][, .( low_code = na.omit(target_code)[1] ), by = .(low_entry = tolower(entry))] # 关联回原表并填充 x[low_map, low_code := i.low_code, on = .(entry = low_entry)] x[is.na(low_code), low_code := code]
这个版本先为每个entry标记是否是小写,再按小写分组提取有效的目标code,确保每个小写分组只取到对应的小写条目code(如果存在)。
内容的提问来源于stack exchange,提问作者swolf
相关产品推荐
相关产品推荐

