R数据科学实战工具详解与案例分析 》 —1.1.3 read.table—任意分隔符数据读取

网友投稿 1447 2022-05-30

1.1.3 read.table—任意分隔符数据读取

read.table函数会将文件读成数据框的格式,将分隔符作为区分变量的依据,把不同的变量放置在不同的列中,每一行的数据都会对应相应的变量名称进行排放。表1-1简要列出了read.table函数中主要参数的中英文对照。

表1-1 函数read.table实用参数及功能对照

以上这些参数已足以应付读取日常练习所用的规整的数据文件,例如,教授布置的统计作业中的原始数据集,各种传感器输出的.csv文件等。下面的代码及运行结果演示非常简单,使用read.table读取1.1.1节中的第一个数据集,实现思路是每次只增加一个read.table函数中的参数。代码如下:

> flights <- read.table(file = "flights.csv")

> head(x = flights)

表1-2展示了所有参数均为默认设置的部分结果。

表1-2 read.table函数参数设置结果展示一

小提示

上面的演示代码中使用了head函数,该函数可以按照人们习惯的方式将数据框按照自上而下的方式显示出来,而不是像str函数那样从左向右展示。一般在做初步数据检视的时候,推荐两个函数都运行,作为互补。head方便与原始数据文档进行比对,而str则可以显示所保存的数据框属性、变量类型等信息。

因为函数默认的分隔符是空白(注意不是空格),所以应有的6个变量都被读在一列中。且默认的header参数是假,所以数据变量被默认分配了一个新的变量名V1,并且应为变量名称的这一行变成了观测值的第一行。将header设置为TRUE后的代码如下:

> flights <- read.table(file = "flights.csv",header = TRUE)

> head(x = flights)

表1-3中显示的是部分结果。

表1-3 read.table函数参数设置结果展示二

指定header参数为真,分隔符sep参数为“,”后,变量名称才得以读取成应有的样子(如表1-4所示)。

> flights <- read.table(file = "flights.csv",header = TRUE,sep = ",")

> head(flights)

表1-4 read.table函数参数设置结果展示三

表1-4所示的数据框终于呈现了该有的样子。需要注意的,是因为字符数据因子化的参数还是默认设置,因此变量carrier、tailnum、origin、dest还是因子型。在实际练习或使用时,建议指定stringAsFactors = FALSE。

以上读取的数据集都是规整的数据集,即每一行数据都有相同的观测值。不过在实际生活中,原始数据难免会存在空白行、空白值、默认值,或者某一行数据存在多余观测值却没有与之对应的变量名称,抑或元数据和原始数据在同一个文件中等各种问题。这里暂且称这些问题数据集为不规则数据集,简单说就是,实际列的个数多于列名的个数。read.table函数为这些问题准备了相应的参数。

1.空白行

表1-1中介绍过read.table对于空白行的默认处理是跳过,这可以满足大部分常见数据的情况。不过在某些特殊情况下,例如,一个数据文件中同时存在两个或两个以上的数据集,那么保留空白行可能会有助于后续的数据处理。表1-5演示的就是一个比较特殊的例子。空白行的上部是元数据,也即解释数据的数据,这里演示的是航空公司的缩写和全名的对照。空白行的下部是数据的主体部分,航班号、起始地缩写、起飞时间。这里保留空白行可有助于区分数据的不同部分。

表1-5 特殊类型文本数据文档

保留空白行的代码如下所示:

> airlines <- read.table(file = "airlines.csv", header = TRUE, sep = "\t", blank.lines.skip = FALSE, stringsAsFactors = FALSE)

> head(airlines, n = 8)

指定空白行保留的参数后,数据被成功读进R(表1-6)。

表1-6  read.table函数参数设置结果展示四

如此一来,不同的数据集就可以很容易地进行切割并归集到新的数据集中。可是,另外一个问题又出现了,函数按照第一部分的两列变量将后续的所有数据也都写入了两列。这是因为read.table会扫描文件中前五行的数据(包括变量名称)并以此为标准来确定变量数,airlines.csv中开始的五行数据都只有两列,所以后续的数据也都强制读取成两列。如果数据的第2~5行中存在任何一行拥有多于前面一行或几行的数据值,那么函数就会报错提示第一行没有相应数量的值。这种情况可以根据实际数据文件内容,用两种方式来处理,具体如下。

1)如果文件中开始的部分是暂时不需要的元数据,那么可以使用skip函数跳过相应的行数,只读取感兴趣的数据。

2)如果文件内容是一个整体,只是若干行数据具有额外的观测值。那么可以通过调整参数col.names或fill和header进行处理。

第一种情况比较容易,读者可以自行测试,在此略过。第二种情况需要知道数据中观测值个数的最大值,以用来补齐变量个数。因为已经知道airlines文件的第二部分拥有6个变量,所以下面就来演示如何将6个变量名称指定成新的变量名(表1-7),代码如下:

> airlines <- read.table(file = "airlines.csv", header = FALSE, sep = "\t", stringsAsFactors = FALSE, col.names = paste0("V",1:6), blank.lines.skip = FALSE)

> head(airlines)

演示结果如表1-7所示。

《R数据科学实战:工具详解与案例分析 》 —1.1.3 read.table—任意分隔符数据读取

表1-7 read.table函数参数设置结果展示五

小技巧:

另外一个获取不规则数据集中所需变量个数的方法是利用报错信息。当不指定col.names参数,且原始数据的第2~5行中任一行有多于第一行的数据时,read.table会报错提示Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : line 1 did not have X elements, X即所需要的手动指定的变量个数。

这里使用paste0来创建新的变量名称。paste0可以理解为胶水函数,用于将需要的字符串粘合在一起。这里演示的意思是创建6个以V开头,从V1到V6的字符串作为变量名。这种处理方式足以应付平时练习用的小型数据集(比如,只有几行到几十行数据的数据集)。但是在处理实际工作中成百上千行的数据时,这种手动指定变量个数的方法就显得笨拙而低效了。下面的代码演示了如何实现自动检测数据集所需的变量数:

> number_of_col <- max(count.fields("airlines.csv",sep = "\t"))

> airlines <- read.table(file = "airlines.csv", header = FALSE, sep = "\t", stringsAsFactors = FALSE, col.names = paste0("V",seq_len(number_of_col)), blank.lines.skip = FALSE)

> head(airlines)

部分结果展示如表1-8所示。

表1-8 read.table函数参数设置结果展示六

count.fields/max/seq_len这三个函数的配合使用实现了如下功能。

count.fields用于自动检测数据集中每一行数据的观测值个数,max用于找出count.fields输入结果中的最大值,seq_len用于以最大值为参照生成1到最大值的整数序列,胶水函数paste0用于定义变量名称。

因为R基于向量计算的特性,因此这种函数之间简单的配合使用很常见也很有效。所以希望小伙伴们在以后的练习或实际工作中,多思考,尽量使用这样的组合来提高代码的效率、简洁性和可重复性。

使用参数fill和header也可以读取不规则数据集。需要注意的是,采用这种方法是有前提条件的,即原始数据第2~5行实际列的个数应大于列名。代码如下:

> flights_uneven <- read.table("airlines.csv", header = FALSE, sep = "\t", stringsAsFactors = FALSE, fill = TRUE)

> head(flights_uneven)

上述代码的演示结果如表1-9所示。

表1-9 read.table函数参数设置结果展示七

2.默认值、空白

一个数据集里出现默认值(NA)或空白(“”)的情况十分常见,两者之间的区别需要根据不同的实际情况来确定。理论上来讲,默认值仍是数据观测值的一种,虽然在原始数据中其可能与空白一样没有显示,但是它可以通过其他手段来进行补齐。而空白有可能并不是数据,比如在上面的演示中,V3至V6列,1~5行都是空白,这些空白不属于任何实际数据变量,是真正的空白,因而不能说这些空白是默认值。默认值和空白的处理完全可以独立成书,因为相关内容已经超出了本书的范围,所以这里不再过多讨论。下面只演示在导入数据的过程中,如何进行简单的默认值、空白预处理,代码如下:

> flights_uneven <- read.table(file = "flights_uneven.csv", header = FALSE, sep = "\t", stringsAsFactors = FALSE, fill = TRUE, na.strings = c(""))

> head(flights_uneven)

表1-10中展示了处理后的部分数据值。

表1-10 read.table函数参数设置结果展示八

第七列中的数据在指定将空白替换成“NA”之后,原有的空白位置被写入了“NA”,也就是说第七列的空白属于数据的一部分。根据实际情况,也可以将多余的数据部分或全部替换成“NA”(如表1-11所示),以方便后续的处理及分析,代码如下:

> flights_uneven <- read.table("flights_uneven.csv",sep = "\t", stringsAsFactors = FALSE, fill = TRUE,header = FALSE, na.strings = c(paste0("测试",1:3),""))

> head(flights_uneven)

替换结果如表1-11所示。

表1-11 read.table函数参数设置结果展示九

当数据集行数较多,无法轻易地鉴别出某一列到底有多少个观测值需要赋值为“NA”的时候,可以配合unique函数进行处理。处理的思路是先将数据读取到R中,然后使用unique函数找到指定列中的非重复观测值,选取指定观测值并保存到一个向量内,然后将向量指定给na.strings参数来进行替换,代码如下:

> flights_uneven <- read.table("flights_uneven.csv",sep = "\t", string-sAsFactors = FALSE, fill = TRUE, header = FALSE)

> replace <- unique(flights_uneven$V7)

replace

[1] ""      "测试1" "测试2" "测试3"

> flights_uneven <- read.table("flights_uneven.csv",sep = "\t", stringsAsFactors = FALSE, fill = TRUE,header = FALSE, na.strings = c(replace[c(1,3)]))

> head(flights_uneven)

替换结果如表1-12所示。

表1-12 read.table函数参数设置结果展示十

第一次读取数据是为了获得需要替换的观测值,第二次读取则是将需要替换成“NA”的观测值指定给相应参数。因为replace是一个字符串向量,所以可以使用“[”按位置选择其中的值,当然也可以不选择任何值,直接全部替换。

小知识

“[”是baseR中Extract的一种,在R的使用过程中,这是必须掌握和理解的函数之一。

其他

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring Boot微信扫码支付
下一篇:2021年大数据Spark(二十五):SparkSQL的RDD、DF、DS相关操作
相关文章