使用purrr与read_csv批量跳过CSV首尾行的实现方法
批量处理CSV:用purrr跳过前2行与最后1行并合并数据集
问题场景
有一批从数据库导出的CSV文件(如site1_observations.csv、site2_observations.csv等),每个文件的结构如下:
| Column A | Column B | Column C |
|---|---|---|
| # 团队:所有团队 | ||
| # 观测类型:xyz | ||
| Site ID | Reason | Quantity |
| a | xyz | 1 |
| b | abc | 2 |
| 总数量 | 3 |
需求是:批量读取这些文件时跳过前2行注释行和最后1行汇总行,最终合并成一个用于分析的主数据集。
已知read_csv的skip参数可以跳过前几行,但没有直接跳过末行的参数,手动处理时通过n_max临时解决,但无法高效扩展到批量文件,希望用purrr::map()实现程序化处理。
手动处理示例
library(tidyverse) observations_skip_head <- 2 # 手动处理单个文件 site1_rawdata <- read_csv("/data/site1_observations.csv", skip = observations_skip_head, n_max = nrow(read_csv("/data/site1_observations.csv", skip = observations_skip_head))-1) # 重复处理其他文件后合并 # all_sites_rawdata <- bind_rows(site1_rawdata, site2_rawdata, ...)
尝试的程序化代码(存在问题)
用户尝试用purrr::map()批量处理,但n_max固定指向单个文件,无法动态适配每个CSV:
observations_csv_paths_chr <- paste0("data/site", 1:3,"_observations.csv") all_sites_rawdata <- observations_csv_paths_chr %>% map(~ read_csv(., skip = observations_skip_head, n_max = nrow(read_csv("/data/site1_observations.csv", skip = observations_skip_head))-1)) %>% set_names(observations_csv_paths_chr)
解决方案
下面提供两种基于purrr的实现方式,分别适用于不同场景:
方法1:先读取再过滤(简洁易读)
定义一个读取单文件的函数,先跳过前2行读取全部数据,再用slice(-n())移除最后一行汇总行,最后用map_dfr批量读取并合并:
library(tidyverse) observations_skip_head <- 2 observations_csv_paths_chr <- paste0("data/site", 1:3,"_observations.csv") # 定义读取单个CSV的函数 read_obs_csv <- function(file_path) { read_csv(file_path, skip = observations_skip_head) %>% slice(-n()) # 移除最后一行 } # 批量读取并合并,.id参数可选,用于标记数据来源文件 all_sites_rawdata <- observations_csv_paths_chr %>% map_dfr(read_obs_csv, .id = "source_file")
优点:代码简洁直观,容易理解和调试;缺点:会先读取包括最后一行的所有数据,对于超大CSV可能占用较多内存。
方法2:先计算有效行数再读取(高效省内存)
先通过read_lines获取文件总行数,计算出需要读取的有效行数(总行数 - 前2行 - 最后1行),再用n_max精准读取目标行,适合处理大文件:
read_obs_csv_efficient <- function(file_path) { # 获取文件总行数 total_lines <- length(read_lines(file_path)) # 计算需要读取的行数:总行数 - 要跳过的前2行 - 最后1行 valid_line_count <- total_lines - observations_skip_head - 1 read_csv(file_path, skip = observations_skip_head, n_max = valid_line_count) } # 批量读取并合并 all_sites_rawdata <- observations_csv_paths_chr %>% map_dfr(read_obs_csv_efficient, .id = "source_file")
优点:仅读取需要的行,内存占用更低,处理大文件更高效;缺点:多了一步读取总行数的操作,逻辑稍复杂。
内容的提问来源于stack exchange,提问作者Sam Lin
相关产品推荐
相关产品推荐

