数据导入利器——rio包

作者: 新云旧雨 | 来源:发表于2019-10-01 02:20 被阅读0次

    笔记说明

    在读《Modern R with the tidyverse》一书时发现了这个非常好用的R包,做此笔记记录。本笔记记录rio包的数据导入功能。导出功能说明见:用rio包进行数据导出

    数据导入

    Hadley Wickham在《R for Data Science》中总结的探索性数据分析的分析流程

    数据导入是数据分析的第一步。实际工作中数据的来源和原始数据文件的格式多种多样。对应不同的原始文件来源或格式就有很多不同的读取数据的R包。学习、使用起来非常麻烦。在rio包之前,为了满足数据导入需要,大概需要学习的R包和其对应的数据文件类型如下:

    • readr包 - text files(如csv, tsv, fwf文件)
    • haven包 - SPSS, Stata, and SAS files
    • readxl包 - excel files
    • DBI包 - databases
    • jsonlite包 - json
    • xml2包 - XML
    • httr包 - Web APIs
    • rvest包 - HTML (Web Scraping)

    rio包及其数据导入功能

    rio包封装了很多数据导入和导出的包,并将不同包的数据导入导出操作统一到两个函数上:import()export(),通过文件的后缀名来判断文件类型。这使得在R中进行数据的导入导出操作变得非常简单。有关rio包的更多信息可以参见:https://cran.r-project.org/web/packages/rio/vignettes/rio.html
    下面对rio包的一些数据导入功能进行展示(基本参照《Modern R with the tidyverse》中对应的内容,所使用的数据可以在https://github.com/b-rodrigues/modern_R/tree/master/datasets下载):

    • 加载rio包
    library(rio)
    
    ## The following rio suggested packages are not installed: ‘csvy’, ‘feather’, ‘fst’, ‘hexView’, ‘readODS’, ‘rmatio’, ‘xml2’
    ## Use 'install_formats()' to install them
    
    • 使用import()进行数据导入
    #导入csv文件
    mtcars <- import("data/mtcars.csv")
    head(mtcars)
    
    ##   mpg cyl disp  hp drat    wt  qsec vs am gear carb
    ## 1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
    ## 2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
    ## 3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
    ## 4 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
    ## 5 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
    ## 6 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
    

    在Windows系统下,对于萌新来说需要注意的一点是不能直接把文件路径粘贴过来,windows系统使用“\”标识路径,而R使用“/”表示路径。
    导入其他格式的数据也是一样:

    #导入stata数据
    mtcars_stata <- import("data/mtcars.dta")
    #导入sas数据
    mtcars_sas <- import("data/mtcars.sas7bdat")
    
    • import_list()导入一个excel文件中的多个sheet
    multi <- import_list("data/multi.xlsx")
    str(multi)
    
    ## List of 2
    ##  $ mtcars:'data.frame':  32 obs. of  11 variables:
    ##   ..$ mpg : num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
    ##   ..$ cyl : num [1:32] 6 6 4 6 8 6 8 4 4 6 ...
    ##   ..$ disp: num [1:32] 160 160 108 258 360 ...
    ##   ..$ hp  : num [1:32] 110 110 93 110 175 105 245 62 95 123 ...
    ##   ..$ drat: num [1:32] 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
    ##   ..$ wt  : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
    ##   ..$ qsec: num [1:32] 16.5 17 18.6 19.4 17 ...
    ##   ..$ vs  : num [1:32] 0 0 1 1 0 1 0 1 1 1 ...
    ##   ..$ am  : num [1:32] 1 1 1 0 0 0 0 0 0 0 ...
    ##   ..$ gear: num [1:32] 4 4 4 3 3 3 3 4 4 4 ...
    ##   ..$ carb: num [1:32] 4 4 1 1 2 1 4 2 2 4 ...
    ##  $ iris  :'data.frame':  150 obs. of  5 variables:
    ##   ..$ Sepal.Length: num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
    ##   ..$ Sepal.Width : num [1:150] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
    ##   ..$ Petal.Length: num [1:150] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
    ##   ..$ Petal.Width : num [1:150] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
    ##   ..$ Species     : chr [1:150] "setosa" "setosa" "setosa" "setosa" ...
    

    str(multi)的结果可以看出,导入后生成的multi对象是一个由两个dataframe组成的list。

    • 一次性导入同一目录下的所有数据文件

    首先生成一个包含所有数据文件的向量:

    paths <- Sys.glob("data/unemployment/*.csv")
    paths
    
    ## [1] "data/unemployment/unemp_2013.csv" "data/unemployment/unemp_2014.csv"
    ## [3] "data/unemployment/unemp_2015.csv" "data/unemployment/unemp_2016.csv"
    

    Sys.glob()利用正则表达式找到所有数据文件,本例中找到所有data/unemployment/目录下以csv为后缀的文件。
    之后利用import_list()一次性导入所有数据文件:

    all_data <- import_list(paths)  
    str(all_data)
    
    ## List of 4
    ##  $ unemp_2013:'data.frame':  118 obs. of  8 variables:
    ##   ..$ Commune                   : chr [1:118] "Grand-Duche de Luxembourg" "Canton Capellen" "Dippach" "Garnich" ...
    ##   ..$ Total employed population : int [1:118] 223407 17802 1703 844 1431 4094 2146 971 1218 3002 ...
    ##   ..$ of which: Wage-earners    : int [1:118] 203535 15993 1535 750 1315 3800 1874 858 1029 2664 ...
    ##   ..$ of which: Non-wage-earners: int [1:118] 19872 1809 168 94 116 294 272 113 189 338 ...
    ##   ..$ Unemployed                : int [1:118] 19287 1071 114 25 74 261 98 45 66 207 ...
    ##   ..$ Active population         : int [1:118] 242694 18873 1817 869 1505 4355 2244 1016 1284 3209 ...
    ##   ..$ Unemployment rate (in %)  : num [1:118] 7.95 5.67 6.27 2.88 4.92 ...
    ##   ..$ Year                      : int [1:118] 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
    ##  $ unemp_2014:'data.frame':  118 obs. of  8 variables:
    ##   ..$ Commune                   : chr [1:118] "Grand-Duche de Luxembourg" "Canton Capellen" "Dippach" "Garnich" ...
    ##   ..$ Total employed population : int [1:118] 228423 18166 1767 845 1505 4129 2172 1007 1268 3124 ...
    ##   ..$ of which: Wage-earners    : int [1:118] 208238 16366 1606 757 1390 3840 1897 887 1082 2782 ...
    ##   ..$ of which: Non-wage-earners: int [1:118] 20185 1800 161 88 115 289 275 120 186 342 ...
    ##   ..$ Unemployed                : int [1:118] 19362 1066 122 19 66 287 91 38 61 202 ...
    ##   ..$ Active population         : int [1:118] 247785 19232 1889 864 1571 4416 2263 1045 1329 3326 ...
    ##   ..$ Unemployment rate (in %)  : num [1:118] 7.81 5.54 6.46 2.2 4.2 ...
    ##   ..$ Year                      : int [1:118] 2014 2014 2014 2014 2014 2014 2014 2014 2014 2014 ...
    ##  $ unemp_2015:'data.frame':  118 obs. of  8 variables:
    ##   ..$ Commune                   : chr [1:118] "Grand-Duche de Luxembourg" "Canton Capellen" "Dippach" "Garnich" ...
    ##   ..$ Total employed population : int [1:118] 233130 18310 1780 870 1470 4130 2170 1050 1300 3140 ...
    ##   ..$ of which: Wage-earners    : int [1:118] 212530 16430 1620 780 1350 3820 1910 920 1100 2770 ...
    ##   ..$ of which: Non-wage-earners: int [1:118] 20600 1880 160 90 120 310 260 130 200 370 ...
    ##   ..$ Unemployed                : int [1:118] 18806 988 106 29 73 260 80 41 72 169 ...
    ##   ..$ Active population         : int [1:118] 251936 19298 1886 899 1543 4390 2250 1091 1372 3309 ...
    ##   ..$ Unemployment rate (in %)  : num [1:118] 7.46 5.12 5.62 3.23 4.73 ...
    ##   ..$ Year                      : int [1:118] 2015 2015 2015 2015 2015 2015 2015 2015 2015 2015 ...
    ##  $ unemp_2016:'data.frame':  118 obs. of  8 variables:
    ##   ..$ Commune                   : chr [1:118] "Grand-Duche de Luxembourg" "Canton Capellen" "Dippach" "Garnich" ...
    ##   ..$ Total employed population : int [1:118] 236100 18380 1790 870 1470 4160 2160 1030 1330 3150 ...
    ##   ..$ of which: Wage-earners    : int [1:118] 215430 16500 1640 780 1350 3840 1900 900 1130 2780 ...
    ##   ..$ of which: Non-wage-earners: int [1:118] 20670 1880 150 90 120 320 260 130 200 370 ...
    ##   ..$ Unemployed                : int [1:118] 18185 975 91 27 66 246 76 35 70 206 ...
    ##   ..$ Active population         : int [1:118] 254285 19355 1881 897 1536 4406 2236 1065 1400 3356 ...
    ##   ..$ Unemployment rate (in %)  : num [1:118] 7.15 5.04 4.84 3.01 4.3 ...
    ##   ..$ Year                      : int [1:118] 2016 2016 2016 2016 2016 2016 2016 2016 2016 2016 ...
    

    特别地,如果处理的数据是像unemployment数据这种,每个数据集的变量结构一致,你可以在一次性导入同一目录下所有数据文件的基础上,利用rbind = TRUE选项将他们合并到一个数据集中:

    bind_data <-  import_list(paths, rbind = TRUE)  
    str(bind_data)
    
    ## 'data.frame':    472 obs. of  9 variables:
    ##  $ Commune                   : chr  "Grand-Duche de Luxembourg" "Canton Capellen" "Dippach" "Garnich" ...
    ##  $ Total employed population : int  223407 17802 1703 844 1431 4094 2146 971 1218 3002 ...
    ##  $ of which: Wage-earners    : int  203535 15993 1535 750 1315 3800 1874 858 1029 2664 ...
    ##  $ of which: Non-wage-earners: int  19872 1809 168 94 116 294 272 113 189 338 ...
    ##  $ Unemployed                : int  19287 1071 114 25 74 261 98 45 66 207 ...
    ##  $ Active population         : int  242694 18873 1817 869 1505 4355 2244 1016 1284 3209 ...
    ##  $ Unemployment rate (in %)  : num  7.95 5.67 6.27 2.88 4.92 ...
    ##  $ Year                      : int  2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
    ##  $ _file                     : chr  "data/unemployment/unemp_2013.csv" "data/unemployment/unemp_2013.csv" "data/unemployment/unemp_2013.csv" "data/unemployment/unemp_2013.csv" ...
     - attr(*, ".internal.selfref")=<externalptr> 
    

    注意到新生成的数据集中多了一个变量:_file 用来指示当前观测原本属于哪个数据文件。

    • 使用更多参数进行非常规导入

    如果数据导入遇到问题,可能需要查看rio包背后使用的是什么包的什么函数来进行数据导入,并根据情况在用import()读取数据时添加对应参数。
    接下来看一个不成功的导入例子:

    testdata <- import("data/mtcars_problem.csv")  
    head(testdata)
    
    ##   mpg&cyl&disp&hp&drat&wt&qsec&vs&am&gear&carb
    ## 1          21&6&160&110&3.9&2.62&16.46&0&1&4&4
    ## 2         21&6&160&110&3.9&2.875&17.02&0&1&4&4
    ## 3        22.8&4&108&93&3.85&2.32&18.61&1&1&4&1
    ## 4      21.4&6&258&110&3.08&3.215&19.44&1&0&3&1
    ## 5       18.7&8&360&175&3.15&3.44&17.02&0&0&3&2
    ## 6       18.1&6&225&105&2.76&3.46&20.22&1&0&3&1
    

    可以看出导入并不成功,不成功的原因在于原始的csv中使用非常规的“&”符号作为分隔符。查看import()的帮助(在R中运行“?import”)可知,当数据是csv格式时,rio调用data.table包的fread()进行读取。我们进一步查看data.table::fread()的帮助,发现fread()中可以使用sep=选项来指定csv数据的分隔符。当我们把这个参数传给import()后,import()会在调用data.table::fread()时将其传给data.table::fread()

    testdata <- import("data/mtcars_problem.csv", sep = "&")  
    head(testdata)
    
    ##    mpg cyl disp  hp drat    wt  qsec vs am gear carb
    ## 1   21   6  160 110  3.9  2.62 16.46  0  1    4    4
    ## 2   21   6  160 110  3.9 2.875 17.02  0  1    4    4
    ## 3 22.8   4  108  93 3.85  2.32 18.61  1  1    4    1
    ## 4 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
    ## 5 18.7   8  360 175 3.15  3.44 17.02  0  0    3    2
    ## 6 18.1   6  225 105 2.76  3.46 20.22  1  0    3    1
    

    相关文章

      网友评论

        本文标题:数据导入利器——rio包

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