首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >「Workshop」第四十二期 R文件读写

「Workshop」第四十二期 R文件读写

作者头像
王诗翔呀
发布2021-04-23 11:01:23
发布2021-04-23 11:01:23
1.3K0
举报
文章被收录于专栏:优雅R优雅R

rio package

rio是一个比较简单,但是又非常强大的一个数据读写包,这个包的特点是:根据文件的拓展名推断文件的类型,然后调用不同的包来读写数据,目前支持的文件类型

主要使用的函数有:

  • importimport_list
  • exportexport_list
  • convert

import

import函数的用法:

代码语言:javascript
复制
import(file, format, setclass, which, ...)
  • file指定文件名
  • format 一般是根据文件名来推断文件类型,但是也可以通过这个参数来指定文件类型
  • setclass 指定读入数据后返回的数据类型,默认是data.frame,可以更改为"tbl_df","tbl","tibble","data.table"
  • which 当我们需要从含有多个数据对象的文件中读取数据时可以指定这个参数;比如file是一个压缩的文件夹,可以使用该参数来指定需要读取的文件;如果是一个excel表格(含有多个子表格),可以使用which指定读取的表格;如果是一个Rdata文件也可以指定需要读取的对象

当我们在一个文件夹下有多个文件,可以使用import_list函数来一次性读入:

代码语言:javascript
复制
list.files("./files_list/")
#[1] "ACC_simulation.rds"  "BLCA_simulation.rds" "BRCA_simulation.rds"
dt <- import_list(file =paste0("./files_list/",dir("files_list/")),rbind = T)

export

export函数的用法为:

代码语言:javascript
复制
export(x, file, format, ...)
  • x 数据框或者矩阵
  • file 保存的文件名
  • format 保存的文件格式(文件拓展名);fileformat至少要指定一个

也可以使用export将多个对象输出到一个文件中(excel和Rdata):

代码语言:javascript
复制
##export
export(iris,file = "iris.csv")
# export to sheets of an Excel workbook
export(list(mtcars = mtcars, iris = iris), "multi.xlsx")
# export to an .Rdata file
## as a named list
export(list(mtcars = mtcars, iris = iris), "multi.rdata")
## as a character vector
export(c("mtcars", "iris"), "multi2.rdata")

export_list可以将多个对象输出为多个文件:

代码语言:javascript
复制
export_list(list(mtcars = mtcars, iris = iris), "%s.tsv")

convert

convert函数是importexport函数的包装,可以直接将一种格式的文件转化成另一种格式的文件

代码语言:javascript
复制
convert(in_file = "iris.csv",out_file = "iris.tsv")

readr package

readr包主要有7个函数用来进行数据的读入:

  • read_csv(): comma separated (CSV) files
  • read_tsv(): tab separated files
  • read_delim(): general delimited files
  • read_fwf(): fixed width files
  • read_table(): tabular files where columns are separated by white-space.
  • read_log(): web log files

base Rread.*函数相比,readr包的read_*函数的特点有:

  • 更快
  • 读入的数据类型是tibbles,不会将字符变量转化为因子;可以自动的解析常见的时间格式
  • base R在读取数据时可能会继承一些操作系统的行为或者环境变量,使得代码的复用性降低

5-1-1

readr将文件解析成tibble分成3个步骤:

  • 文件被解析成字符串矩阵
  • 决定每列的数据类型
  • 将每列的字符串按照特定的数据类型进行解析

向量解析

向量解析使用parse_*函数,将字符向量转化为特定类型的向量

代码语言:javascript
复制
parse_integer(c("1", "2", "3"))
#> [1] 1 2 3
parse_double(c("1.56", "2.34", "3.56"))
#> [1] 1.56 2.34 3.56
parse_logical(c("true", "false"))
#> [1]  TRUE FALSE

readr默认.作为小数点,,作为分节号(group marker),可以使用locale()来更改:

代码语言:javascript
复制
parse_double(c("1,56", "2,34", "356"),locale=locale(decimal_mark = ","))

使用parse_number可以更灵活的解析字符到数字:

代码语言:javascript
复制
parse_number(c("0%", "10%", "150%"))
#> [1]   0  10 150
parse_number(c("$1,234.5", "$12.45"))
#> [1] 1234.50   12.45

readr也支持日期,时间数据的解析,有3个函数:

  • parse_datetime() ISO8601
  • parse_date()
  • parse_time()
代码语言:javascript
复制
parse_datetime("2010-10-01T2010")
#> [1] "2010-10-01 20:10:00 UTC"
# If time is omitted, it will be set to midnight
parse_datetime("20101010")
#> [1] "2010-10-10 UTC"

parse_date("2010-10-01")
#> [1] "2010-10-01"

library(hms)
parse_time("01:10 am")
#> 01:10:00
parse_time("20:10:01")
#> 20:10:01

列类型判断

readr使用启发式的方法来猜测每一列的数据类型,使用的函数是guess_parser:

代码语言:javascript
复制
guess_parser(c("a", "b", "c"))
#> [1] "character"
guess_parser(c("1", "2", "3"))
#> [1] "double"
guess_parser(c("1,000", "2,000", "3,000"))
#> [1] "number"
guess_parser(c("2001/10/10"))
#> [1] "date"

在读入文件的时候可以使用col_type来人为指定列的类型

可以通过spec_**函数来查看数据读入过程中的列类型判断:

代码语言:javascript
复制
x <- spec_csv(readr_example("challenge.csv"))
#> 
#> ── Column specification ────────────────────────────────────────────────────────
#> cols(
#>   x = col_double(),
#>   y = col_logical()
#> )

数据解析

当使用readr的7个函数读入数据时,这些函数会先读入字符矩阵,然后调用spec_*函数来决定每列的数据类型,最后根据这个类型来解析每一列:

代码语言:javascript
复制
df2 <- read_csv("iris.csv")
# Parsed with column specification:
#   cols(
#     Sepal.Length = col_double(),
#     Sepal.Width = col_double(),
#     Petal.Length = col_double(),
#     Petal.Width = col_double(),
#     Species = col_character()
#   )

可能存在的问题

readr猜列的数据类型时是先读入前1000行,然后根据这1000行来决定列的数据类型:

代码语言:javascript
复制
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 '/Users/runner/work/_temp/Library/readr/extdata/challenge.csv'
#> 1002   y 1/0/T/F/TRUE/FALSE 2018-05-18 '/Users/runner/work/_temp/Library/readr/extdata/challenge.csv'
#> 1003   y 1/0/T/F/TRUE/FALSE 2015-09-05 '/Users/runner/work/_temp/Library/readr/extdata/challenge.csv'
#> 1004   y 1/0/T/F/TRUE/FALSE 2012-11-28 '/Users/runner/work/_temp/Library/readr/extdata/challenge.csv'
#> 1005   y 1/0/T/F/TRUE/FALSE 2020-01-13 '/Users/runner/work/_temp/Library/readr/extdata/challenge.csv'
#> .... ... .................. .......... ..............................................................
#> See problems(...) for more details.

###使用problem查看问题
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… '/Users/runner/work/_temp/Library/readr/…
#> 2  1002 y     1/0/T/F/TRUE/F… 2018-05… '/Users/runner/work/_temp/Library/readr/…
#> 3  1003 y     1/0/T/F/TRUE/F… 2015-09… '/Users/runner/work/_temp/Library/readr/…
#> 4  1004 y     1/0/T/F/TRUE/F… 2012-11… '/Users/runner/work/_temp/Library/readr/…
#> 5  1005 y     1/0/T/F/TRUE/F… 2020-01… '/Users/runner/work/_temp/Library/readr/…
#> 6  1006 y     1/0/T/F/TRUE/F… 2016-04… '/Users/runner/work/_temp/Library/readr/…
#> # … with 994 more rows

这个challenge数据集的第二列前1000行是NA,所以readr认为它是逻辑值,这个时候我们可以指定列的类型(col_types)或者增多猜所依据的行数(guess_max):

代码语言:javascript
复制
challenge <- read_csv(
  readr_example("challenge.csv"), 
  col_types = cols(
    x = col_double(),
    y = col_date()
  )
)

challenge2 <- read_csv(readr_example("challenge.csv"), guess_max = 1001)
#> 
#> ── Column specification ────────────────────────────────────────────────────────
#> cols(
#>   x = col_double(),
#>   y = col_date(format = "")
#> )

也可以将数据全部以字符形式读入,然后再使用type_convert进行转化(这个时候如果没有指定列的类型,是根据所有的行进行推测的):

代码语言:javascript
复制
challenge2 <- read_csv(readr_example("challenge.csv"), 
  col_types = cols(.default = col_character())
)
type_convert(challenge3) -> a
# Parsed with column specification:
#   cols(
#     x = col_double(),
#     y = col_date(format = "")
#   )

数据输出

readr使用write_*函数来输出文件

当使用write_csv或者write_tsv等函数时,指定的列的类型会丢失(再次读入时还需要指定):

代码语言:javascript
复制
write_csv(challenge, "challenge-2.csv")
read_csv("challenge-2.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 '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   
# 7  2489 NA   
# 8  1449 NA   
# 9  3665 NA   
# 10  3863 NA   
# # ... with 1,990 more rows

把文件保存为rds或者feather文件就不会出现这种问题:

代码语言:javascript
复制
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        
#> # … with 1,994 more rows

##feather可以被python使用
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>
#> # ... with 1,994 more rows
代码语言:javascript
复制
##python input
import feather
path = 'data/co2.feather'
df_co2_feather = feather.read_dataframe(path)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • rio package
    • import
    • export
    • convert
  • readr package
    • 向量解析
    • 列类型判断
    • 数据解析
    • 可能存在的问题
    • 数据输出
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档