前言

文本是数据分析师接触最多的一种数据,本文讲解如何使用R对其进行读写,使用readr这个包:

install.packages("readr")

读取文本

基础

readr提供许多工具函数用于读取不同类型的文件:

  • 分隔符:read_csv()读取逗号分隔的文件;read_csv2()读取分号分隔的文件;read_tsv()读取\t分隔的文件;read_delim()读取任意分隔符分隔的文件。
  • 固定宽度:read_fwf()读取固定宽度的文件,指定宽度的方法包括三种,一是fwf_empty(),获取一个或多个空格形成的空白位置,并用其拆分列,这种模式被封装为另一个函数read_table();二是fwf_widths(),指定每个字段的宽度;三是fwf_positions(),提供两个vector,分别指定每个字段的起始位置和结束位置。
  • 日志:read_log()读取Apache风格的日志,更高级的功能可以使用webreadr包。

本文只讲解read_csv()方法,其余方法类似。

read_csv()的第一个参数是文件路径,另有几个常用的选项:

  • skip=n:跳过前n行;
  • comment="#":忽略以#开头的所有行;
  • col_names = FALSE:告诉readr文件不包含列名;
  • na="NA":告诉readr文件中的NA字符串代表空值

绝大多数情况下,上面的这些知识就足够用来读取文本了。readr提供的这些工具比R内置的read.table()系列函数效率要高十几倍。如果文件还是太大,读的还是太慢,可以移步data.table包,试一下fread()函数。

进阶

如果读取文件遇到了问题,那就需要这些知识帮助你正确地读入文件。

首先,我们要知道data.frame是按列存储的,每一列是一个向量。readr的底层原理是:读取文件的前1000行,对1000行的每一列去推断它最可能的类型。所以以下情况就会出错:假设一列数据是numeric类型,但是前1000行是整数,所以被错误地判断为integer类型,导致这列后续的值读取出错;又或者这一列的前1000行是缺失值,会被错误地判断为character类型,导致这列后续的值虽然被读入,但类型不对。你可以使用下面的选项推测类型时修改读取的行数:

  • guess_max = 1001:读取前1001行推断每列类型。

每一列数据最开始都被当做是字符串,readr一共有以下几类解析器,试图将其解析为对应的格式:

  • parse_logical()parse_integer()
  • parse_double()
  • parse_character():主要得处理编码问题
  • parse_factor()
  • parse_datetime()parse_date()parse_time():针对日期时间处理

调用read_csv()失败后会返回解析失败的几行数据,用problems()可以观察所有的出错结果。根据观察结果,你可以使用以下选项人工指定每一列的类型:

  • col_types = cols(x = col_integer(), y = col_character()):指定x为整数类型,指定y为字符串类型。
  • col_types = cols(.default = col_character()):让未声明类型的每一列都按照字符串类型读取。

上述的每个parse_xyz()对应一个col_xyz()类型。

输出文本

readr提供两个函数将数据写入到磁盘:write_csv()write_tsv()。在写出过程中,字符串的编码使用UTF-8,日期时间格式按照ISO8601输出。

如果希望输出的csv文件提供给Excel,请使用write_excel_csv(),这个函数将在文件的开头写入一些标记,让Excel知道文件是使用UTF-8编码。

输出文本的常用选项有:

  • x=df:要输出的data.frame数据;
  • path=file_name:保存的文件路径;
  • na=".":代表空值的字符串输出;
  • append=FALSE:是否追加模式。

除了输出文本,readr还支持输出二进制格式。RDS是R自定义的一种二进制编码格式,通过write_rds()read_rds()可以完成这种格式文件的读写。