R 如何實現(xiàn)更快讀取數(shù)據(jù) - 使用readr包

readr package

Hadley Wickham 和 RStudio 團隊開發(fā)了一個新的用于文本數(shù)據(jù)讀取的包,那就是readr包。readr包提供了幾個新的函數(shù),能夠更快的讀取文本文件.


#1. 相比于R基礎包

  • 比基礎模塊中函數(shù)速度更快(約快10倍);
  • 生成tibble,并且不會把字符向量轉換成因子,不使用行名稱,也不會隨意改動列名稱;
  • 更易于重復使用;

#2. readr介紹

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

  • readr 的多數(shù)函數(shù)用于將平面文件轉換為數(shù)據(jù)框。
read_csv()讀取逗號分隔文件
read_csv2()讀取分號分隔文件
read_tsv()讀取制表符分隔文件
read_delim()讀取使用任意分隔符的文件
read_fwf()讀取固定寬度文件;既可以使用fwf_widths()函數(shù)按照寬度來設定域,也可以使用fwf_positions()函數(shù)按照位置來設定域。read_table()讀取固定寬度文件的一種常用變體,其中使用空白字符來分隔各列
read_log()讀取Apache風格的日志文件。
read_csv()函數(shù)使用數(shù)據(jù)的第一行作為列名稱
read_table 可用于替代read.table();但是read.table()支持文件列之間存在不等長空格,read_table()要求列必需對齊;

有時候文件有幾行元數(shù)據(jù),可以使用skip=n來跳過前n行;或者使用comment="#"來丟棄所有以#開頭的行;

##2.2 與R基礎包進行比較

  • 比基礎模塊中函數(shù)速度更快(約快10倍)
  • 生成tibble,并且不會把字符向量轉換成因子,不使用行名稱,也不會隨意改動列名稱
  • 更易于重復使用

#3. 解析向量

parse_*()函數(shù)族接受一個字符向量,并返回一個特定向量,如邏輯、整數(shù)或日期向量

> 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 數(shù)值解析

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

對于數(shù)值型解析主要會遇到3個問題:

1. 各地數(shù)值書寫方式不同,小數(shù)分隔號有`.`和`,`
2. 數(shù)值賦予某種實際意義時,可能會加上某種符號,如$100或10%
3. 數(shù)值的分組處理,如1 000 000

對于第一個問題,可以通過創(chuàng)建一個新的地區(qū)對象設定參數(shù)decimal_mark解決;readr()默認的地區(qū)時美國。

parse_double("1.23")
parse_double("1,23",locale = locale(decimal_mark = ","))
  • parse_number()可以忽略數(shù)值前后的非數(shù)值型字符;
> parse_number("$100")
[1] 100
> parse_number("20%")
[1] 20
> parse_number("It cost $123.45")
[1] 123.45
  • parse_number()結合地區(qū)設置可以解決第三個問題;
> parse_number("$123,456,789")
[1] 123456789
#適用于歐洲多數(shù)國家
> 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()函數(shù)用于字符串解析

    字符串解析時需要注意編碼形式,默認編碼方式時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()函數(shù)用于解析因子,其中國levels參數(shù)設置水平。
> 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 基礎包中沒有能夠很好表示時間數(shù)據(jù)的內置類,但是可以使用hms包提供的時間類。
> library(hms)
> parse_date("01/02/15","%m/%d/%y")
[1] "2015-01-02"

#4. 解析文件

##4.1 每列數(shù)據(jù)類型確定

? 解析文件,首要任務就是對文件每列數(shù)據(jù)類型的確定;大多數(shù)工具會根據(jù)文件header或隨機抽取一定數(shù)量行數(shù)確定數(shù)據(jù)類型;readr 通過讀取文件前1000行來確定每列的類型,使用guess_parser()函數(shù)返回readr解析的數(shù)據(jù)類型,parse_guess()利用這個類型去解析文件的數(shù)據(jù)。

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

? 遇到特殊情況,讀取1000行的方法是行不通的;這時可以調控一些參數(shù)來解決遇到的問題。
col_types: 在文件讀取時,通過參數(shù)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: 指定用于解析列變量類型的行數(shù);
n_max():指定文件讀入行數(shù);在處理大內存文件時相當有用;
read_lines(): 按行讀入文件

#5. 寫入文件

  • write.csv(), write.tsv() 常用于將數(shù)據(jù)輸出到磁盤,默認使用UTF-8編碼;
write_csv(challenge,"challenge.csv")
read_csv("challenge.csv")

? 但是這種輸出方式的缺點就是無法保留列類型信息,當再次讀入文件時需要重新判定類的類型;這對于數(shù)據(jù)處理過程中輸出讀取臨時文件會產(chǎn)生沒必要的麻煩或錯誤;如果要避免這樣的現(xiàn)象,可以使用其它輸出方法:write_rds()和write_feather(), 后者需要調用feather包。

  • write_rds()聯(lián)合read_rds()使用,write_rds()將數(shù)據(jù)保存為自定義的二進制形式(RDS格式)
write_rds(challenge,"challenge.csv")
read_rds("challenge.csv")
  • feather包也是實現(xiàn)一種二進制形式,可以在多個編程語言之間共享;相比于RDS,速度更快。
library(feather)
write_feather(challenge,"challenge.csv")
read_feather("challenge.csv")

參考

New packages for reading data into R — fast
R 數(shù)據(jù)科學

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容