1 readr与R基础包进行比较
- 比基础模块中函数速度更快(约快10倍)
- 生成tibble,并且不会把字符向量转换成因子,不使用行名称,也不会随意改动列名称
- 更易于重复使用
2 R基础包
read.table()
read.table(file, header = FALSE, sep = "", quote = "\"'", dec = ".", numerals = c("allow.loss", "warn.loss", "no.loss"), row.names, col.names, as.is = !stringsAsFactors, na.strings = "NA", colClasses = NA, nrows = -1, skip = 0, check.names = TRUE, fill = !blank.lines.skip, strip.white = FALSE, blank.lines.skip = TRUE, comment.char = "#", allowEscapes = FALSE, flush = FALSE, stringsAsFactors = default.stringsAsFactors(), fileEncoding = "", encoding = "unknown", text, skipNul = FALSE)
read.csv()
读取逗号分隔文件
read.csv(file, header = TRUE, sep = ",", quote = "\"", dec = ".", fill = TRUE, comment.char = "", ...)
read.csv2()
读取分号分隔文件
read.csv2(file, header = TRUE, sep = ";", quote = "\"", dec = ",", fill = TRUE, comment.char = "", ...)
read.delim()
读取制表符分隔文件
read.delim(file, header = TRUE, sep = "\t", quote = "\"", dec = ".", fill = TRUE, comment.char = "", ...)
read.delim2()
读取制表符分隔文件
read.delim2(file, header = TRUE, sep = "\t", quote = "\"", dec = ",", fill = TRUE, comment.char = "", ...)
参数
参数 | 含义 |
---|---|
file | 文件名(包在“”内,或者使用一个字符型变量),可能需要全程路径(注意即使是在windows下,符号\也不允许包含在内,必须使用/替换),或者一个URL链接(http://...)(用URL对文件远程访问) |
header | 一个逻辑值(FALSE or TRUE)用来反映这个文件的第一行是否包含变量名 |
sep | 文件中的字段分隔符,例如对用制表符分隔的文件使用sep=“\t” |
quote | 指定用于包围字符型数据的字符 |
dec | 用来表示小数点的字符 |
row.names | 保存行名的向量,或文件中一个变量的序号或名字,缺省时行号取为1,2,3... |
col.names | 指定列名的字符向量(缺省值是:V1,V2,V3...) |
as.is | 控制是否将字符型变量转化为因子型变量(如果值为FALSE),或者仍将其保留为字符型(TRUE)。as.is可以是逻辑型,数值型或字符型向,用来判断变量是否被保留为字符 |
na.strings | 代表缺失数据的值(转化NA) |
colClasses | 指定各列的数据类型的一个字符型变量 |
nrows | 可以读取的最大行数(忽略负值) |
skip | 在读取数据前跳过的行数 |
check.names | 如果为TRUE,则检查变量名是否存在R中有效 |
fill | 如果为TRUE且非所有的行中变量数目相同,则用空白填补 |
strip.white | 在sep已指定的情况下,如果为TRUE,则删除字符型变量前后多余的空格 |
blank.lines.skip | 如果为TRUE,忽略空白行 |
comment.char | 一个字符用来在数据文件中写注释,以这个字符开头的行将被忽略(要禁用这个参数,可使用comment.char="") |
3 readr包
readr是tidyverse的核心包之一,readr 的多数函数用于将平面文件转换为数据框
read_csv()
读取逗号分割文件
read_csv(file, col_names = TRUE, col_types = NULL, locale = default_locale(), na = c("", "NA"), quoted_na = TRUE, quote = "\"", comment = "", trim_ws = TRUE, skip = 0, n_max = Inf, guess_max = min(1000, n_max), progress = show_progress(), skip_empty_rows = TRUE)
read_csv2()
读取分号分割文件
read_csv2(file, col_names = TRUE, col_types = NULL, locale = default_locale(), na = c("", "NA"), quoted_na = TRUE, quote = "\"", comment = "", trim_ws = TRUE, skip = 0, n_max = Inf, guess_max = min(1000, n_max), progress = show_progress(), skip_empty_rows = TRUE)
read_tsv()
读取制表符分割文件
read_tsv(file, col_names = TRUE, col_types = NULL, locale = default_locale(), na = c("", "NA"), quoted_na = TRUE, quote = "\"", comment = "", trim_ws = TRUE, skip = 0, n_max = Inf, guess_max = min(1000, n_max), progress = show_progress(), skip_empty_rows = TRUE)
read_delim()
读取任意分隔符分割的文件
read_delim(file, delim, quote = "\"", escape_backslash = FALSE, escape_double = TRUE, col_names = TRUE, col_types = NULL, locale = default_locale(), na = c("", "NA"), quoted_na = TRUE, comment = "", trim_ws = FALSE, skip = 0, n_max = Inf, guess_max = min(1000, n_max), progress = show_progress(), skip_empty_rows = TRUE)
read_fwf()
读取固定宽度文件;既可以使用fwf_widths()函数按照宽度来设定域,也可以使用fwf_positions()函数按照位置来设定域。read_table()读取固定宽度文件的一种常用变体,其中使用空白字符来分隔各列
read_log()读取Apache风格的日志文件
3.1 参数:
参数 | 含义 |
---|---|
file | 文件名(包在“”内,或者使用一个字符型变量),可能需要全程路径(注意即使是在windows下,符号\也不允许包含在内,必须使用/替换),或者一个URL链接(http://...)(用URL对文件远程访问) |
header | 一个逻辑值(FALSE or TRUE)用来反映这个文件的第一行是否包含变量名 |
sep | 文件中的字段分隔符,例如对用制表符分隔的文件使用sep=“\t” |
quote | 指定用于包围字符型数据的字符 |
dec | 用来表示小数点的字符 |
fill | 如果为TRUE且非所有的行中变量数目相同,则用空白填补 |
comment.char | 一个字符用来在数据文件中写注释,以这个字符开头的行将被忽略(要禁用这个参数,可使用comment.char="") |
3.2 read_csv()函数
# 加载readr
library(tidyverse)
# read_csv()使用数据的第一行作为列名称
read_csv("a,b,c
1,2,3
4,5,6")
# # A tibble: 2 x 3
# a b c
#
# 1 1 2 3
# 2 4 5 6
# skip=n用来跳过数据的前n行,因为第一列是默认的列名称,所以skip=1,实际上会跳过2列
read_csv("a,b,c
1,2,3
4,5,6",skip=1)
# # A tibble: 1 x 3
# `1` `2` `3`
#
# 1 4 5 6
# 使用comment=“#”,可以丢弃所有以“#”开头的行
read_csv("# it is a test
a,b,c
1,2,3
4,5,6",comment="#")
# # A tibble: 2 x 3
# a b c
#
# 1 1 2 3
# 2 4 5 6
# 第一行仅有一条数据,所以仅得到一列数据
read_csv("# it is a test
a,b,c
1,2,3
4,5,6")
# # A tibble: 3 x 1
# `# it is a test`
#
# 1 a
# 2 1
# 3 4
# 用逗号进行分割,读取得到完整的数据
read_csv("# it is a test,,
a,b,c
1,2,3
4,5,6")
# # A tibble: 3 x 3
# `# it is a test` X2 X3
#
# 1 a b c
# 2 1 2 3
# 3 4 5 6
# col_names=FALSE,用于通知read_csv()取消第一行作为列名称
read_csv("a,b,c
1,2,3
4,5,6",col_names=F)
# # A tibble: 3 x 3
# X1 X2 X3
#
# 1 a b c
# 2 1 2 3
# 3 4 5 6
# 使用换行符“\n”添加新行
read_csv("a,b,c\n1,2,3\n4,5,6",col_names=F)
# # A tibble: 3 x 3
# X1 X2 X3
#
# 1 a b c
# 2 1 2 3
# 3 4 5 6
# 通过向量赋值指定col_names
read_csv("a,b,c
1,2,3
4,5,6",col_names=c("A","B","C"))
# # A tibble: 3 x 3
# A B C
#
# 1 a b c
# 2 1 2 3
# 3 4 5 6
# 设定na=“ ”,用于设定使用哪个用来表示文件的缺失值
read_csv("a,b,c
1,.,3
4,5,.",na=".")
# # A tibble: 2 x 3
# a b c
#
# 1 1 NA 3
# 2 4 5 NA
# 通过向量设定na=“ ”,用于设定使用哪些值来表示文件的缺失值
read_csv("a,b,c
1,.,3
4,5,/",na=c(".","/"))
# # A tibble: 2 x 3
# a b c
#
# 1 1 NA 3
# 2 4 5 NA
4. 向量解析 parse_*()
4.1 重要的解析函数有8 种
-
parse_logical()
和parse_integer()
函数分别解析逻辑值和整数。因为这两个解析函数
基本不会出现问题,所以我们不再进行更多介绍。 -
parse_double()
是严格的数值型解析函数,parse_number()
则是灵活的数值型解析函数。
这两个函数要比你预想的更复杂,因为世界各地书写数值的方式不尽相同。 -
parse_character()
函数似乎太过简单,甚至没必要存在。但一个棘手的问题使得这个
函数变得非常重要:字符编码。 -
parse_factor()
函数可以创建因子,R 使用这种数据结构来表示分类变量,该变量具有
固定数目的已知值。 -
parse_datetime()
、parse_date()
和parse_time()
函数可以解析不同类型的日期和时间。
它们是最复杂的,因为有太多不同的日期书写形式。
4.2 举例
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"
# 如解析失败,会收到Warning信息
parse_integer(c("1", "2", "abc","3"))
# Warning: 1 parsing failure.
# row col expected actual
# 3 -- an integer abc
# na参数可以设定哪些字符串当做缺失值进行处理
parse_integer(c("1", "2", "abc","3"),na="abc")
# [1] 1 2 NA 3
# 解析失败的值在输出中是以缺失值的形式存在
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 .45
x
# [1] 123 345 NA NA
# attr(,"problems")
# # A tibble: 2 x 4
# row col expected actual
#
# 1 3 NA an integer abc
# 2 4 NA no trailing characters .45
# Warning message:
# `...` is not empty.
# 如果解析失败的值很多,那么就应该使用problems() 函数来获取完整的失败信息集合。这
个函数会返回一个tibble,你可以使用dplyr 包来进行处理
problems(x)
# # A tibble: 2 x 4
# row col expected actual
#
# 1 3 NA an integer abc
# 2 4 NA no trailing characters .45
4.3 解析数值 parse_datetime()
、parse_date()
和parse_time()
解析数值似乎是非常直截了当的,但以下3 个问题增加了数值解析的复杂性。
• 世界各地的人们书写数值的方式不尽相同。例如,有些国家使用. 来分隔实数中的整数
和小数部分,而有些国家则使用,。
• 数值周围经常有表示某种意义的其他字符,如$1000 或10%。
• 数值经常包含“分组”,以便更易读,如1 000 000,而且世界各地用来分组的字符也不
尽相同。
# 在解析数值时,最重要的选项就是用来表示小数点的字符。通过创建一个新的地区对象并设定decimal_mark 参数,可以覆盖"." 的默认值
parse_double("1.23")
# [1] 1.23
# decimal_mark,十进制标记
parse_double("1,23", locale = locale(decimal_mark = ","))
# [1] 1.23
# decimal_mark只能在点"."和逗号","里面选择
parse_double("1;23", locale = locale(decimal_mark = ";"))
# Error in locale(decimal_mark = ";") :
# decimal_mark %in% c(".", ",") is not TRUE
# 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忽略分组符号
parse_number("$123,456,789")
# [1] 123456789
# 适用于多数欧洲国家
# locale()指定分组符号
parse_number(
"123.456.789",
locale = locale(grouping_mark = ".")
)
# [1] 123456789
locale()
函数
locale(date_names = "en", date_format = "%AD", time_format = "%AT", decimal_mark = ".", grouping_mark = ",", tz = "UTC", encoding = "UTF-8", asciify = FALSE)
4.4 解析字符串 parse_character()
# charToRaw(x),将字符串转换为十六进制数,从十六进制数到字符的这种映射称为编码,这个示例中的编码方式称为ASCII(American Standard Code for Information Interchange)
charToRaw("Hadley")
# [1] 48 61 64 6c 65 79
# 对于英语之外的其他语言,有多种编码方式。
# Latin1(即ISO-8859-1,用于西欧语言)
# Latin2(即ISO-8859-2,用于东欧语言)是两种常用的编码方式
# UTF-8 可以为现在人类使用的所有字符进行编码,同时还支持很多特殊字符
x1 <- "El Ni\xf1o was particularly bad this year"
x2 <- "\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd"
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] "こんにちは"
# guess_encoding() 函数可以帮助找到编码方式,但也并不是绝对准确
guess_encoding(charToRaw(x1))
# # A tibble: 2 x 2
# encoding confidence
#
# 1 ISO-8859-1 0.46
# 2 ISO-8859-9 0.23
guess_encoding(charToRaw(x2))
# # A tibble: 1 x 2
# encoding confidence
#
# 1 KOI8-R 0.42
# Warning message:
# `...` is not empty.
4.5 因子 parse_factor()
R 使用因子表示取值范围是已知集合的分类变量。如果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
# attr(,"problems")
# # A tibble: 1 x 4
# row col expected actual
#
# 1 3 NA value in level set bananana
# Levels: apple banana
# Warning message:
# `...` is not empty.
4.6 日期、日期时间与时间 parse_datetime()
、parse_date()
和parse_time()
分别根据需要,在下述3 种解析函数之间进行选择
- 日期型数据(从1970-01-01 开始的天数)
- 日期时间型数据(从1970-01-01午夜开始的秒数)
- 时间型数据(从午夜开始的秒数)
# parse_datetime() 期待的是符合ISO 8601 标准的日期时间。ISO 8601 是一种国际标准,其中日期的各个部分按从大到小的顺序排列,即年、月、日、小时、分钟、秒:
parse_datetime("2010-10-01T2010")
# [1] "2010-10-01 20:10:00 UTC"
# 如果时间被省略了,那么它就会被设置为午夜
parse_datetime("20101010")
# [1] "2010-10-10 UTC"
# parse_date() 期待的是四位数的年份、一个- 或/、月、一个- 或/,然后是日:
parse_date("2010-10-01")
# [1] "2010-10-01"
# parse_time() 期待的是小时、:、分钟、可选的: 和秒,以及一个可选的a.m./p.m. 标识符:
library(hms)
parse_time("01:10 am")
# 01:10:00
parse_time("20:10:01")
# 20:10:01
# 如果这些默认设置不适合你的数据,那么你可以提供自己的日期时间格式
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"
# 年
### %Y(4 位数)
### %y(2 位数;00-69 → 2000-2069、70-99 → 1970-1999)
# 月
### %m(2 位数)
### %b(简写名称,如Jan)
### %B(完整名称,如January)
# 日
### %d(1 位或2 位数)
### %e(2 位数)
# 时间
### %H(0-23 小时)
### %I(0-12 小时,必须和%p 一起使用)
### %p(表示a.m./p.m.)
### %M(分钟)
### %S(整数秒)
### %OS(实数秒)
### %Z(时区,America/Chicage 这样的名称)
### %z(与国际标准时间的时差,如+0800)
# 非数值字符
### %.(跳过一个非数值字符)
### %*(跳过所有非数值字符)
5 解析文件
5.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"
这个启发式过程会尝试以下每种数据类型,直至找到匹配的类型。
- 逻辑值
只包括 F、T、FALSE 和 TRUE。 - 整数
只包括数值型字符(以及 -)。 - 双精度浮点数
只包括有效的双精度浮点数(也包括 4.5e-5 这样的数值)。 - 数值
只包括带有分组符号的有效双精度浮点数。 - 时间
与默认的 time_format 匹配的值。 - 日期
与默认的 date_format 匹配的值。 - 日期时间
符合 ISO 8601 标准的任何日期。
如果以上类型均不匹配,那么这一列就还是一个字符串向量
5.2 问题
这些默认设置对更大的文件并不是一直有效的。以下是两个主要问题。
- 前 1000 行可能是一种特殊情况,readr 猜测出的类型不足以代表整个文件。例如,一列双精度数值的前 1000 行可能都是整数。
- 列中可能含有大量缺失值。如果前 1000 行中都是 NA,那么 readr 会猜测这是一个字符向量,但你其实想将这一列解析为更具体的值。
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/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 1002 y 1/0/T/F/TRUE/FALSE 2018-05-18 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 1003 y 1/0/T/F/TRUE/FALSE 2015-09-05 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 1004 y 1/0/T/F/TRUE/FALSE 2012-11-28 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 1005 y 1/0/T/F/TRUE/FALSE 2020-01-13 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# .... ... .................. .......... ...............................................................................
# See problems(...) for more details.
# 以上的输出可以分为两部分:从前 1000 行中猜测出的列类型与前 5 条解析失败记录。我们总是应该使用 "problems()" 函数明确地列出这些失败记录,以便更加深入地探究其中的问题:
problems(challenge)
# # A tibble: 1,000 x 5
# row col expected actual file
#
# 1 1001 y 1/0/T/F/TRUE/FALSE 2015-01-16 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 2 1002 y 1/0/T/F/TRUE/FALSE 2018-05-18 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 3 1003 y 1/0/T/F/TRUE/FALSE 2015-09-05 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 4 1004 y 1/0/T/F/TRUE/FALSE 2012-11-28 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 5 1005 y 1/0/T/F/TRUE/FALSE 2020-01-13 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 6 1006 y 1/0/T/F/TRUE/FALSE 2016-04-17 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 7 1007 y 1/0/T/F/TRUE/FALSE 2011-05-14 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 8 1008 y 1/0/T/F/TRUE/FALSE 2020-07-18 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 9 1009 y 1/0/T/F/TRUE/FALSE 2011-04-30 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# 10 1010 y 1/0/T/F/TRUE/FALSE 2010-05-11 'C:/Users/caoqiansheng/Documents/R/win-library/3.6/readr/extdata/challenge.csv'
# # ... with 990 more rows
# 一列列地处理,直至解决所有问题,是一种良好策略。根据报错信息修改如下
(
challenge <- read_csv(
readr_example("challenge.csv"),
col_types = cols(
x=col_double(),
y=col_character()
)
)
)
# # A tibble: 2,000 x 2
# x y
#
# 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
# 这样就解决了第一个问题,但如果查看最后几行的话,你会发现保存在字符向量中的其实是日期数据:
tail(challenge)
# # A tibble: 6 x 2
# x y
#
# 1 0.805 2019-11-21
# 2 0.164 2018-03-29
# 3 0.472 2014-08-04
# 4 0.718 2015-08-16
# 5 0.270 2020-02-04
# 6 0.608 2019-01-06
# 设定 y 为日期列可以解决这个问题
challenge <- read_csv(
readr_example("challenge.csv"),
col_types = cols(
x=col_double(),
y=col_date()
)
)
tail(challenge)
# # A tibble: 6 x 2
# x y
#
# 1 0.805 2019-11-21
# 2 0.164 2018-03-29
# 3 0.472 2014-08-04
# 4 0.718 2015-08-16
# 5 0.270 2020-02-04
# 6 0.608 2019-01-06
每个 parse_xyz()
函数都有一个对应的 col_xyz()
函数。如果数据已经保存在 R 的字符向量中,那么你可以使用 arse_xyz()
;如果想要告诉readr
如何加载数据,则应该使用 col_xyz()
。
我们强烈建议你总是提供 col_types
参数,从 readr
打印出的输出中可以知道它的值。这可以确保数据导入脚本的一致性,并可以重复使用。如果不提供这个参数,而是依赖猜测的类型,那么当数据发生变化时,readr
会继续读入数据。如果想要严格解析,可以使用stop_for_problems()
函数:当出现任何解析问题时,它会抛出一个错误,并终止脚本。
5.3 其他策略
我们再介绍其他几种有助于解析文件的通用策略。
在前面的示例中,我们的运气太差了:如果比默认方式再多检查 1 行,我们就能一蹴而就,解析成功。
challenge2 <- read_csv(
readr_example("challenge.csv"),
guess_max = 1001
)
)
# Parsed with column specification:
# cols(
# x = col_double(),
# y = col_date(format = "")
# )
challenge2
# # A tibble: 2,000 x 2
# x y
#
# 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
# 有时如果将所有列都作为字符向量读入的话,会更容易诊断出问题
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 x 2
# x y
#
# 1 1 1.21
# 2 2 2.32
# 3 3 4.56
type_convert(df)
# Parsed with column specification:
# cols(
# x = col_double(),
# y = col_double()
# )
# # A tibble: 3 x 2
# x y
#
# 1 1 1.21
# 2 2 2.32
# 3 3 4.56
6 写入文件
readr 还提供了两个非常有用的函数,用于将数据写回到磁盘:write_csv()
和 write_ tsv()
。这两个函数输出的文件能够顺利读取的概率更高,因为:
- 它们总是使用 UTF-8 对字符串进行编码;
- 它们使用 ISO 8601 格式来保存日期和日期时间数据,以便这些数据不论在何种环境下都更容易解析。
6.1 用法:
write_delim(x, path, delim = " ", na = "NA", append = FALSE, col_names = !append, quote_escape = "double")
write_csv(x, path, na = "NA", append = FALSE, col_names = !append, quote_escape = "double")
write_csv2(x, path, na = "NA", append = FALSE, col_names = !append, quote_escape = "double")
write_excel_csv(x, path, na = "NA", append = FALSE, col_names = !append, delim = ",", quote_escape = "double")
write_excel_csv2(x, path, na = "NA", append = FALSE, col_names = !append, delim = ";", quote_escape = "double")
write_tsv(x, path, na = "NA", append = FALSE, col_names = !append, quote_escape = "double")
6.2 导为 Excel 文件
如果想要将 CSV 文件导为 Excel 文件,可以使用 write_excel_csv()
函数,该函数会在文件开头写入一个特殊字符(字节顺序标记),告诉 Excel 这个文件使用的是 UTF-8 编码。
这几个函数中最重要的参数是 x(要保存的数据框)和 path(保存文件的位置)。还可以使用 na 参数设定如何写入缺失值,如果想要追加到现有的文件,需要设置 append 参数:
write_csv(challenge, "challenge.csv")
- 当保存为 CSV 文件时,类型信息就丢失了
challenge
# # A tibble: 2,000 x 2
# x y
#
# 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
write_csv(challenge, "challenge-2.csv")
read_csv("challenge-2.csv")
# # A tibble: 2,000 x 2
# x y
#
# 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
7 其他类型的数据读取
要想将其他类型的数据导入 R 中,我们建议首先从下列的 tidyverse 包开始。它们当然远非完美,但确实是一个很好的起点。对矩形数据来说
haven
可以读取 SPSS、Stata 和 SAS 文件
readxl
可以读取 Excel 文件(.xls 和 .xlsx 均可);
- readxl-package {readxl}
-
readxl: Read Excel Files
配合专用的数据库后端程序(如 RMySQL、RSQLite、RPostgreSQL 等),DBI 可以对相应数据库进行 SQL 查询,并返回一个数据框