使用两种宽度方案读取固定宽度的文件

时间:2019-06-21 15:52:55

标签: r readr

我想读取一个大的固定宽度文件到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命令读取文件,并在读取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

1 个答案:

答案 0 :(得分:0)

一种方法(如果只有两种类型的话)是使用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函数{{1} }。

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()
相关问题