r - 使用两种宽度方案读取固定宽度文件
问题描述
我想将一个大的固定宽度文件读入 R。固定宽度文件包含两种类型的行。即:以“A”开头的行包含由一组宽度定义的变量,以“B”开头的行包含由另一组宽度定义的变量。一个基于以下的玩具示例mtcars
:
AMazda RX4 21.0 160.0
BHornet 4 Drive 1 0 3
BHornet Sportabout 0 0 3
AMazda RX4 Wag 21.0 160.0
ADatsun 710 22.8 108.0
AHornet 4 Drive 21.4 258.0
BValiant 1 0 3
AHornet Sportabout 18.7 360.0
BDuster 360 0 0 3
目前,我使用两个readr::read_fwf
命令读取文件并在读取 s 后删除B
行,A
反之亦然。但是,当然,对于一个固定宽度的大文件,这意味着两次读取数据。而且,如果某些字符串变量的A
位置与 中的某些数字变量重叠B
,那么read_fwf
(最终)列类型会出错,我必须处理下游(下面的玩具示例中不是这种情况)。
有什么聪明的想法可以提高速度和工作流程吗?
我目前的“解决方案”:
example <- "
AMazda RX4 21.0 160.0
BHornet 4 Drive 1 0 3
BHornet Sportabout 0 0 3
AMazda RX4 Wag 21.0 160.0
ADatsun 710 22.8 108.0
AHornet 4 Drive 21.4 258.0
BValiant 1 0 3
AHornet Sportabout 18.7 360.0
BDuster 360 0 0 3"
library(tidyverse)
library(readr)
in_a <- read_fwf(example, fwf_widths(c(1, 20, 4, 5), c("code", "name", "mpg", "disp"))) %>%
filter(code == "A")
in_b <- read_fwf(example, fwf_widths(c(1, 20, 4, 3, 3), c("code", "name", "vs", "am", "gear"))) %>%
filter(code == "B")
结果
> in_a
# A tibble: 5 x 4
code name mpg disp
<chr> <chr> <dbl> <dbl>
1 A Mazda RX4 21 160
2 A Mazda RX4 Wag 21 160
3 A Datsun 710 22.8 108
4 A Hornet 4 Drive 21.4 258
5 A Hornet Sportabout 18.7 360
> in_b
# A tibble: 4 x 5
code name vs am gear
<chr> <chr> <dbl> <dbl> <dbl>
1 B Hornet 4 Drive 1 0 3
2 B Hornet Sportabout 0 0 3
3 B Valiant 1 0 3
4 B Duster 360 0 0 3
解决方案
一种方法(如果您只有两种类型)是使用comment=
参数:
library(readr)
in_a <- read_fwf("~/StackOverflow/jfeigenbaum.txt", fwf_widths(c(1, 20, 4, 5), c("code", "name", "mpg", "disp")),
comment = "B")
in_a
# # A tibble: 5 x 4
# code name mpg disp
# <chr> <chr> <dbl> <dbl>
# 1 A Mazda RX4 21 160
# 2 A Mazda RX4 Wag 21 160
# 3 A Datsun 710 22.8 108
# 4 A Hornet 4 Drive 21.4 258
# 5 A Hornet Sportabout 18.7 360
如果您有 2 种以上的类型并且想稍微概括一下,您可以使用pipe()
和 grep 输出(使用命令行grep
,而不是 R 函数grep()
)。
read_fwf(paste(readLines(pipe("grep ^A ~/StackOverflow/jfeigenbaum.txt")), collapse = "\n"),
fwf_widths(c(1, 20, 4, 5), c("code", "name", "mpg", "disp")))
# # A tibble: 5 x 4
# code name mpg disp
# <chr> <chr> <dbl> <dbl>
# 1 A Mazda RX4 21 160
# 2 A Mazda RX4 Wag 21 160
# 3 A Datsun 710 22.8 108
# 4 A Hornet 4 Drive 21.4 258
# 5 A Hornet Sportabout 18.7 360
不幸的是,虽然readr::read_table
现在可以pipe(...)
用作基于连接的输入,但它似乎read_fwf(pipe(...))
不起作用,因此我们需要上述临时(并且公认效率较低)的解决方法。(如果您的数据不大,这应该不会造成问题。)
最后,如果您的数据确实是一个字符串,您可以grep()
在拆分成单独的行后将其取出:
example <- strsplit("
AMazda RX4 21.0 160.0
BHornet 4 Drive 1 0 3
BHornet Sportabout 0 0 3
AMazda RX4 Wag 21.0 160.0
ADatsun 710 22.8 108.0
AHornet 4 Drive 21.4 258.0
BValiant 1 0 3
AHornet Sportabout 18.7 360.0
BDuster 360 0 0 3", "\\n")[[1]]
read_fwf(grep("^A", example, value = TRUE),
fwf_widths(c(1, 20, 4, 5), c("code", "name", "mpg", "disp")))
# # A tibble: 5 x 4
# code name mpg disp
# <chr> <chr> <dbl> <dbl>
# 1 A Mazda RX4 21 160
# 2 A Mazda RX4 Wag 21 160
# 3 A Datsun 710 22.8 108
# 4 A Hornet 4 Drive 21.4 258
# 5 A Hornet Sportabout 18.7 360
推荐阅读
- javascript - JavaScript单击嵌套html中的同级
- javascript - 使用带有 react-chartjs-2 的 chartjs-chart-geo 插件实现等值线图
- ruby-on-rails - rails 6 ajax“remote:true”什么都不做
- javascript - 嵌入后获取用户输入(Discord.js)
- mysql - 使用 express 和 nodejs 插入 mysql
- sql - 使用空行和列将 Excel 工作簿导入 SQL 数据库
- java - 如何从数组列表中删除重复项
- python - 在这段代码中,有一个初始化问题导致我们的函数行为不正确。你能找到问题并解决它吗?
- c# - C#匿名类型`ToString`复杂?
- html - 如何将引号保留在引号内?