许多组织都试图收集和利用尽可能多的数据,以改进他们如何经营业务、增加收入或如何影响周围的世界。因此,数据科学家面对50GB甚至500GB大小的数据集的情况变得越来越普遍。
现在,这些数据集使用起来有点…不舒服。它们小到可以装进你日常使用的笔记本电脑的硬盘,但大到可以装进内存。因此,它们已经很难打开和检查,更不用说探索或分析了。
在处理这样的数据集时,通常采用3种策略。第一种是对数据进行子抽样。这里的缺点是显而易见的:一个人可能会因为不看相关部分而错过关键的洞见,或者更糟的是,不看全部内容可能会曲解故事和它所讲述的数据。下一个策略是使用分布式计算。虽然在某些情况下这是一种有效的方法,但是它带来管理和维护集群的巨大开销。想象一下,必须为一个刚好超出RAM范围的数据集设置一个集群,比如在30 - 50gb范围内。对我来说,这似乎太过分了。另一种选择是,可以租用一个强大的云实例,该实例的内存与处理相关数据所需的内存一样多。例如,AWS提供了具有tb内存的实例。在这种情况下,您仍然需要管理云数据桶,等待每次实例启动时从桶到实例的数据传输,处理将数据放到云上所带来的遵从性问题,以及处理在远程机器上工作所带来的所有不便。更不用说成本了,虽然开始时很低,但随着时间的推移,成本会逐渐增加。
在本文中,我将向您展示一种新的方法:一种更快速、更安全、更全面、更方便的方法,可以使用几乎任意大小的数据进行数据科学研究,只要它能适合您的笔记本电脑、台式机或服务器的硬盘驱动器即可。
Vaex
Vaex是一个开源的DataFrame库,它可以在与硬盘大小相同的表格数据集上进行可视化、探索、分析甚至机器学习。为此,Vaex采用了内存映射、高效的外核算法和延迟计算等概念。所有这些都封装在一个熟悉的类似
pandas的API中,因此任何人都可以立即开始。
亿辆出租车的分析
为了说明这一概念,让我们对一个数据集进行简单的探索性数据分析,该数据集非常大,无法容纳典型的笔记本电脑的RAM。在本文中,我们将使用纽约市出租车数据集,该数据集包含了标志性的黄色出租车在2009年至2015年间超过10亿次出租车运行的信息。数据可从
本网站下载,并以CSV格式提供。完整的分析可以在这个
Jupyter notebook中单独查看。
清扫街道
第一步是将数据转换为内存映射文件格式,如Apache Arrow、Apache Parquet或HDF5。在这里可以找到如何将CSV数据转换为HDF5的示例。一旦数据是内存映射格式,使用Vaex打开它是瞬间的(0.052秒!),尽管磁盘上的容量超过100GB:
[caption id="attachment_48074" align="aligncenter" width="1341"]
使用Vaex打开内存映射文件是即时的(0.052秒!),即使它们超过100GB大。[/caption]
为什么这么快?当您使用Vaex打开内存映射文件时,实际上没有数据读取。Vaex只读取文件元数据,比如磁盘上数据的位置、数据结构(行数、列数、列名和类型)、文件描述等等。那么,如果我们想要检查或与数据交互呢?打开一个数据集的结果是一个标准的数据aframe和检查它是一样快,因为它是琐碎的:
[caption id="attachment_48075" align="aligncenter" width="1340"]
纽约市黄色出租车数据预览[/caption]
再次注意,单元执行时间非常短。这是因为显示Vaex DataFrame或列只需要从磁盘读取前5行和后5行。这就引出了另一个重要的问题:Vaex只会在必要时遍历整个数据集,而且它会尽可能少地传递数据。
无论如何,让我们首先从极端异常值或错误的数据输入中清理这个数据集开始。一种好的开始方法是使用describe方法获得数据的高级概览,该方法显示了样本的数量、缺失值的数量和每个列的数据类型。如果列的数据类型是numerical,则还将显示平均值、标准偏差以及最小值和最大值。所有这些统计数据都是通过一次数据传递计算的。
[caption id="attachment_48078" align="aligncenter" width="1340"]
使用“describe”方法获得数据帧的高级概述。注意,DataFrame包含18列,但在此屏幕截图中只有前7列可见。[/caption]
describe方法很好地说明了Vaex的能力和效率:所有这些统计数据都是在我的MacBook Pro(15英寸,2018年,2.6GHz Intel Core i7, 32GB RAM)上3分钟内计算出来的。其他库或方法需要分布式计算或超过100GB的云实例才能完成相同的计算。有了Vaex,你所需要的只是数据,和你的笔记本电脑只有几GB的内存。
查看description的输出,很容易注意到数据包含一些严重的异常值。首先,让我们从检查取货地点开始。删除异常值的最简单方法是简单地绘制出上下车的位置,并直观地定义我们希望重点分析的纽约市的区域。由于我们使用的是如此大的数据集,直方图是最有效的可视化方法。用Vaex创建和显示柱状图和热图是如此的快,这样的图可以是交互式的!
df.plot_widget(df.pickup_longitude,
df.pickup_latitude,
shape=512,
limits='minmax',
f='log1p',
colormap='plasma')
一旦我们交互式地决定我们想要关注纽约市的哪个区域,我们可以简单地创建一个过滤后的数据aframe:
上面代码块最酷的地方是它需要的内存可以忽略不计!过滤Vaex数据帧时,不会生成数据的副本。相反,只创建对原始对象的引用,并在其上应用二进制掩码。掩码选择显示哪些行并用于将来的计算。这为我们节省了100GB的RAM,如果要复制数据,就像今天许多标准的数据科学工具所做的那样。
现在,让我们检查一下乘客计数栏。在一次出租车行程中记录的乘客人数最多为255人,这似乎有点极端。让我们计算一下每一位乘客的运行次数。这是很容易做到的value_counts方法:
应用于10亿行的“value_counts”方法只需要~20秒!
从上图中我们可以看出,乘客超过6人的运行很可能是罕见的异常值,或者只是数据输入错误。也有大量的运行是0名乘客。既然现在我们还不知道这些数据是否合法,那就让我们把它们过滤掉吧。
让我们做一个关于运行距离的类似练习。由于这是一个连续变量,我们可以绘制行程的分布。看最小值(负数!)和最大(比火星更远!)的距离,让我们用一个更合理的范围来绘制直方图。
[caption id="attachment_48083" align="aligncenter" width="1344"]
纽约出租车数据集的行程距离直方图。[/caption]
从上面的图表我们可以看出,运行次数随着距离的增加而减少。在大约100英里的距离上,分布有一个很大的下降。目前,我们将使用此作为截止点,以消除基于行程距离的极端异常值:
在运行距离列中存在极端异常值,可以作为调查出租车运行时长和平均速度的动机。这些特性在数据集中不易获得,但计算起来却很简单:
上面的代码块需要零内存,不需要时间执行!这是因为代码导致创建虚拟列。这些列仅包含数学表达式,并且仅在需要时计算。否则,虚拟列的行为与任何其他常规列一样。请注意,其他标准库在相同的操作中需要10GB的RAM。
好吧,我们来绘制运行时间的分布图:
[caption id="attachment_48086" align="aligncenter" width="1343"]
纽约10亿多次出租车运营持续时间的直方图。[/caption]
从上面的图中我们可以看到95%的出租车旅行都不到30分钟就能到达目的地,尽管有些旅程可以花费4到5个小时。你能想象在纽约被困在出租车里超过3个小时吗?不管怎样,让我们开诚布公,考虑一下总共持续不到3小时的所有行程:
现在让我们调查出租车的平均速度,同时也为数据限制选择一个合理的范围:
[caption id="attachment_48088" align="aligncenter" width="1342"]
平均出租车速度的分布。[/caption]
根据分布趋平的地方,我们可以推断出合理的出租车平均速度在每小时1到60英里之间,因此我们可以更新过滤后的DataFrame:
让我们把注意力转移到出租车运营成本上。从describe方法的输出中,我们可以看到fare_amount、total_amount和tip_amount列中有一些异常值。首先,这些列中的任何值都不应为负。与此相反,这些数字表明,一些幸运的司机几乎成了百万富翁。让我们看看这些量的分布,但在一个相对合理的范围内:
[caption id="attachment_48092" align="aligncenter" width="1342"]
纽约10亿多个出租车出行的票价、总金额和小费的分布情况。在笔记本电脑上创建这些图只用了31秒![/caption]
我们看到上面的三个分布都有相当长的尾部。尾部的一些值可能是正确的,而其他值可能是错误的数据输入。无论如何,现在我们还是保守一点,只考虑票价、总票价和小费低于200美元的乘车。我们还要求票价金额、总金额值大于0美元。
最后,在对数据进行了所有的初始清理之后,让我们看看还有多少出租车行程可供我们分析:
我们还有超过11亿次的行程!这些数据足以让我们对出租车行程有一些有价值的见解。
坐进驾驶座
假设我们是一个未来的出租车司机,或出租车公司的经理,并有兴趣使用这个数据集来学习如何最大限度地提高我们的利润,降低我们的成本,或者只是改善我们的工作生活。
让我们先找出平均来说能带来最好收益的接送乘客的地点。天真地说,我们可以画出一张接客地点的热图,用平均票价编码,然后看看热点地区。然而,出租车司机自己也有成本。例如,他们得付燃料费。因此,把乘客带到很远的地方可能会导致更大的票价,但这也意味着更大的油耗和时间损失。此外,要从那个偏远的地方找到一个乘客去市中心的某个地方可能不那么容易,因此没有乘客的情况下开车回去可能会很昂贵。一种解释方法是用车费和行程距离之比的平均值对热图进行颜色编码。让我们考虑这两种方法:
[caption id="attachment_48100" align="aligncenter" width="1341"]
纽约市彩色热图编码:平均票价金额(左)和票价金额与行程的平均比率。[/caption]
在幼稚的情况下,当我们只关心为提供的服务获得最大票价时从纽约机场、以及范怀克(Van Wyck)高速公路和长岛(Long Island)高速公路等主要道路上搭载乘客的最佳区域是纽约机场。当我们考虑行程的距离时,我们得到的图像略有不同。范怀克(Van Wyck)高速公路、长岛(Long Island)高速公路大道以及机场仍然是搭载乘客的好地方,但它们在地图上的重要性要低得多。然而,在哈德逊河的西侧出现了一些新的热点地区,看起来利润颇丰。
出租车司机是一份相当灵活的工作。为了更好地利用这种灵活性,除了知道开车应该躲在什么地方之外,知道什么时候开车最赚钱也是很有用的。为了回答这个问题,让我们制作一个图表,显示每天和每小时的平均票价与旅行距离之比:
[caption id="attachment_48101" align="aligncenter" width="1340"]
票价与每周每天行程距离和每天小时的平均比率。[/caption]
上面的数字是合理的:最好的收入发生在高峰时间,特别是中午,在工作日。作为一名出租车司机,我们收入的一部分给了出租车公司,所以我们可能会对哪一天、哪段时间顾客给的小费最多感兴趣。让我们制作一个类似的图表,这次显示的是平均小费比例:
[caption id="attachment_48102" align="aligncenter" width="1341"]
每周每天和每天小时的平均小费百分比。[/caption]
上面的情节很有趣。它告诉我们,乘客在早上7点到10点之间和在本周早些时候的晚上给出租车司机小费。如果你在凌晨3点或4点接乘客,不要指望会有丰厚的小费。结合上两个部分的分析,早上8点到10点是上班的好时间:一个人每英里可以得到一个好的车费和一个好的小费。
原文链接:https://towardsdatascience.com/how-to-analyse-100s-of-gbs-of-data-on-your-laptop-with-python-f83363dda94