本节书摘来自华章出版社《R语言数据分析》一书中的第1章,第1.3节,作者盖尔盖伊·道罗齐(Gergely Daróczi),潘怡 译,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1.3 导入文本文件的子集
某些时候,我们仅需要一部分存放在数据库或文本文件中的数据用来进行数据分析。此时,如果处理对象范围仅包括数据框中和应用相关的数据子集,其处理速度将比我们之前讨论过的那些特定开发包和性能优化程序更快。
假设我们仅对飞往纳什维尔的航班感兴趣,因为2012年在那召开了useR!的大会,那我们仅需要CSV文件中Dest属性为BNA的记录(BNA为国际航空运输协会为纳什维尔规定的国际空港编号)。
与其先花将近2000毫秒导入所有的数据(如前述小节所述),然后再去掉不符合要求的行(参见第3章),不如让我们看看在数据装载时就对其进行筛选的处理方法。
可以使用前面提到的sqldf包来解决这个问题。通过设置SQL语句的内容来完成数据的筛选:
参数sql默认为“select * from f?ile”,即从数据集中选择所有数据。现在,在此基础上增加一个筛选条件。注意,我们对更新后的SQL语句中查找条件上增加了双引号,因为sqldf不能自动识别出双引号,只会将其作为域的一部分处理。我们也可以在类Unix系统中通过一个特制的用户筛选参数,如下例所示来解决这个问题:
处理得到的结果数据框包含了从227?496个记录中筛选出的3481个样本值,而使用临时的SQLite数据库来进行筛选也能提高一点点导入速度:
之所以能加快一点处理速度,是因为所有的R命令首先都会将CSV文件先加载到一个临时的SQLite数据库中,这一过程所需要的时间是不能少的。为了加快处理速度,读者可以将dbname指定为null,这样,系统就会在内存而非临时文件内创建SQLite数据库,但是这种方法有可能并不适合大数据集。
在导入到R会话前筛选平面文件
有没有其他更快或更便捷的方法来处理类似文本文件中的部分数据呢?有些人可能会采取一些常规的基于表达式的筛选条件,在导入平面文件之前对其进行筛选。例如,在Unix环境中,grep或者ack都是非常不错的工具。但是在Windows平台上,我们默认是找不到类似方法的,并且将CSV文件采用常规表达式去进行解析也有可能导致一些意想不到的负面结果。相信我,你肯定不愿意从零开始写一个CSV、JSON,或者XML的分析器。
无论如何,现在数据科学家在处理数据时,必须要具备万事通的能力。下面,我们将给出一个简单可行的样例来展示我们如何以低于100毫秒的速度读入筛选好的数据:
相比之前我们得到的结果,这个结果确实非常棒!但如果我们希望再挑选出那些到达时延超过13.5分钟的航班呢?
另一种,也可能是更容易实现的方法,可以首先将数据导入到某个数据库中,然后根据需要,查询得到符合条件的数据子集。我们使用一个简单的例子来说明这种方法。例如,将SQLite数据库导入到某个文件中,然后在read.csv.sql的默认运行时间内来获取任意数据子集。
下面,我们将创建一个永久的SQLite数据库:
该命令在当前工作路径下创建了一个名为hf?lights_db的文件。接下来,我们还将创建一个名为hf?lights的表格,并将之前CSV文件的内容导入到该数据库中:
至此,还没完成创建测试平台的任务,由于以上操作仅能执行一次,而对数据集进行筛选的操作之后有可能需要执行若干次:
我们在少于100毫秒的时间内完成了数据库子集的导入!不过,如果计划经常需要对这个永久数据库进行查询,那我们还可以做得更好:为什么不设计一个真的数据库实例作为数据库而非使用一个简单的基于文件的、无服务器的SQLite测试后台呢?