美文网首页R语言学习
Rdata005 使用readr进行数据导入

Rdata005 使用readr进行数据导入

作者: caoqiansheng | 来源:发表于2020-09-18 15:37 被阅读0次

    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
    # <dbl> <dbl> <dbl>
    # 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`
    # <dbl> <dbl> <dbl>
    #  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
    # <dbl> <dbl> <dbl>
    # 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`
    # <chr>           
    # 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   
    # <chr>            <chr> <chr>
    # 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   
    # <chr> <chr> <chr>
    # 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   
    # <chr> <chr> <chr>
    # 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    
    # <chr> <chr> <chr>
    # 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
    # <dbl> <dbl> <dbl>
    # 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
    # <dbl> <dbl> <dbl>
    # 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
    #     <int> <int> <chr>                  <chr> 
    # 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
    #     <int> <int> <chr>                  <chr> 
    # 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
    #     <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
    # 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 <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
    # 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                                                                           
    #    <int> <chr> <chr>              <chr>      <chr>                                                                          
    # 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    
    #   <dbl> <chr>
    # 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         
    #   <dbl>   <chr>     
    # 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         
    #   <dbl>   <date>    
    # 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         
    #   <dbl> <date>    
    # 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    
    #  <chr> <chr>
    # 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
    #    <dbl> <dbl>
    # 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         
    #   <dbl> <date>    
    # 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    
    #   <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
    

    7 其他类型的数据读取

    要想将其他类型的数据导入 R 中,我们建议首先从下列的 tidyverse 包开始。它们当然远非完美,但确实是一个很好的起点。对矩形数据来说

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

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

    • readxl-package {readxl}
    • readxl: Read Excel Files


      image.png

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

    相关文章

      网友评论

        本文标题:Rdata005 使用readr进行数据导入

        本文链接:https://www.haomeiwen.com/subject/mxqjyktx.html