前言
前面我们讲到了 readr
的解析器,总共有 8
个解析函数。
下面我们具体介绍每个解析函数的用法
解析器
1. 数值
对数值的解析看起来挺简单的,但其实有几个问题需要解决:
-
世界上不同地区的人写数字的方式会有所不同,比如,一些国家使用
.
来区分实数的整数部分和小数部分,而其他国家使用,
来区分 -
数字在不同的使用场景会被不同的字符包裹,比如
$1000
,10%
-
数字通常包含分组字符,方便阅读。例如
1,000,000
为了解决第一个问题,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("$100")
[1] 100
> parse_number("20%")
[1] 20
> parse_number("It cost $123.45")
[1] 123.45
最后一个问题可以通过结合 parse_number()
和 locale
来忽略分组标记
# Used in America
> parse_number("$123,456,789")
[1] 123456789
# Used in many parts of Europe
> parse_number("123.456.789", locale = locale(grouping_mark = "."))
[1] 123456789
# Used in Switzerland
> parse_number("123'456'789", locale = locale(grouping_mark = "'"))
[1] 123456789
2. 字符串
用 parse_character()
来解析字符串看起来应该是很简单的,能够直接把输入返回。
但是,生活并不是那么简单的,因为同一个字符串的表示方法有很多种。
为了理解解析时发生了,我们需要深入了解计算机如何来表示字符串的。在 R
中,我们可以使用 charToRaw()
获得字符串的底层表示形式
> charToRaw("Hadley")
[1] 48 61 64 6c 65 79
每个十六进制数代表一个字节的信息,48
表示 H
, 61
表示 a
等等。从十六进制数到字符的映射称为编码,在这种情况下编码称为 ASCII
。
ASCII
在表示英语字符方面做得很好,因为它是美国信息交换的标准代码
而对于非英文来说,事情就变得更加复杂了点。在计算机早期时代,有许多编码非英语字符的竞争标准,要正确解释一个字符串,您需要同时知道值和编码
例如,两种常见的编码 Latin1
(ISO-8859-1
,用于西欧语言)和 Latin2
(ISO-8859-2
,用于东欧语言)。在 Latin1
中,字节 b1
表示 ±
,但是在 Latin2
中表示的是 ą
。
幸运的是,现在有一个标准几乎在所有地方都能够得到支持:UTF-8
。UTF-8
可以编码当今人类使用的几乎所有字符,以及许多额外的符号(比如 emoji
)
readr
使用的都是 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"
> x1
[1] "El Ni\xf1o was particularly bad this year"
> x2
[1] "\x82\xb1\x82\xf1\x82\u0242\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))
# A tibble: 2 x 2
encoding confidence
<chr> <dbl>
1 ISO-8859-1 0.46
2 ISO-8859-9 0.23
> guess_encoding(charToRaw(x2))
# A tibble: 1 x 2
encoding confidence
<chr> <dbl>
1 KOI8-R 0.42
guess_encoding()
的第一个参数可以是文件的路径,也可以是字符串的原始向量
3. 因子
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 <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
4. 时间和日期
你可以根据需要从三个解析器中选择相应的解析器
-
parse_datetime()
:ISO8601
格式的日期和时间,ISO8601
是一个国际标准,其中日期的组成部分按从大到小的顺序排列:年、月、日、时、分、秒
[1] "2010-10-01 20:10:00 UTC"
> parse_datetime("20101010")
[1] "2010-10-10 UTC"
-
parse_date()
: 接受4
位数的年份yyyy-mm-dd
或yyyy/mm/dd
> parse_date("2010-10-01")
[1] "2010-10-01"
-
parse_time()
: 接受格式hh:mm(:ss am/pm)
> parse_time("01:10 am")
01:10:00
> parse_time("20:10:01")
20:10:01
如果这些默认值不适用于您的数据,您可以提供自己的日期时间格式,由以下几部分组成
Year
-
%Y
:4
位数字 -
%y
:2
位数字;00-69 -> 2000-2069
,70-99 -> 1970-1999
Month
-
%m
:2
位数字 -
%b
: 简写, 如Jan
-
%B
: 全称, 如January
Day
-
%d
:2
位数字 -
%e
: 可选的前导空格
Time
-
%H
:0-23
小时 -
%I
:0-12
小时, 必须包含%p
-
%p
:AM/PM
-
%M
: 分钟 -
%S
: 整数秒数 -
%OS
: 实数秒数 -
%Z
: 时区 -
%z
: 相对于UTC
的偏移, 如+0800
Non-digits
-
%.
: 跳过一个非数字字符 -
%*
: 跳过任意个非数字字符
示例
> 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"
如果 %B
或 %b
使用的是非英语的月份名,你需要用 locale()
设置语言。
详情参见 date_names_langs()
中的内置语言列表,或者如果没有包含你的语言,可以用 date_names()
创建你自己的语言
> parse_date("1 janvier 2015", "%d %B %Y", locale = locale("fr"))
[1] "2015-01-01"
最后,是上节的思考练习。是一位读者写的,我发出来给大家参考参考
( ̄▽ ̄)~*
网友评论