R语言data.table批量列向量化乘法实现(无循环)
批量生成data.table列:cN = aN * bN(无循环实现)
假设我们有如下结构的data.table,其中包含大量形如a1、a2…a100和b1、b2…b100的列:
dt <- data.table(id = 1:5, a1 = runif(5), a2 = runif(5), b1 = runif(5), b2 = runif(5))
示例输出:
id a1 a2 b1 b2 1: 1 0.94431156 0.34668771 0.54899478 0.91512664 2: 2 0.32730005 0.87924651 0.88777763 0.90167832 3: 3 0.07438915 0.53728539 0.21463741 0.11291512 4: 4 0.23025893 0.08528074 0.68454936 0.45441690 5: 5 0.86105462 0.49976703 0.07362091 0.08834252
需要批量生成新列c1、c2…,满足cN = aN * bN,最终效果如下:
id a1 a2 b1 b2 c1 c2 1: 1 0.94431156 0.34668771 0.54899478 0.91512664 0.51842212 0.31726316 2: 2 0.32730005 0.87924651 0.88777763 0.90167832 0.29056966 0.79279752 3: 3 0.07438915 0.53728539 0.21463741 0.11291512 0.01596669 0.06066765 4: 4 0.23025893 0.08528074 0.68454936 0.45441690 0.15762361 0.03875301 5: 5 0.86105462 0.49976703 0.07362091 0.08834252 0.06339162 0.04415068
下面是几个高效的无循环实现方案:
方案1:列名匹配+Map批量赋值
先提取所有a和b开头的列,按后缀对应后批量计算:
# 筛选出a、b开头的列名 a_cols <- grep("^a\\d+$", colnames(dt), value = TRUE) b_cols <- grep("^b\\d+$", colnames(dt), value = TRUE) # 生成对应的c列名 c_cols <- sub("^a", "c", a_cols) # 批量执行乘法并赋值,Map自动对应每一组aN和bN dt[, (c_cols) := Map(`*`, .SD[, ..a_cols], .SD[, ..b_cols])]
这里..用来引用外部定义的列名向量,Map会逐个对a_cols和b_cols里的对应列做乘法,最后一次性把结果赋值给新的c列,全程没有循环,效率很高。
方案2:长格式转宽格式(适合超大量列场景)
如果你的列数特别多(比如几百上千列),可以先把数据转成“长格式”,计算后再转回宽格式:
# 转成长格式,把aN和bN对应分组 dt_long <- melt(dt, id.vars = "id", measure.vars = patterns("^a\\d+$", "^b\\d+$"), value.name = c("a_val", "b_val"), variable.name = "group") # 计算c值 dt_long[, c_val := a_val * b_val] # 转回宽格式 dt_wide <- dcast(dt_long, id ~ group, value.var = c("a_val", "b_val", "c_val")) # 重命名列,还原原有的aN、bN、cN格式 setnames(dt_wide, gsub("_val", "", colnames(dt_wide)))
这种方法利用melt和dcast的高效内部实现,避免手写循环,处理超大量列时表现稳定。
方案3:遍历后缀+get函数获取列
先提取所有数字后缀,再逐个生成对应列的乘法结果:
# 提取所有a/b列的数字后缀 nums <- unique(sub("^[ab]", "", grep("^[ab]\\d+$", colnames(dt), value = TRUE))) # 批量生成c列 dt[, paste0("c", nums) := lapply(nums, function(x) get(paste0("a", x)) * get(paste0("b", x)))]
get函数可以根据字符串获取对应的列,lapply遍历所有后缀,一次性生成所有乘法结果并赋值给新列,同样没有显式循环。
内容的提问来源于stack exchange,提问作者Algebro1000
相关产品推荐
相关产品推荐

