《R数据科学》学习笔记|Note7:使用readr进行数据导入

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 《R数据科学》学习笔记|Note7:使用readr进行数据导入

7.1 简介


本章将学习如何将纯文本格式的矩形文件读入 R。虽然本章内容只是数据导入的冰山一角,但其中的原则完全适用于其他类型的数据。本章末尾将提供 一些有用的 R 包,以处理其他类型的数据。


7.2 入门


readr 的多数函数用于将平面文件转换为数据框。


• read_csv() 读取逗号分隔文件、read_csv2() 读取分号分隔文件、read_tsv() 读取制表符分隔文件、read_delim() 可以读取使用任意分隔符的文件。


• read_fwf() 读取固定宽度的文件。既可以使用 fwf_widths() 函数按照宽度来设定域,也可以使用 fwf_positions() 函数按照位置来设定域。read_table() 读取固定宽度文件的一种常用变体,其中使用空白字符来分隔各列。


• read_log() 读取 Apache 风格的日志文件。(但需要检查是否安装了 webreadr 包,(https:// github.com/Ironholds/webreadr),因为该包位于 read_log() 函数的开头,还可以提供很多有用的工具。)


read_csv() 函数的第一个参数是最重要的,该参数是要读取的文件的路径:

heights <- read_csv("data/heights.csv")`

还可以提供一个行内 CSV 文件。

read_csv("a,b,c
1,2,3
4,5,6")
> read_csv("a,b,c
+ 1,2,3
+ 4,5,6")
# A tibble: 2 x 3
      a     b     c
  <dbl> <dbl> <dbl>
1     1     2     3
2     4     5     6

以上两种情况下,read_csv() 函数都使用数据的第一行作为列名称。


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

read_csv("The first line of metadata
 The second line of metadata
 x,y,z
 1,2,3", skip = 2)
> read_csv("The first line of metadata
+  The second line of metadata
+  x,y,z
+  1,2,3", skip = 2)
# A tibble: 1 x 3
      x     y     z
  <dbl> <dbl> <dbl>
1     1     2     3
read_csv("# A comment I want to skip
 x,y,z
 1,2,3", comment = "#")
> read_csv("# A comment I want to skip
+  x,y,z
+  1,2,3", comment = "#")
# A tibble: 1 x 3
      x     y     z
  <dbl> <dbl> <dbl>
1     1     2     3

• 数据没有列名称。可以使用 col_names = FALSE 来通知 read_csv() 不要将第一行作为列标题,而是将各列依次标注为 X1 至 Xn:

read_csv("1,2,3\n4,5,6", col_names = FALSE) #\n 换行
> read_csv("1,2,3\n4,5,6", col_names = FALSE)
# A tibble: 2 x 3
     X1    X2    X3
  <dbl> <dbl> <dbl>
1     1     2     3
2     4     5     6

或者你也可以向 col_names 传递一个字符向量,以用作列名称:

read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))
> read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))
# A tibble: 2 x 3
      x     y     z
  <dbl> <dbl> <dbl>
1     1     2     3
2     4     5     6

另一个通常需要修改的选项是 na。它设定使用哪个值(或哪些值)来表示文件中的缺失值:

read_csv("a,b,c\n1,2,.", na = ".")
> read_csv("a,b,c\n1,2,.", na = ".")
# A tibble: 1 x 3
      a     b c    
  <dbl> <dbl> <lgl>
1     1     2 NA

7.2.1 与R基础包进行比较


readr 相较于R基础包中具有同样功能的函数,如read.csv()有以下优点


• 一般来说,比基础模块中的函数速度更快(约快10倍)。


• 可以生成 tibble,并且不会将字符向量转换为因子,不使用行名称,也不会随意改动列名称。


• 更易于重复使用。R 基础包中的函数会继承操作系统的功能,并依赖环境变量,因 此,可以在你的计算机上正常运行的代码在导入他人计算机时,不一定能正常运行。


7.3 解析向量


在详细介绍 readr 如何从磁盘读取文件前,我们需要先讨论一下 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"

和 tidyverse 中的所有函数一样,parse_*() 函数族的用法是一致的。第一个参数是需要解析的字符向量,na 参数设定了哪些字符串应该当作缺失值来处理:

parse_integer(c("1", "231", ".", "456"), na = ".")
> [1] 1 231 NA 456

如果解析失败,你会收到一条警告:

x <- parse_integer(c("123", "345", "abc", "123.45"))
> x <- parse_integer(c("123", "345", "abc", "123.45"))
Warning: 2 parsing failures.
row col               expected actual
  3  -- an integer             abc   
  4  -- no trailing characters 123.45
#解析失败的值在输出中是以缺失值的形式存在的
x
> x
[1] 123 345  NA  NA
attr(,"problems")
# A tibble: 2 x 4
    row   col expected               actual
  <int> <int> <chr>                  <chr> 
1     3    NA an integer             abc
2     4    NA no trailing characters 123.45


在解析函数的使用方面,最重要的是要知道有哪些解析函数,以及每种解析函数用来处理 哪种类型的输入。具体来说,重要的解析函数有 8 种。


• parse_logical() 和 parse_integer() 函数分别解析逻辑值和整数。


• parse_double() 是严格的数值型解析函数,parse_number() 则是灵活的数值型解析函数。


• parse_character() 字符编码。


• parse_factor() 函数可以创建因子,R 使用这种数据结构来表示分类变量,该变量具有固定数目的已知值。


• parse_datetime()、parse_date() 和 parse_time() 函数可以解析不同类型的日期和时间。


7.3.1 数值


解析数值似乎是非常直截了当的,但以下 3 个问题增加了数值解析的复杂性。


• 世界各地的人们书写数值的方式不尽相同。例如,有些国家使用 . 来分隔实数中的整数和小数部分,而有些国家则使用 ,。


• 数值周围经常有表示某种意义的其他字符,如 $1000 或 10%。


• 数值经常包含“分组”,以便更易读,如 1 000 000,而且世界各地用来分组的字符也不 尽相同。


为了解决第一个问题,readr 使用了“地区”这一概念,这是可以按照不同地区设置解析选项的一个对象。在解析数值时,最重要的选项就是用来表示小数点的字符。通过创建一个新的地区对象并设定 decimal_mark 参数,可以覆盖 . 的默认值:

parse_double("1.23")
> [1] 1.23
parse_double("1,23", locale = locale(decimal_mark = ","))
> [1] 1.23

readr 的默认地区是 US-centric,因为 R 是以美国为中心的。


parse_number() 解决了第二个问题:它可以忽略数值前后的非数值型字符。这个函数特别适合处理货币和百分比,也可以提取嵌在文本中的数值:

parse_number("$100")
> [1] 100
parse_number("20%")
> [1] 20
parse_number("It cost $123.45")
> [1] 123

组合使用 parse_number() 和地区设置可以解决最后一个问题,因为 parse_number() 可以忽略“分组符号”:

# 适用于美国
parse_number("$123,456,789")
> [1] 1.23e+08
# 适用于多数欧洲国家
parse_number(
 "123.456.789",
 locale = locale(grouping_mark = ".")
)
> [1] 1.23e+08
# 适用于瑞士
parse_number(
 "123'456'789",
 locale = locale(grouping_mark = "'")
)
> [1] 1.23e+08

7.3.2 字符串


R 中,我们可以使用 charToRaw() 函数获得一个字符串的底层表示:

charToRaw("Hadley")
> [1] 48 61 64 6c 65 79

每个十六进制数表示信息的一个字节:48 是 H、61 是 a 等。从十六进制数到字符的这种映射称为编码,这个示例中的编码方式称为 ASCII。ASCII 可以非常好地表示英文字符,因为它就是美国信息交换标准代码(American Standard Code for Information Interchange)的缩写。


readr 全面支持 UTF-8:当读取数据时,它假设数据是 UTF-8 编码的,并总是使用 UTF-8 编码写入数据。但对于从不支持 UTF-8 的那些旧系统中产生的数据,你的字符串打印出来就是一堆乱码。例如:

x1 <- "El Ni\xf1o was particularly bad this year"
x2 <- "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"

要想解决这个问题,需要在 parse_character() 函数中设定编码方式:

parse_character(x1, locale = locale(encoding = "Latin1"))
> [1] "El Niño was particularly bad this year"
parse_character(x2, locale = locale(encoding = "Shift-JIS"))
> [1] "こんにちは"

readr 提供了 guess_encoding() 函数来帮助你找出编码方式

guess_encoding(charToRaw(x1))
> encoding confidence
> 1 ISO-8859-1 0.46
> 2 ISO-8859-9 0.23
guess_encoding(charToRaw(x2))
> encoding confidence
> 1 KOI8-R 0.42

guess_encoding() 的第一个参数可以是一个文件路径,也可以是一个原始向量(适用于字符串已经在R中的情况)。


7.3.3 因子


R 使用因子表示取值范围是已知集合的分类变量。如果 parse_factor() 函数的 levels 参数被赋予一个已知向量,那么只要存在向量中没有的值,就会生成一条警告:

fruit <- c("apple", "banana")
parse_factor(c("apple", "banana", "bananana"), levels = fruit)
> 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

7.4 解析文件


现在你已经学会了如何解析单个向量,接下来我们就回到本章的最初目标,研究 readr 是如何解析文件的。你将在本节中学到以下两种新技能。


• readr 如何自动猜出文件每列的数据类型。


• 如何修改默认设置。


7.4.1 策略


readr 使用一种启发式过程来确定每列的类型:先读取文件的前 1000 行,然后使用(相对保守的)某种启发式算法确定每列的类型。可以使用字符向量模拟这个过程,先使用 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] "integer"
guess_parser(c("12,352,561"))
> [1] "number"
str(parse_guess("2010-10-10"))
> Date[1:1], format: "2010-10-10"

7.4.2 问题


这个部分内容都是原理,对实际使用没有太大影响,我这里就跳过了。


7.5 写入文件


readr 还提供了两个非常有用的函数,用于将数据写回到磁盘:write_csv() 和 write_ tsv()。这两个函数输出的文件能够顺利读取的概率更高,因为:


• 它们总是使用 UTF-8 对字符串进行编码;


• 它们使用 ISO 8601 格式来保存日期和日期时间数据,以便这些数据不论在何种环境下 都更容易解析。 如果想要将 CSV 文件导为 Excel 文件,可以使用 write_excel_csv() 函数,该函数会在文件开头写入一个特殊字符(字节顺序标记),告诉 Excel 这个文件使用的是 UTF-8 编码。 这几个函数中最重要的参数是 x(要保存的数据框)和 path(保存文件的位置)。还可以使 用 na 参数设定如何写入缺失值,如果想要追加到现有的文件,需要设置 append 参数:


write_csv(challenge, "challenge.csv")

注意,当保存为 CSV 文件时,类型信息就丢失了。


这使得 CSV 文件在暂存临时结果时有些不可靠——每次加载时都要重建列类型。以下是两种替代方式。


• write_rds() 和 read_rds() 函数是对基础函数 readRDS() 和 saveRDS() 的统一包装。前者可以将数据保存为 R 自定义的二进制格式,称为 RDS 格式:

write_rds(challenge, "challenge.rds")
read_rds("challenge.rds")
> write_rds(challenge, "challenge.rds")
> read_rds("challenge.rds")
# 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


• feather包实现了一种快速二进制格式,可以在多个编程语言间共享:

install.packages("feather")
library(feather)
write_feather(challenge, "challenge.feather")
read_feather("challenge.feather")
> read_feather("challenge.feather")
# 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

feather 要比 RDS 速度更快,而且可以在 R 之外使用。RDS 支持列表列,feather 目前还不行。


7.6 其他类型的数据

要想将其他类型的数据导入 R 中,可以从下列的 tidyverse 包开始。


对矩形数据来说:


• haven 可以读取 SPSS、Stata 和 SAS 文件;


• readxl 可以读取 Excel 文件(.xls 和 .xlsx 均可);


• 配合专用的数据库后端程序(如 RMySQL、RSQLite、RPostgreSQL 等),DBI 可以对相 应数据库进行 SQL 查询,并返回一个数据框。


对于层次数据,可以使用 jsonlite读取 JSON 串,使用 xml2 读取 XML 文件。对于其他的文件类型,可以学习一下 R 数据导入 / 导出手册([https://cran.r-project.org/doc/ manuals/r-release/R-data.html](https://cran.r-project.org/doc/ manuals/r-release/R-data.html))。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
机器学习/深度学习 算法 数据挖掘
数据分析入门系列教程-K-Means实战
数据分析入门系列教程-K-Means实战
|
6月前
|
存储 算法 数据可视化
数据分析入门系列教程-K-Means原理
数据分析入门系列教程-K-Means原理
|
SQL 数据挖掘 定位技术
《R数据科学》学习笔记|Note8:使用dplyr处理关系数据
《R数据科学》学习笔记|Note8:使用dplyr处理关系数据
194 0
《R数据科学》学习笔记|Note8:使用dplyr处理关系数据
|
大数据 数据处理
《R数据科学》学习笔记|Note6:使用tibble实现简单数据框
本系列为《R数据科学》(R for Data Science)的学习笔记。相较于其他R语言教程来说,本书一个很大的优势就是直接从实用的R包出发,来熟悉R及数据科学。更新过程中,读者朋友如发现错误,欢迎指正。如果有疑问,也可以在评论区留言或后台私信。希望各位读者朋友能学有所得!
548 0
《R数据科学》学习笔记|Note6:使用tibble实现简单数据框
《R数据科学》学习笔记|Note12:使用magrittr进行管道操作
《R数据科学》学习笔记|Note12:使用magrittr进行管道操作
168 0
《R数据科学》学习笔记|Note12:使用magrittr进行管道操作
《R数据科学》学习笔记|Note5:使用dplyr进行数据转换(下)
本系列为《R数据科学》(R for Data Science)的学习笔记。相较于其他R语言教程来说,本书一个很大的优势就是直接从实用的R包出发,来熟悉R及数据科学。更新过程中,读者朋友如发现错误,欢迎指正。如果有疑问,也可以在评论区留言或后台私信。希望各位读者朋友能学有所得!
166 0
《R数据科学》学习笔记|Note5:使用dplyr进行数据转换(下)
|
资源调度 索引
《R数据科学》学习笔记|Note16:使用purrr实现迭代(下)
《R数据科学》学习笔记|Note16:使用purrr实现迭代(下)
124 0
《R数据科学》学习笔记|Note16:使用purrr实现迭代(下)
《R数据科学》学习笔记|Note9:使用stringr处理字符串(上)
本周内容较多且杂,故分成上下两篇。正则表达式是从左到右来匹配一个字符串的。“Regular Expression”这个词太长了,我们通常使用它的缩写“regex”或者“regexp”。 正则表达式可以被用来替换字符串中的文本、验证表单、基于模式匹配从一个字符串中提取字符串等等。
173 0
《R数据科学》学习笔记|Note9:使用stringr处理字符串(上)
《R数据科学》学习笔记|Note10:使用stringr处理字符串(下)
《R数据科学》学习笔记|Note10:使用stringr处理字符串(下)
231 0
《R数据科学》学习笔记|Note10:使用stringr处理字符串(下)
|
数据可视化
《R数据科学》学习笔记|Note14:向量
《R数据科学》学习笔记|Note14:向量
273 0
《R数据科学》学习笔记|Note14:向量