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

使用R的Arrow包合并含缺失值多CSV文件报错求助

问题与解决方案:合并超大CSV文件时的类型转换错误处理

问题背景

有13个超大CSV文件(kinder_2011.csv至kinder_2023.csv),列名及顺序完全一致,但部分列存在整文件缺失值(如kinder_2011.csv的month列全为NA)。使用arrow和tidyverse编写合并代码时,出现以下错误:

Error in compute.Dataset():
! Invalid: Could not open CSV input source 'C:/Users/XXXX/Dropbox/ChileEduc/data/intermediate/kinder/kinder_2013.csv': Invalid: In CSV column #26: Row #7: CSV conversion error to int32: invalid value ''
ℹ If you have supplied a schema and your data contains a header row, you should supply the argument skip = 1 to prevent the header being read in as data.

Run rlang::last_trace() to see where the error occurred.

错误核心:空字符串('')无法被arrow自动解析为int32类型的缺失值,导致类型转换失败。


解决方法

方法1:修改arrow读取参数,识别空字符串为缺失值

在open_delim_dataset中新增na = c("", "NA")参数,让arrow将空字符串和标准NA识别为缺失值,同时保留预定义schema确保数据类型一致。此方法无需加载全部数据到内存,适合超大文件:

library(arrow)
library(tidyverse)

# 保留原schema定义
schema <- schema(
  year = int32(),
  month = int32(),
  mrun = int32(),
  sex_stud = int32(),
  birth_date_stud = int32(),
  school_id = int32(),
  RBD = int32(),
  ID_ESTAB_J = int32(),
  ID_ESTAB_I = int32(),
  NOM_ESTAB = utf8(),
  COD_REG_ESTAB = int32(),
  COD_PRO_ESTAB = int32(),
  COD_COM_ESTAB = int32(),
  NOM_REG_ESTAB = utf8(),
  NOM_REG_A_ESTAB = utf8(),
  NOM_PRO_ESTAB = utf8(),
  NOM_COM_ESTAB = utf8(),
  COD_DEPROV_ESTAB = int32(),
  NOM_DEPROV_ESTAB = utf8(),
  latitude = float64(),
  longitude = float64(),
  rural_establishment = int32(),
  ORIGEN = int32(),
  DEPENDENCIA = int32(),
  NIVEL1 = int32(),
  NIVEL2 = int32(),
  COD_ENSE1_M = int32(),
  COD_GRADO_M = int32(),
  LET_CUR_M = utf8(),
  COD_TIP_CUR_M = int32(),
  COD_DEPE1_M = int32(),
  COD_ENSE2_M = int32(),
  ESTADO_ESTAB_M = int32(),
  CORR_GRU_J = int32(),
  COD_PROG_J = int32(),
  DESC_PROG_J = utf8(),
  COD_NIVEL_J = int32(),
  DESC_NIVEL_J = utf8(),
  COD_MODAL_J = int32(),
  DESC_MODAL_J = utf8(),
  COD_JOR_J = int32(),
  NOM_JOR_J = utf8(),
  DESC_MOD_I = utf8(),
  DESC_NIV_I = utf8(),
  COD_NIVEL_I = int32(),
  COD_GRUPO_I = int32(),
  TIPO_SOSTENEDOR = int32(),
  FORMAL = int32(),
  ASIS_REAL_J = int32(),
  ASIS_POTEN_J = int32(),
  DIAS_TRAB_GRUPO_J = int32()
)

# 读取数据集,指定空字符串为缺失值
kinder <- open_delim_dataset(
  paste0(getwd(), "/ChileEduc/data/intermediate/kinder"),
  delim = ";",
  schema = schema,
  skip = 1,
  na = c("", "NA")  # 新增参数:将空字符串和NA识别为缺失值
)

# 导出为Parquet(推荐,压缩率高、适合大数据)
write_parquet(kinder, paste0(getwd(), "/ChileEduc/data/final/kinder_combined.parquet"))

# 若需CSV格式(不推荐,体积大),可执行:
# write_csv(as.data.frame(kinder), paste0(getwd(), "/ChileEduc/data/final/kinder_combined.csv"))

方法2:单文件读取并处理异常值(适合排查问题)

如果方法1仍报错,可逐个读取文件,手动处理数值列的异常值后再合并,确保每个文件的数据类型匹配:

library(arrow)
library(tidyverse)

# 获取所有目标文件路径
file_paths <- list.files(
  paste0(getwd(), "/ChileEduc/data/intermediate/kinder"),
  pattern = "kinder_\\d{4}\\.csv",
  full.names = TRUE
)

# 定义单文件处理函数:转换异常值为NA,匹配数据类型
process_file <- function(file_path) {
  df <- read_delim(file_path, delim = ";", skip = 1, na = c("", "NA"))
  # 将非字符型的字符列转为整数,经纬度转为浮点型
  df <- df %>%
    mutate(
      across(where(is.character) & !matches("^NOM_|^DESC_|^LET_CUR_M"), ~as.integer(.)),
      across(c(latitude, longitude), as.double)
    )
  return(df)
}

# 批量处理并合并所有文件
kinder_combined <- map_dfr(file_paths, process_file)

# 导出为Parquet
write_parquet(kinder_combined, paste0(getwd(), "/ChileEduc/data/final/kinder_combined.parquet"))

关键注意事项

  • 优先使用Parquet格式:列式存储,压缩率远高于CSV,后续读取和分析速度更快,适合900万条观测的数据集。
  • 避免全量加载到内存:直接对arrow的Dataset对象执行write_parquet,无需转为data.frame,减少内存占用。
  • 排查单个文件:若仍有错误,单独读取kinder_2013.csv查看第26列(NIVEL2)的异常值,确认是否存在非空字符串的无效值,手动清理后再合并。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:34:54