在data.table中生成数字存在性哑变量,如何避免使用for循环?
无循环实现字符型变量的哑变量生成(data.table版)
我有一个字符型变量,其中存储着长度不同的0到5的数字,想要创建5个哑变量(dummy-variables),用于标识每行是否存在对应数字(0到5)。我目前通过以下代码实现了该功能:
library(data.table) dataset <- data.table( 'char' = c('1 2 3 0', '1 5 0', '1 2 0', '1 0', '1 2 4 0') ) for(i in c(0:5)){ dataset[grepl(i, char), c(paste0('Idx_', i)) := 1] }
运行结果如下:
char Idx_0 Idx_1 Idx_2 Idx_3 Idx_4 Idx_5 1: 1 2 3 0 1 1 1 1 NA NA 2: 1 5 0 1 1 NA NA NA 1 3: 1 2 0 1 1 1 NA NA NA 4: 1 0 1 1 NA NA NA NA 5: 1 2 4 0 1 1 1 NA 1 NA
由于数据集规模较大,想知道无需for循环的实现方式。
方法1:data.table原生拆分-重塑流程
通过拆分字符列转为长格式,再重塑为宽格式生成哑变量,适合复杂拆分场景:
library(data.table) dataset <- data.table( char = c('1 2 3 0', '1 5 0', '1 2 0', '1 0', '1 2 4 0') ) # 按行拆分字符,生成每行对应的数字列表 dt_long <- dataset[, .(num = unlist(strsplit(char, " "))), by = .(row_id = 1:nrow(dataset))] # 标记数字存在为1 dt_long[, value := 1] # 重塑为宽格式,缺失值自动填充NA dt_wide <- dcast(dt_long, row_id ~ paste0("Idx_", num), value.var = "value") # 合并回原数据集,保留原始顺序 dataset <- cbind(dataset, dt_wide[, -"row_id"])
方法2:向量化grepl操作(高效简洁)
直接对0-5的每个值执行向量化匹配,一次性生成所有哑变量,避免循环:
library(data.table) dataset <- data.table( char = c('1 2 3 0', '1 5 0', '1 2 0', '1 0', '1 2 4 0') ) # 定义要创建的哑变量列名 cols <- paste0("Idx_", 0:5) # 向量化判断每个数字是否存在,转成1/0后替换0为NA dataset[, (cols) := lapply(0:5, function(x) as.integer(grepl(x, char)))] dataset[, (cols) := lapply(.SD, function(x) replace(x, x == 0, NA)), .SDcols = cols]
方法3:stringi包加速匹配(超大数据集首选)
如果数据量极大,用stringi::stri_detect_fixed进行固定字符串匹配,速度比grepl更快:
library(data.table) library(stringi) dataset <- data.table( char = c('1 2 3 0', '1 5 0', '1 2 0', '1 0', '1 2 4 0') ) cols <- paste0("Idx_", 0:5) # 固定匹配数字,生成1/0后替换0为NA dataset[, (cols) := lapply(0:5, function(x) as.integer(stri_detect_fixed(char, as.character(x))))] dataset[, (cols) := lapply(.SD, function(x) replace(x, x == 0, NA)), .SDcols = cols]
以上三种方法都能得到和原循环代码一致的结果,且均为无循环实现,其中方法2和3属于向量化操作,在大数据集上的执行效率远高于for循环。
内容的提问来源于stack exchange,提问作者Irgendniemand
相关产品推荐
相关产品推荐

