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

能否用Arrow按列而非列值划分数据集?data.table内存优化求助

分批生成按列分组的Parquet文件并合并方案

前提准备

假设你已经有包含完整2900万行index列的主数据表main_index_dt(可从文件读取或生成),样本文件为带index列的单个样本数据(如sample1.csv到sample10.csv)。


方案一:每个Parquet文件包含index+分组样本列

步骤1:分组样本文件

将10个样本文件分成每组5个:

library(data.table)
library(arrow)

# 加载主index表
main_index_dt <- fread("main_index.csv") # 替换为你的主index文件路径
# 样本文件列表
sample_files <- paste0("sample", 1:10, ".csv")
# 按每5个一组拆分
file_groups <- split(sample_files, ceiling(seq_along(sample_files)/5))

步骤2:分批处理并写入Parquet

循环处理每个分组,合并样本列与主index后写入文件,主动释放内存:

for (i in seq_along(file_groups)) {
  group_files <- file_groups[[i]]
  # 初始化临时表,先复制主index
  temp_dt <- copy(main_index_dt)
  
  # 逐个读取样本文件,合并到临时表
  for (f in group_files) {
    sample_dt <- fread(f)
    # 按index合并,保证与主index行完全匹配(空值自动填充NA)
    sample_dt <- merge(temp_dt[, .(index)], sample_dt, by = "index", all.x = TRUE)
    # 将样本列加入临时表
    temp_dt[, colnames(sample_dt)[-1] := sample_dt[, .SD, .SDcols = -"index"]]
    
    # 释放当前样本文件的内存
    rm(sample_dt)
    gc()
  }
  
  # 写入Parquet文件
  write_parquet(temp_dt, paste0("part-", i, ".parquet"))
  
  # 释放临时表内存
  rm(temp_dt)
  gc()
}

方案二:单独存储index,Parquet仅存样本列

步骤1:写入单独的index文件

write_parquet(main_index_dt, "index.parquet")

步骤2:分批处理样本列并写入Parquet

for (i in seq_along(file_groups)) {
  group_files <- file_groups[[i]]
  temp_dt <- copy(main_index_dt)
  
  for (f in group_files) {
    sample_dt <- fread(f)
    sample_dt <- merge(temp_dt[, .(index)], sample_dt, by = "index", all.x = TRUE)
    temp_dt[, colnames(sample_dt)[-1] := sample_dt[, .SD, .SDcols = -"index"]]
    
    rm(sample_dt)
    gc()
  }
  
  # 移除index列,仅保留样本列
  temp_dt[, index := NULL]
  write_parquet(temp_dt, paste0("part-", i, ".parquet"))
  
  rm(temp_dt)
  gc()
}

读取合并Parquet文件

针对方案一(每个Parquet带index)

# 获取所有part文件路径
part_files <- list.files(pattern = "part-.*\\.parquet", full.names = TRUE)
# 逐个读取并按index合并(或直接cbind,因为index顺序一致)
full_dt <- lapply(part_files, function(f) as.data.table(read_parquet(f))) %>% 
  Reduce(function(x, y) merge(x, y, by = "index", all.x = TRUE), .)

# 或用更高效的cbind(需保证所有文件的index顺序完全一致)
full_dt <- do.call(cbind, lapply(part_files, function(f) as.data.table(read_parquet(f))))
# 去重重复的index列
full_dt <- full_dt[, !duplicated(colnames(full_dt)), with = FALSE]

针对方案二(单独index+样本列Parquet)

# 读取index表
index_dt <- as.data.table(read_parquet("index.parquet"))
# 读取所有样本列Parquet
part_dts <- lapply(list.files(pattern = "part-.*\\.parquet", full.names = TRUE), 
                   function(f) as.data.table(read_parquet(f)))
# 合并index与所有样本列
full_dt <- cbind(index_dt, do.call(cbind, part_dts))

注意事项

  • 处理样本文件时必须通过merge与主index匹配,确保行顺序和完整性,避免直接读取样本文件就写入(可能存在index缺失或顺序不一致)。
  • 每次处理完单个样本文件或分组后,用rm()+gc()主动释放内存,避免内存累积。
  • 方案一的容错性更高,每个Parquet文件独立包含index,合并时无需依赖行顺序;方案二的文件体积更小,但需严格保证样本列的行顺序与index完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:30:06