如何从自定义格式文本指定行读取数据并转换为data.frame
问题描述
有如下格式的文本文件内容:
DATE NETWORK GROUP ID AVERAGE CONC (YYMMDDHH) RECEPTOR (XR, YR, ZELEV, ZHILL, ZFLAG) OF TYPE GRID-ID - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ALL HIGH 1ST HIGH VALUE IS 3822.82070 ON 88011803: AT ( 500000.00, 4000150.00, 0.00, 0.00, 0.00) GC GRID1 HIGH 2ND HIGH VALUE IS 3376.11752 ON 88011803: AT ( 500000.00, 4000000.00, 0.00, 0.00, 0.00) GC GRID1 HIGH 3RD HIGH VALUE IS 2563.76151 ON 88022706: AT ( 500200.00, 4000000.00, 0.00, 0.00, 0.00) GC GRID1 HIGH 4TH HIGH VALUE IS 2033.30514 ON 88010224: AT ( 500050.00, 4000050.00, 0.00, 0.00, 0.00) GC GRID1
数据位于文件中间(例如第102839行),需要提取前两行数据,转换为如下结构的data.frame:
SRCGROUP Value Conc YYMMDDHH X_coord Y_coord Zelev Zhill ZFLAG 1 ALL 1ST HIGH VALUE 6099.915 8801222 500050 4000050 0 0 0 2 ALL 2ND HIGH VALUE 6001.993 88011801 500100 4000100 0 0 0
目前通过grep定位起始行(row + 9),用readLines读取目标行,但输出是字符向量,无法直接分割为列。尝试过以下代码:
temp <- readLines(file_name)[(row + 9):(row + 9+values_to_read)] out <- data.frame(SRCGROUP = temp[,1:9], Value = temp[,15:19], Conc = temp[,33:48], YYMMDDHH = temp[,52:60], X_coord = temp[,66:77], Y_coord = temp[,80:90], Zelev = temp[,91:100], Zhill = temp[,101:110], ZFLAG = temp[,111:119] )
现寻求可行解决方案。
解决方案
方法1:使用read.fwf读取固定宽度格式
你的文件属于固定宽度格式,用read.fwf可以直接按列宽读取,无需手动处理字符向量:
# 定义各列的起始和结束位置(根据文本格式调整) col_positions <- list( SRCGROUP = c(1, 9), Value = c(15, 31), Conc = c(33, 48), YYMMDDHH = c(52, 59), X_coord = c(66, 77), Y_coord = c(80, 90), Zelev = c(91, 100), Zhill = c(101, 110), ZFLAG = c(111, 119) ) # 转换为列宽向量 col_widths <- sapply(col_positions, function(x) x[2] - x[1] + 1) # 读取指定行 out <- read.fwf( file = file_name, widths = col_widths, skip = row + 8, # 跳过目标行之前的所有行 nrows = values_to_read, col.names = names(col_positions), strip.white = TRUE # 自动去除字段前后空格 ) # 清理YYMMDDHH列的冒号,转换数值列类型 out$YYMMDDHH <- gsub(":", "", out$YYMMDDHH) out[, c("Conc", "X_coord", "Y_coord", "Zelev", "Zhill", "ZFLAG")] <- lapply(out[, c("Conc", "X_coord", "Y_coord", "Zelev", "Zhill", "ZFLAG")], as.numeric)
方法2:处理已读取的字符向量
如果已经通过readLines得到temp字符向量,可使用stringr包提取字段并组合成data.frame:
library(stringr) # 逐字段提取并清理 out <- data.frame( SRCGROUP = str_trim(str_sub(temp, 1, 9)), Value = str_trim(str_sub(temp, 15, 31)), Conc = as.numeric(str_trim(str_sub(temp, 33, 48))), YYMMDDHH = str_trim(str_remove(str_sub(temp, 52, 59), ":")), X_coord = as.numeric(str_trim(str_sub(temp, 66, 77))), Y_coord = as.numeric(str_trim(str_sub(temp, 80, 90))), Zelev = as.numeric(str_trim(str_sub(temp, 91, 100))), Zhill = as.numeric(str_trim(str_sub(temp, 101, 110))), ZFLAG = as.numeric(str_trim(str_sub(temp, 111, 119))) ) # 填充第二行及以后的SRCGROUP空值(继承第一行的"ALL") out$SRCGROUP[out$SRCGROUP == ""] <- out$SRCGROUP[1]
注意:需根据实际文本的列位置微调起始/结束索引,确保截取内容准确。
内容的提问来源于stack exchange,提问作者melmo
相关产品推荐
相关产品推荐

