使用Arrow的open_dataset读取多CSV时,如何将int转为double?
解决Arrow读取CSV时int64与double类型不兼容问题
核心问题原因
- Arrow默认仅读取前N行(R默认1000行、Python默认1000行)推断CSV列类型,若某列前N行都是整数、后续出现浮点数,会被误判为
int64类型。 unify_schemas = TRUE默认不允许int64与double合并,Arrow认为这两种类型属于不兼容类型,需显式开启类型提升策略。
R 解决方案
方案1:读取全部行推断类型+自动类型提升
通过配置CSV读取选项,强制Arrow读取每个文件的所有行来推断类型,再通过自定义合并逻辑允许int64自动提升为double:
library(tidyverse) library(arrow) # 配置CSV读取规则:读取全部行推断类型 csv_options <- csv_format(infer_schema_length = -1) # 自定义schema合并函数,允许类型提升 merge_schemas_with_promotion <- function(schemas) { reduce(schemas, function(a, b) { a$merge(b, promote = TRUE) }) } # 获取每个CSV文件的独立schema file_paths <- list.files("data/", pattern = "\\.csv$", full.names = TRUE) file_schemas <- map(file_paths, ~read_csv_arrow(.x, format = csv_options)$schema) # 合并所有schema,允许int转double unified_schema <- merge_schemas_with_promotion(file_schemas) # 使用合并后的schema读取数据集 csvs <- open_dataset( sources = "data/", format = "csv", schema = unified_schema, format_options = csv_options ) csvs |> glimpse()
方案2:仅修改特定列类型(无需枚举所有列)
如果不想读取全部行,可以先自动推断基础schema,再单独调整需要兼容的列类型:
library(tidyverse) library(arrow) # 获取所有文件的初始schema并合并 file_paths <- list.files("data/", pattern = "\\.csv$", full.names = TRUE) file_schemas <- map(file_paths, ~read_csv_arrow(.x)$schema) temp_schema <- reduce(file_schemas, function(a, b) {a$merge(b, promote = TRUE)}) # 修改指定列的类型(这里是列b改为double) final_schema <- schema( a = temp_schema$a, # 保留原类型 b = float64() # 强制设为double ) # 使用调整后的schema读取数据集 csvs <- open_dataset( sources = "data/", format = "csv", schema = final_schema ) csvs |> glimpse()
Python 解决方案
方案1:读取全部行推断类型+自动类型提升
import os import pyarrow as pa import pyarrow.dataset as ds # 配置CSV读取规则:读取全部行推断类型 csv_read_options = pa.csv.ReadOptions(infer_schema_length=-1) csv_format = ds.CsvFormat() # 获取每个CSV文件的独立schema file_paths = [f"data/{f}" for f in os.listdir("data") if f.endswith(".csv")] schemas = [] for path in file_paths: table = pa.csv.read_csv(path, read_options=csv_read_options) schemas.append(table.schema) # 合并schema,允许int64提升为double unified_schema = schemas[0] for schema in schemas[1:]: unified_schema = unified_schema.merge(schema, promote=True) # 使用合并后的schema读取数据集 dataset = ds.open_dataset( "data/", format="csv", schema=unified_schema, format_options=csv_format ) # 查看结果 print(dataset.schema) print(dataset.to_table().to_pandas())
方案2:仅修改特定列类型
import pyarrow as pa import pyarrow.dataset as ds # 先读取足够多的行推断基础schema temp_dataset = ds.open_dataset("data/", format="csv", infer_schema_length=100000) base_schema = temp_dataset.schema # 调整指定列的类型(这里是列b改为float64) new_fields = [] for field in base_schema.fields: if field.name == "b": new_fields.append(pa.field(field.name, pa.float64())) else: new_fields.append(field) final_schema = pa.schema(new_fields) # 使用调整后的schema读取数据集 dataset = ds.open_dataset( "data/", format="csv", schema=final_schema ) print(dataset.schema) print(dataset.to_table().to_pandas())
补充说明
infer_schema_length=-1会读取整个文件推断类型,若文件极大,可设置一个足够大的数值(如1000000)覆盖可能出现类型转换的行,平衡性能与准确性。- 合并schema时的
promote=True是关键,它允许Arrow将兼容的数值类型自动提升(如int64→float64),避免类型不兼容错误。 - 手动指定schema时,只需修改需要调整的列,其他列可保留自动推断的类型,无需枚举所有列。
内容的提问来源于stack exchange,提问作者falsePockets
相关产品推荐
相关产品推荐

