处理含列表列与NULL值的data.table:优化方案及性能疑问
问题:高效处理data.table中的列表列NULL转NA
我从SQL导出了一个大型data.table,SQL里的缺失值在data.table中变成了NULL,导致部分列变成了混有有效值和NULL的列表列。现在需要高效把这些NULL替换成NA,并将列表列转为标准data.table列。
复现场景示例代码
library(data.table) n = 10^6 l1 = as.list(rnorm(n, 10, 25)) l2 = as.list(rnorm(n, 0, 200)) l3 = as.list(rnorm(n)) df = data.table(a = runif(n), b = l1, c = l2, d = rnorm(n, 88, 0.5), e = l3 ) # 创建要设置为NULL的索引向量 id1 = sample(1:n, 0.26*n) id2 = sample(1:n, 0.60*n) id3 = sample(1:n, 0.09*n) # 设置为NULL df$b[id1] = list(NULL) df$c[id2] = list(NULL) df$e[id3] = list(NULL)
已尝试的两种方法(耗时较长)
# 仅需执行一次的列类型判断 type = data.frame(type = sapply(df, class)) col = names(df)[which(type$type == "list")] # ----------- 第一种方法 ----------------------------------------------------------------------- system.time( df[, (col) := lapply(.SD, function(i) unlist(lapply(i, function(x) ifelse(is.null(x), NA, x)))), .SDcols = col] ) # ----------- 第二种方法(稍快一点) --------------------------- system.time( for (i in col) { df[, eval(i) := unlist(lapply(get(i), function(x) ifelse(is.null(x), NA, x)))] } )
为什么第一种方法比第二种慢?
第一种方法采用了嵌套lapply:外层lapply(.SD, ...)遍历目标列,内层又对列中的每个元素做lapply,再额外调用unlist转换为向量。这种嵌套操作会带来双重循环的开销,再加上.SD在处理多列时会创建中间对象、传递环境,相比直接在for循环中用get(i)定位单列,额外成本更高。
而第二种方法的for循环直接针对单列操作,减少了.SD带来的中间环节,因此速度稍快。
更高效的解决方案
以下几种方法都能大幅提升处理速度,适合大型数据集:
方案1:用vapply替代嵌套lapply
vapply提前指定返回值类型,避免了类型推断开销,且直接返回向量,无需unlist:
system.time( df[, (col) := lapply(.SD, function(x) vapply(x, function(y) if (is.null(y)) NA_real_ else y, FUN.VALUE = numeric(1))), .SDcols = col] )
方案2:用purrr::map_dbl(需安装purrr包)
map_dbl专门针对数值型结果做了优化,代码更简洁:
library(purrr) system.time( df[, (col) := lapply(.SD, map_dbl, ~ifelse(is.null(.x), NA_real_, .x)), .SDcols = col] )
方案3:用data.table原生set函数(最快选项之一)
set是data.table的原地修改函数,跳过了[.data.table的额外开销,直接操作列,内存和速度表现最优:
system.time( for (j in col) { set(df, j = j, value = vapply(df[[j]], function(x) if (is.null(x)) NA_real_ else x, numeric(1))) } )
额外优化提示
- 针对列类型指定NA:如果是数值列用
NA_real_,字符列用NA_character_,避免隐式类型转换; - 避免重复计算:原代码中重复执行了列类型判断,只需执行一次即可。
内容的提问来源于stack exchange,提问作者nimliug
相关产品推荐
相关产品推荐

