You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于data.table优化map2中rmultinomial的大样本运行效率

优化多项分布航班分配代码(处理千万级数据)

问题描述

我们需要通过多项分布将每行的总航班数分配到V1、V2、V3三个层级,但现有基于purrr::map2的代码在处理1000万行数据时耗时极长,希望优化实现(比如用data.table),核心要求是逐行对应不同的概率向量。

初始数据

number_total_flights
3
4
5

预期结果

number_total_flightsV1V2V3
3003
4211
5113

原代码及问题

原代码使用map2逐行调用rmultinom,但逐行操作在千万级数据下效率极低,且多次转换数据结构(列表转数据框再合并)进一步拖慢速度:

library(dplyr)
library(data.table)
library(purrr)

# 初始数据
base <- structure(list(
  number_total_flights = c(3L, 4L, 5L)), row.names = c(NA, 3L), class = "data.frame")

# 每行对应的概率向量列表
proba <- list(
  structure(c(0.1, 0.4, 0.5), .Dim = c(1L, 3L)),
  structure(c(0.5, 0.2, 0.3), .Dim = c(1L, 3L)),
  structure(c(0.2, 0.2, 0.6), .Dim = c(1L, 3L)))

# 逐行生成多项分布结果的函数
distrib_for_each_level <- function(nb_flights, prob){
  level <- t(rmultinom(n=1, size=nb_flights, prob=prob))
}

# 整合结果的函数
adding_levels <- function (base, proba){
  list_levels <- map2(base$number_total_flights, proba, distrib_for_each_level) %>%
    map(as.data.frame) %>% rbindlist()
  base <- base %>% cbind(list_levels)
} 

# 生成结果
base_with_levels <- adding_levels(base, proba)

优化方案:基于data.table的矢量化实现

核心思路是避免逐行调用rmultinom,改用批量/矢量化操作,同时用data.table直接处理减少数据转换开销:

方案1:利用apply批量处理+data.table合并

# 将概率列表转为矩阵
proba_mat <- do.call(rbind, proba)
# 转为data.table
base_dt <- as.data.table(base)

# 批量生成多项分布结果,比map2效率更高
multinom_dt <- as.data.table(t(
  apply(cbind(base_dt$number_total_flights, proba_mat), 1, function(x) {
    rmultinom(n=1, size=x[1], prob=x[2:4])
  })
))
# 重命名列
setnames(multinom_dt, c("V1", "V2", "V3"))

# 合并结果
base_with_levels_dt <- cbind(base_dt, multinom_dt)

方案2:用专用包实现高效批量生成(推荐千万级数据)

使用extraDistr包的rmnom函数,原生支持批量输入概率矩阵,性能远超逐行调用:

library(extraDistr)
library(data.table)

base_dt <- as.data.table(base)
proba_mat <- do.call(rbind, proba)

# 直接生成所有行的多项分布结果
multinom_fast <- rmnom(n = nrow(base_dt), size = base_dt$number_total_flights, prob = proba_mat)
# 合并到原数据
base_with_levels_fast <- cbind(base_dt, as.data.table(multinom_fast))

优化效果说明

  • 避免了map2的逐行迭代开销,批量操作在千万级数据下速度可提升数十倍
  • data.table的合并和转换操作内存效率更高,减少中间数据占用
  • extraDistr::rmnom是专为批量多项分布设计的函数,处理大规模数据时性能最优

内容的提问来源于stack exchange,提问作者Daoudi Karim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 01:20:38