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

如何用readr的read_csv按列位置指定列类型:默认double,部分设character

问题

我有多个CSV文件,数据具备以下特性:

  • 绝大多数列为数值型;
  • 不同文件中的数值列数量不固定;
  • 少数列为字符型,这些字符列的数量和位置在所有文件中固定,但列名未知且不统一。

举个例子:前2列为字符型,后续是数量未知的double型,且前2列的列名在不同文件中存在差异(因此无法通过列名指定类型)。

我需要用read_csv实现以下需求:

  1. 指定double()为默认列类型;
  2. 按列位置而非列名将特定列设为character();
  3. 保留文件中原有的列名;
  4. 禁止read_csv猜测任何列类型,完全按照规则解析数据。

现有方案多依赖列名指定类型,无法满足需求。以下是测试示例:

生成测试CSV文件

suppressPackageStartupMessages(library(dplyr))
library(readr)

write_csv(iris, 'iris1.csv')
write_csv(rename(iris, species = Species), 'iris2.csv')
write_csv(rename(iris, Sp = Species), 'iris3.csv')

已知可行但无法使用的方案(依赖列名)

df1 <- read_csv('iris1.csv', col_types = cols(Species = 'c', .default = 'd'))
df2 <- read_csv('iris2.csv', col_types = cols(species = 'c', .default = 'd'))
df3 <- read_csv('iris3.csv', col_types = cols(Sp = 'c', .default = 'd'))

但我仅知晓第4列为字符型,其余为数值型,却不知道列名,需要强制按该规则读取文件。实际场景中文件包含数十列且列数不固定,col_types = 'dddc'这类方式不可行(readr会猜测未指定的列)。

尝试过的无效写法

# 语法错误,会报错
#df1 <- read_csv('iris1.csv', col_types = cols('4' = 'c', .default = 'd'))
#df2 <- read_csv('iris2.csv', col_types = cols('4' = 'c', .default = 'd'))
#df3 <- read_csv('iris3.csv', col_types = cols('4' = 'c', .default = 'd'))
# 可运行但会猜测列类型,不符合需求
df1 <- read_csv('iris1.csv', col_types = '???c')
df2 <- read_csv('iris2.csv', col_types = '???c')
df3 <- read_csv('iris3.csv', col_types = '???c')

解决方案

可以通过先读取文件列名,再动态构建col_types参数的方式,实现按位置指定列类型的需求,具体步骤如下:

  1. 快速读取目标CSV的列名(不加载数据);
  2. 初始化所有列为默认的double()类型,再将指定位置的列修改为character();
  3. 用构建好的col_types读取完整数据。

通用函数实现

library(readr)
library(purrr)

read_csv_by_position <- function(file_path, char_col_positions, default_type = col_double()) {
  # 读取列名,不加载数据
  col_names <- read_csv(file_path, n_max = 0) %>% colnames()
  # 初始化所有列为默认类型
  col_types <- map(col_names, ~default_type) %>% set_names(col_names)
  # 修改指定位置的列为字符型
  for(pos in char_col_positions) {
    if(pos <= length(col_types)) {
      col_types[[pos]] <- col_character()
    }
  }
  # 转换为cols对象
  col_types <- do.call(cols, col_types)
  # 读取数据
  read_csv(file_path, col_types = col_types)
}

测试使用

针对示例中「第4列为字符型」的场景,调用函数读取三个文件:

# 读取iris1.csv,第4列为字符型
df1 <- read_csv_by_position('iris1.csv', char_col_positions = 4)
# 读取iris2.csv,第4列为字符型
df2 <- read_csv_by_position('iris2.csv', char_col_positions = 4)
# 读取iris3.csv,第4列为字符型
df3 <- read_csv_by_position('iris3.csv', char_col_positions = 4)

# 验证列类型
sapply(df1, class)
sapply(df2, class)
sapply(df3, class)

说明

  • 通过read_csv(file_path, n_max = 0)获取列名,仅读取表头,效率极高;
  • 完全禁止readr的类型猜测逻辑,所有列类型严格按照设定规则解析;
  • 保留原文件的列名,符合需求;
  • 支持同时指定多个字符型列位置,比如char_col_positions = c(1,2)可将前两列设为字符型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:05:28