R 如何实现更快读取数据 - 使用readr包

readr package

Hadley Wickham 和 RStudio 团队开发了一个新的用于文本数据读取的包,那就是readr包。readr包提供了几个新的函数,能够更快的读取文本文件.


#1. 相比于R基础包

  • 比基础模块中函数速度更快(约快10倍);
  • 生成tibble,并且不会把字符向量转换成因子,不使用行名称,也不会随意改动列名称;
  • 更易于重复使用;

#2. readr介绍

##2.1 readr()也是tidyverse的核心包之一。

  • readr 的多数函数用于将平面文件转换为数据框。
read_csv()读取逗号分隔文件
read_csv2()读取分号分隔文件
read_tsv()读取制表符分隔文件
read_delim()读取使用任意分隔符的文件
read_fwf()读取固定宽度文件;既可以使用fwf_widths()函数按照宽度来设定域,也可以使用fwf_positions()函数按照位置来设定域。read_table()读取固定宽度文件的一种常用变体,其中使用空白字符来分隔各列
read_log()读取Apache风格的日志文件。
read_csv()函数使用数据的第一行作为列名称
read_table 可用于替代read.table();但是read.table()支持文件列之间存在不等长空格,read_table()要求列必需对齐;

有时候文件有几行元数据,可以使用skip=n来跳过前n行;或者使用comment="#"来丢弃所有以#开头的行;

##2.2 与R基础包进行比较

  • 比基础模块中函数速度更快(约快10倍)
  • 生成tibble,并且不会把字符向量转换成因子,不使用行名称,也不会随意改动列名称
  • 更易于重复使用

#3. 解析向量

parse_*()函数族接受一个字符向量,并返回一个特定向量,如逻辑、整数或日期向量

> str(parse_logical(c("TRUE","FALSE","NA")))
 logi [1:3] TRUE FALSE NA
> str(parse_integer(c("1","2","3")))
 int [1:3] 1 2 3
> str(parse_date(c("2010-01-01","1979-10-14")))
 Date[1:2], format: "2010-01-01" "1979-10-14"

##3.1 数值解析

  • parse_integer() 解析整数;
  • parse_double()和parse_number()都是数值型解析函数;

对于数值型解析主要会遇到3个问题:

1. 各地数值书写方式不同,小数分隔号有`.`和`,`
2. 数值赋予某种实际意义时,可能会加上某种符号,如$100或10%
3. 数值的分组处理,如1 000 000

对于第一个问题,可以通过创建一个新的地区对象设定参数decimal_mark解决;readr()默认的地区时美国。

parse_double("1.23")
parse_double("1,23",locale = locale(decimal_mark = ","))
  • parse_number()可以忽略数值前后的非数值型字符;
> parse_number("$100")
[1] 100
> parse_number("20%")
[1] 20
> parse_number("It cost $123.45")
[1] 123.45
  • parse_number()结合地区设置可以解决第三个问题;
> parse_number("$123,456,789")
[1] 123456789
#适用于欧洲多数国家
> parse_number("$123.456.789",locale = locale(grouping_mark = "."))
[1] 123456789
#适用于瑞士
> parse_number("$123'456,789",locale = locale(grouping_mark = "'"))
[1] 123456

##3.2 字符串解析

  • parse_character()函数用于字符串解析

    字符串解析时需要注意编码形式,默认编码方式时UTF-8;

> x2<-"\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"
> parse_character(x2,locale = locale(encoding = "shift-JIS"))
[1] "こんにちは"

​ 对于不知道编码方式的字符串,可以使用guess_encoding(charToRaw())找出编码方式,charToRaw()可以返回字符串的底层表示;

> guess_encoding(charToRaw(x2))
# A tibble: 1 x 2
  encoding confidence
  <chr>         <dbl>
1 KOI8-R         0.42

##3.3 因子解析

  • parse_factor()函数用于解析因子,其中国levels参数设置水平。
> fruit<-c("apple","banana")
> parse_factor(c("apple","banana","bananana"),levels = fruit)
Warning: 1 parsing failure.
row col           expected   actual
  3  -- value in level set bananana

[1] apple  banana <NA>  
attr(,"problems")
# A tibble: 1 x 4
    row   col expected           actual  
  <int> <int> <chr>              <chr>   
1     3    NA value in level set bananana
Levels: apple banana

##3.4 日期、日期时间和时间解析

  • parse_datetime() 接受符合ISO 8601标准的日期时间,其中日期的各个部分按从大到小的顺序排列,即年、月、日,小时,分钟、秒;
> parse_datetime("2010-10-01T2010")
[1] "2010-10-01 20:10:00 UTC"
  • parse_date() 接受年月日;
> parse_date("2010-10-01")
[1] "2010-10-01"
  • parse_time() 接受小时;但是还可以加上分钟,秒,以及a.m./p.m.标识符
> parse_time("01:01 am")
01:01:00
  • R 基础包中没有能够很好表示时间数据的内置类,但是可以使用hms包提供的时间类。
> library(hms)
> parse_date("01/02/15","%m/%d/%y")
[1] "2015-01-02"

#4. 解析文件

##4.1 每列数据类型确定

​ 解析文件,首要任务就是对文件每列数据类型的确定;大多数工具会根据文件header或随机抽取一定数量行数确定数据类型;readr 通过读取文件前1000行来确定每列的类型,使用guess_parser()函数返回readr解析的数据类型,parse_guess()利用这个类型去解析文件的数据。

> guess_parser("2010-10-01")
[1] "date"
> guess_parser("15:01")
[1] "time"

​ 遇到特殊情况,读取1000行的方法是行不通的;这时可以调控一些参数来解决遇到的问题。
col_types: 在文件读取时,通过参数col_types指定每列的类型;

> challenge<-read_csv(readr_example("challenge.csv"))
Parsed with 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 'C:/Users/labworker/Documents/R/win-library/3.5/readr/extdata/challenge.csv'
1002   y 1/0/T/F/TRUE/FALSE 2018-05-18 'C:/Users/labworker/Documents/R/win-library/3.5/readr/extdata/challenge.csv'
1003   y 1/0/T/F/TRUE/FALSE 2015-09-05 'C:/Users/labworker/Documents/R/win-library/3.5/readr/extdata/challenge.csv'
1004   y 1/0/T/F/TRUE/FALSE 2012-11-28 'C:/Users/labworker/Documents/R/win-library/3.5/readr/extdata/challenge.csv'
1005   y 1/0/T/F/TRUE/FALSE 2020-01-13 'C:/Users/labworker/Documents/R/win-library/3.5/readr/extdata/challenge.csv'
.... ... .................. .......... ............................................................................
See problems(...) for more details.

> head(challenge)
# A tibble: 6 x 2
      x y    
  <dbl> <lgl>
1   404 NA   
2  4172 NA   
3  3004 NA   
4   787 NA   
5    37 NA   
6  2332 NA   
> challenge<-read_csv(readr_example("challenge.csv"),
                    col_types = cols(
                      x = col_double(),
                      y = col_character()
                    )
                    )

guess_max: 指定用于解析列变量类型的行数;
n_max():指定文件读入行数;在处理大内存文件时相当有用;
read_lines(): 按行读入文件

#5. 写入文件

  • write.csv(), write.tsv() 常用于将数据输出到磁盘,默认使用UTF-8编码;
write_csv(challenge,"challenge.csv")
read_csv("challenge.csv")

​ 但是这种输出方式的缺点就是无法保留列类型信息,当再次读入文件时需要重新判定类的类型;这对于数据处理过程中输出读取临时文件会产生没必要的麻烦或错误;如果要避免这样的现象,可以使用其它输出方法:write_rds()和write_feather(), 后者需要调用feather包。

  • write_rds()联合read_rds()使用,write_rds()将数据保存为自定义的二进制形式(RDS格式)
write_rds(challenge,"challenge.csv")
read_rds("challenge.csv")
  • feather包也是实现一种二进制形式,可以在多个编程语言之间共享;相比于RDS,速度更快。
library(feather)
write_feather(challenge,"challenge.csv")
read_feather("challenge.csv")

参考

New packages for reading data into R — fast
R 数据科学

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351