第八章-使用readr进行数据的导入

readr读取数据
parse_*函数簇——解析数据(单个向量)
——解析文件

提要:

1.readr函数中掌握read.csv逗号分隔,read.delim任意分隔


2.readr函数中一些参数

  • skip = n 跳过
  • comment = “#” 忽略#开头
  • col_names = FALSE 第一行不是列名
  • col_names=c(“x”,“y”,“z”) 重新设置列名
  • na="." 点最为na读取
  • readr example()函数的用法,它可以找到包含在R包中的文件的路径。

3.读取数据之前,要对数据解析,一种数据有多中表达形式

(1) 数值 parse_number忽略字符串中任何其他非数字符号

decimal_mark = ","
grouping_mark="."忽略分组符号

(2)字符串


1.准备工作
library(tidyverse)
使用readr包将平面文件加载到R中

函数

描述

read_csv()

读取逗号分隔文件

read_csv2()

读取分号分隔文件

read_tsv()

读取制表符分隔文件

read_delim()

可以读取使用任意分隔符的文件

read_fuf()

读取固定宽度的文件。read_table()是他的变体。

read_log()

读取Apache风格的日志文件。

read_lines()

按行读入字符向量

read_file()

读入一个长度为1的字符向量

注意:

  1. 使用readr中函数来读取数据,比R基础包中的读取函数效率更高
    例如readr中函数比R基础模块函数read.csv()速度约快10倍
    data.table::fread()读取比readr更快
  2. readr中函数可以生成tibble,并且不会将字符向量转换为因子,不使用行名称,也不会随意改动列名称。
  3. readr中函数易于重复使用

2.read_csv()的参数

  1. 可以使用skip = n 来跳过前n 行;
  2. 用comment = “#” 来丢弃所有以 # 开头的行
  3. 默认第一行为列名,取消默认用col_names = FALSE,定义列名向col_names传递一个字符向量,用做列名称
  4. 将某些值读取为缺失值,na="."
  5. "\n"是非常便捷的快捷方式,用于添加新行

例子

read_csv("The first line of metadata
The second line of metadata
x,y,z
1,2,3", skip = 2)

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("a,b,c\n1,2,3\n4,5,6")

read_csv("1,2,3\n4,5,6",col_names=c("x","y","z"))

练习

(1) 如果一个文件中的域是由“|”分隔的,那么应该使用哪个函数来读取这个文件?

read_delim(file, delim = "|")

(2) 除了file、skip 和comment,还有哪些参数是read_csv() 和read_tsv() 这两个函数共有的?

union(names(formals(read_csv)), names(formals(read_tsv)))

(3) read_fwf() 函数中最重要的参数是什么?

read_fwf()读取“固定宽度格式” 的最重要的参数是col_positions告诉函数数据列开始和结束的位置。

(4) 有时CSV 文件中的字符串会包含逗号。为了防止引发问题,需要用引号(如" 或’)将逗号围起来。按照惯例,read_csv() 默认引号为",如果想要改变默认值,就要转而使用read_delim() 函数。要想将以下文本读入一个数据框,需要设定哪些参数?

"x,y\n1,'a,b'"
x <- "x,y\n1,'a,b'"
read_csv(x, quote = "'")

3.解析向量

parse_*() 函数接受一个字符型向量,并返回一个特定向量,如逻辑、整数或日期,改变了数据类型。

第一个参数是需要解析的字符向量,na参数设定了哪些字符串应该当作缺失值来处理:

parse_integer(c("1","231",".","456"),na=".")
#>[1]1231NA456
parse_logical()#解析逻辑值
parse_integer()#解析整数
parse_double()#严格的数值型
parse_number()#灵活的数值型
parse_character()
parse_factor()
parse_datetime()#日期型和SQL一样
parse_date()
parse_time()

输入字符串,返回定义的类型

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

解析失败可用problems(x)获取失败信息集合,可用dplyr处理缺失值。

3.1.数值

生活中同一个数值有多个表达形式

readr使用“地区”这个概念,可以按照不同地区设置解析选项的一个对象

默认小数点是"."有的国家用逗号作为小数点,需要用参数
locale = locale(decimal_mark = “,”)设置。

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

数字前后有货币、百分比、无关文本等等,可用parse_number提取,也可以提取嵌在文本中的数值

parse_number()解决了第二个问题:它可以忽略数值前后的非数值型字符。

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

组合使用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
3.2字符串

生活中同一个字符串有多个表达形式
parse_character()
用charToRaw()获得一个字符串的底层编码。

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

ASCII可以非常好地表示英文字符9

readr全面支持UTF-8:当读取数据时,它假设数据是UTF-8编码的,并总是使用UTF-8编码写入数据
处理数据文本乱码,可以用

locale = locale(encoding = "")
猜测编码方式:guess_encoding(charToRaw())

x1="\xceҰ�\xc4\xe3"
parse_character(x1,locale=locale(encoding="chr"))
guess_encoding(charToRaw(x1))
3.3因子

R使用因子表示取值范围是已知集合的分类变量。
如果parse_factor函数的levels参数被赋予一个已知向量,
那么只要存在向量中没有的值,就会生成一条警告:
fruit <- c(“apple”, “banana”,“bananana”)
parse_factor(c(“apple”, “banana”, “bananana”), levels = fruit)
#[1] apple banana bananana
#Levels: apple banana bananana

3.4日期

注意:通常是这样

parse_date("01/02/15","%m/%d/%y")
#>[1]"2015-01-02"
parse_date("01/02/15","%d/%m/%y")
#>[1]"2015-02-01"
parse_date("01/02/15","%y/%m/%d")
#>[1]"2001-02-15"

1.日期时间型
parse_datetime期待的是符合ISO8601标准的日期时间。
ISO8601是一种国际标准,其中日期的各个部分按从大到小的顺序排列,即年、月、日、小时、分钟、秒:

parse_datetime("2010-10-01T2010")
#>[1]"2010-10-0120:10:00 UTC"
如果时间被省略了,那么它就会被设置为午夜
parse_datetime("20101010")
#>[1]"2010-10-10 UTC"

2.日期型
parse_date期待的是四位数的年份、一个-或/、月、一个-或/,然后是日:

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

3.时间型
parse_time期待的是小时、:、分钟、可选的:和秒,以及一个可选的a.m./p.m.标识符:

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

4.解析文件

先是用guess_parser() 猜测数据类型
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"

readr首先读取1000行,然后开始启发式猜测,猜测文件中的数据进行自动解析
可以猜测:逻辑值、整数、双精度浮点数、数值、时间、日期、日期时间等
如果都不匹配,就默认为这一列为字符串

但是按照上面这样,会出现一些问题

readr中包含了一份非常有挑战性的CSV文件,该文件可以说明以上两个问题。
readr example()函数的用法,它可以找到包含在R包中的文件的路径。

challenge <- read_csv(readr_example(“challenge.csv”))

自动根据前1000行,猜测x列为整数,y列为数值。
在1000列之后都是failure了,因为有拖尾字符。
实际上1000行后x列为双精度浮点数,y列为日期
。因此我们在读取命令中加入col_types,指定x列为col_double(),
y列为col_date()

可以更改列的类型

challenge<-read_csv(
  readr_example("challenge. csv"), 
  coL_types=cols(
    x=coL_integer(), 
    y=col_character()
))
接着修改x列的类型:
challenge<-read_csv(
  readr_example("challenge. csv"), 
    coL_types=cols(
      x=coL_double(),
      y=col_character()
))
接着修改y列的类型:                                                                                                                    
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)



另外将所有列作为字符向量读入:
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 × 2
#> x y
#> <chr> <chr>
#> 1 1 1.21
#> 2 2 2.32
#> 3 3 4.56
# 注意列类型
type_convert(df)
#> Parsed with column specification:
#> cols(
#> x = col_integer(),
#> y = col_double()
#> )
#> # A tibble: 3 × 2
#> x y
#> <int> <dbl>
#> 1 1 1.21
#> 2 2 2.32
#> 3 3 4.56

5.保存、导出

readr还提供了两个非常有用的函数,用于将数据写回到磁盘:

write_csv()
write_tsv()

如果想要将CSV文件导为Excel文件,可以使用write_excel_csv()函数

write_csv导出后,列的数据类型会丢失。
替代方式:
(1)write_rds(),read_rds-R自定义的二进制格式RDS格式

write_rds(challenge,"challenge.rds")
read_rds("challenge.rds")

(2)feather包中的write_feather和read_feather-在多种编程语言间通用。

library(feather)
write_feather(challenge,"challenge.feather")
read_feather("challenge.feather")

feather要比RDS速度更快,而且可以在R之外使用。

6.其他类型的数据

• haven 可以读取SPSS、Stata 和SAS 文件;
• readxl 可以读取Excel 文件(.xls 和.xlsx 均可);
library(readxl)
d <- read_excel(“d.xlsx”)
View(d)
• 配合专用的数据库后端程序(如RMySQL、RSQLite、RPostgreSQL等),
DBI可以对相应数据库进行SQL查询,并返回一个数据框。