R data.table迭代多变量时如何与NA比较以标记缺失值填充更新行
问题原因
你现有代码的错误根源是mapply的传参逻辑错误:你传入的第二个参数fixed.vnames是字符串向量,而非对应的列向量,相当于在逐列把原始变量的向量和字符串做identical比较,自然全部返回FALSE。
解决方案
提供两种可行写法,第二种向量化方案更适配你千万级数据的性能需求:
方案1:适配你原有identical逻辑的写法
通过Map遍历原始变量名和填充后变量名的配对,用get()获取对应列的实际值再做比较:
update.names <- paste0('updated.', fill.in.vs) dt[, (update.names) := Map(function(orig_col, fixed_col) { mapply(identical, get(orig_col), get(fixed_col)) }, fill.in.vs, fixed.vnames)]
如果你的需求是标记被更新的行(即原始值和填充值不同),直接对结果取反即可:
dt[, (update.names) := Map(function(orig_col, fixed_col) { !mapply(identical, get(orig_col), get(fixed_col)) }, fill.in.vs, fixed.vnames)]
方案2:高性能向量化写法
逐行调用mapply在千万级数据下性能很差,可以直接用向量化逻辑替代identical的判断逻辑:两个值相等(包括同时为NA)的等价判断为x == y | (is.na(x) & is.na(y)),修改后代码如下:
update.names <- paste0('updated.', fill.in.vs) dt[, (update.names) := Map(function(orig, fixed) { .SD[[orig]] == .SD[[fixed]] | (is.na(.SD[[orig]]) & is.na(.SD[[fixed]])) }, fill.in.vs, fixed.vnames), .SDcols = c(fill.in.vs, fixed.vnames)]
同样如果要标记更新行,对逻辑结果取反即可:
dt[, (update.names) := Map(function(orig, fixed) { !(.SD[[orig]] == .SD[[fixed]] | (is.na(.SD[[orig]]) & is.na(.SD[[fixed]]))) }, fill.in.vs, fixed.vnames), .SDcols = c(fill.in.vs, fixed.vnames)]
运行两种方案都可以得到符合预期的标识列。
内容的提问来源于stack exchange,提问作者dmcd
相关产品推荐
相关产品推荐

