美文网首页R
R 数据处理(六)

R 数据处理(六)

作者: 名本无名 | 来源:发表于2021-01-17 11:48 被阅读0次

解析文件

讲到这里,你应该已经很清楚怎么解析单个向量了。那么让我们回到上节引出的 readr 是如何解析文件的问题。在本节中,将介绍另外两个新的问题

  1. readr 如何自动猜测每列的类型。

  2. 如何覆盖默认规范。

1. 策略

readr 使用启发式方法计算出每一列的类型:它读取前 1000 行,并使用一些(适度保守的)启发式方法来找出每一列的类型。

你可以使用 guess_parser()parse_guess() 解析字符向量来模拟这个过程,guess_parser() 返回 readr 的最佳猜测,parse_guess() 使用该猜测来解析列

> guess_parser("2010-10-01")
[1] "date"
> guess_parser("15:01")
[1] "time"
> guess_parser(c("TRUE", "FALSE"))
[1] "logical"
> guess_parser(c("1", "5", "9"))
[1] "double"
> guess_parser(c("12,352,561"))
[1] "number"
> 
> str(parse_guess("2010-10-10"))
 Date[1:1], format: "2010-10-10"

启发式方法尝试以下每种类型,在找到匹配时停止:

  • logical: 只包含 F, T, FALSE, 或 TRUE
  • integer: 只包含数字字符和 -
  • double: 只包含有效双精度数字(包含科学计数法 4.5e-5)
  • number: 包含有效的双精度数据,其中包含分组标记
  • time: 匹配默认的 time_format
  • date: 匹配默认的 date_format
  • date-time: 任何 ISO8601 格式

如果这些规则都不适用,那么列将保持为字符串向量。

2. Problems

这些默认值并不总是适用于较大的文件。存在两个基本问题:

  1. 1000 行可能是一个特殊情况,readr 猜测是一种不够通用的类型。例如,您可能有一个双精度列,它的前 1000 行中只包含整数

  2. 列可能包含许多缺少的值。如果前 1000 行只包含 NAreadr 会猜测它是一个逻辑向量,而您可能希望将其解析为更具体的内容。

> challenge <- read_csv(readr_example("challenge.csv"))

─ Column specification ────────────────────────────────────────
cols(
  x = col_double(),
  y = col_logical()
)

Warning: 1000 parsing failures.
 row col           expected     actual                                                                                         file
1001   y 1/0/T/F/TRUE/FALSE 2015-01-16 '/Library/Frameworks/R.framework/Versions/3.6/Resources/library/readr/extdata/challenge.csv'
1002   y 1/0/T/F/TRUE/FALSE 2018-05-18 '/Library/Frameworks/R.framework/Versions/3.6/Resources/library/readr/extdata/challenge.csv'
1003   y 1/0/T/F/TRUE/FALSE 2015-09-05 '/Library/Frameworks/R.framework/Versions/3.6/Resources/library/readr/extdata/challenge.csv'
1004   y 1/0/T/F/TRUE/FALSE 2012-11-28 '/Library/Frameworks/R.framework/Versions/3.6/Resources/library/readr/extdata/challenge.csv'
1005   y 1/0/T/F/TRUE/FALSE 2020-01-13 '/Library/Frameworks/R.framework/Versions/3.6/Resources/library/readr/extdata/challenge.csv'
.... ... .................. .......... ............................................................................................
See problems(...) for more details.

readr_example() 会寻找包自带的数据文件

可以看到打印了两部分的输出:第一部分是每列的解析格式,分别为 doublelogical。第二部分,显示了 1000 行之后发生了解析错误,并打印了前 5 个解析错误信息

我们可以使用 problems() 显示更加详细的信息

> problems(challenge)
# A tibble: 1,000 x 5
     row col   expected        actual    file                                                          
   <int> <chr> <chr>           <chr>     <chr>                                                         
 1  1001 y     1/0/T/F/TRUE/F… 2015-01-… '/Library/Frameworks/R.framework/Versions/3.6/Resources/libra…
 2  1002 y     1/0/T/F/TRUE/F… 2018-05-… '/Library/Frameworks/R.framework/Versions/3.6/Resources/libra…
 3  1003 y     1/0/T/F/TRUE/F… 2015-09-… '/Library/Frameworks/R.framework/Versions/3.6/Resources/libra…
 4  1004 y     1/0/T/F/TRUE/F… 2012-11-… '/Library/Frameworks/R.framework/Versions/3.6/Resources/libra…
 5  1005 y     1/0/T/F/TRUE/F… 2020-01-… '/Library/Frameworks/R.framework/Versions/3.6/Resources/libra…
 6  1006 y     1/0/T/F/TRUE/F… 2016-04-… '/Library/Frameworks/R.framework/Versions/3.6/Resources/libra…
# … with 994 more rows

一个较好的策略是一列一列地测试,直到没有问题为止。

在这里我们可以看到 y 列有许多解析问题,我们看下后面几行

0.1635163405444473,2018-03-29
0.47193897631950676,2014-08-04
0.7183186465408653,2015-08-16
0.26987858884967864,2020-02-04
0.608237189007923,2019-01-06

解析后变成了

> tail(challenge)
# A tibble: 6 x 2
      x y    
  <dbl> <lgl>
1 0.805 NA   
2 0.164 NA   
3 0.472 NA   
4 0.718 NA   
5 0.270 NA   
6 0.608 NA

这表明我们需要使用一个日期解析器。要修复调用,我们首先将列格式输出复制并粘贴到原始调用。

challenge <- read_csv(
  readr_example("challenge.csv"), 
  col_types = cols(
    x = col_double(),
    y = col_date() # col_logical()
  )
)

然后,将 col_logical() 改为 col_date()

> tail(challenge)
# A tibble: 6 x 2
      x y         
  <dbl> <date>    
1 0.805 2019-11-21
2 0.164 2018-03-29
3 0.472 2014-08-04
4 0.718 2015-08-16
5 0.270 2020-02-04
6 0.608 2019-01-06

每个 parse_*() 函数都有一个对应的 col_*() 函数。可以使用 parse_*() 解析 R 中的字符串向量,当你要告诉 readr 如何解析数据时,可以使用 col_*() 函数

强烈推荐使用 col_types 参数指定解析方式,这可以确保您拥有一个一致且可重复的数据导入脚本。

如果您依赖于默认猜测策略,但是您的数据发生了更改,readr 会继续读入它。如果您想严格控制数据格式,请使用 stop_ for_problems(): 如果有任何解析问题,它将抛出错误并停止脚本

3. 其他策略

还有其他一些通用策略可以帮助您解析文件:

  • 在前面的例子中,如果我们比默认多看一行,我们可以一次正确解析
> challenge2 <- read_csv(readr_example("challenge.csv"), guess_max = 1001)

─ Column specification ────────────────────────────────────────
cols(
  x = col_double(),
  y = col_date(format = "")
)
  • 有时,如果你只是把所有的列作为字符向量来读取,就会更容易诊断问题
challenge2 <- read_csv(readr_example("challenge.csv"), 
  col_types = cols(.default = col_character())
)

这在与 type_convert() 结合使用时非常有用,它将启发式解析应用于数据中的字符列

> df <- tribble(
+     ~x,  ~y,
+     "1", "1.21",
+     "2", "2.32",
+     "3", "4.56"
+ )
> df
# A tibble: 3 x 2
  x     y    
  <chr> <chr>
1 1     1.21 
2 2     2.32 
3 3     4.56 
> type_convert(df)

─ Column specification ────────────────────────────────────────
cols(
  x = col_double(),
  y = col_double()
)

# A tibble: 3 x 2
      x     y
  <dbl> <dbl>
1     1  1.21
2     2  2.32
3     3  4.56
  • 如果您正在读取一个非常大的文件,您可能希望将 n_max 设置为一个较小的数字,如 10,000100,000。这将消除常见问题的同时加速您的迭代

  • 如果您遇到了解析问题,有时使用 read_lines 读入一行的字符向量会更容易。甚至用 read_file 读取长度为 1 的字符向量

写入文件

readr 还提供了两个函数用于将输出写入到文件中: write_csv()write_tsv()。这两个函数都:

  • 总是用 UTF-8 编码字符串
  • ISO8601 格式保存日期和日期时间

如果想要保存为 Excel 格式的 csv 文件,可以使用 write_excel_csv()

最重要的两个参数是

  • x: 需要保存的数据
  • path: 数据保存路径

你还可以指定如何使用 na 代替缺失值,以及是否想要追加到现有文件

write_csv(challenge, "challenge.csv")

注意: 在保存到 csv 时,类型信息会丢失

> challenge
# A tibble: 2,000 x 2
       x y         
   <dbl> <date>    
 1   404 NA        
 2  4172 NA        
 3  3004 NA        
 4   787 NA        
 5    37 NA        
 6  2332 NA               
# … with 1,994 more rows
> write_csv(challenge, "challenge-2.csv")
> read_csv("challenge-2.csv")

─ Column specification ────────────────────────────────────────
cols(
  x = col_double(),
  y = col_logical()
)

Warning: 1000 parsing failures.
 row col           expected     actual              file
1001   y 1/0/T/F/TRUE/FALSE 2015-01-16 'challenge-2.csv'
1002   y 1/0/T/F/TRUE/FALSE 2018-05-18 'challenge-2.csv'
1003   y 1/0/T/F/TRUE/FALSE 2015-09-05 'challenge-2.csv'
1004   y 1/0/T/F/TRUE/FALSE 2012-11-28 'challenge-2.csv'
1005   y 1/0/T/F/TRUE/FALSE 2020-01-13 'challenge-2.csv'
.... ... .................. .......... .................
See problems(...) for more details.

# A tibble: 2,000 x 2
       x y    
   <dbl> <lgl>
 1   404 NA   
 2  4172 NA   
 3  3004 NA   
 4   787 NA   
 5    37 NA   
 6  2332 NA     
# … with 1,994 more rows

这使得 csv 在缓存中间结果时有点不可靠。可以使用其他两种方法

  1. write_rds()read_rds() 是对基本函数 readRDS()saveRDS() 的统一包装。将数据存储为 R 的自定义二进制格式称为 RDS
> write_rds(challenge, "challenge.rds")
> read_rds("challenge.rds")
# A tibble: 2,000 x 2
       x y         
   <dbl> <date>    
 1   404 NA        
 2  4172 NA        
 3  3004 NA        
 4   787 NA        
 5    37 NA        
 6  2332 NA        
 7  2489 NA        
 8  1449 NA        
 9  3665 NA        
10  3863 NA        
# … with 1,990 more rows
  1. feather 包实现了一种可以跨编程语言共享的快速二进制文件格式
> library(feather)
> write_feather(challenge, "challenge.feather")
> read_feather("challenge.feather")
# A tibble: 2,000 x 2
       x y         
   <dbl> <date>    
 1   404 NA        
 2  4172 NA        
 3  3004 NA        
 4   787 NA        
 5    37 NA        
 6  2332 NA        
 7  2489 NA        
 8  1449 NA        
 9  3665 NA        
10  3863 NA        
# … with 1,990 more rows

featherRDS 更快,且可以脱离 R 使用。

相关文章

网友评论

    本文标题:R 数据处理(六)

    本文链接:https://www.haomeiwen.com/subject/qvyaaktx.html