2021年您是否还在使用Pandas处理大数据?

图片

图片
NASA在Unsplash上拍摄的照片

我最近写了两篇有关使用Dask和Vaex处理大数据的介绍性文章,这两个库都能用于处理大于内存的数据集。在写那两片文章时,我想到一个问题:

这些库真的可以处理比内存更大的数据集吗?还是仅仅是销售口号?

这就促使我对Dask和Vaex进行了实际实验,并尝试处理比内存数据集更大的数据。这些数据集非常大到无法使用Pandas打开它。

**

我所说的大数据是什么?

图片
照片由EV上Unsplash

大数据是一个松散定义的术语, 其定义甚至与Google的点击次数一样多。在本文中,我用这个术语来描述一个庞大的数据集,以至于我们需要专门的软件来处理它。对于Big,我指的是“比一台机器上的主内存更大”。

来自维基百科的定义:

大数据是一个领域,它研究处理分析、系统地从数据中提取信息方法,或以某种方式处理过大或复杂的数据集的方式。这些数据集无法由传统的数据处理应用软件处理。

什么是Dask和Vaex?

图片
照片由JESHOOTS.COM上Unsplash

Dask提供了高级并行性的分析方法,可大幅提高您日常喜欢的工具性能。其中包括numpy,pandas和sklearn。它是开源的,免费提供。它使用现有的Python API和数据结构来,简化了在Dask和类似工具软件之间切换到麻烦。

Vaex是一个高性能Python库,用于Lazy Out-of-Core DataFrame(类似于Pandas),可以用来可视化和探索大型表格数据集。它可以计算每秒超过十亿行的基本统计信息。它支持多种可视化,允许交互式探索大数据。

Dask和Vaex数据框与Pandas数据框不完全兼容,但是两种工具都支持某些最常见的“数据整理”操作。Dask更善于集群计算,而Vaex使在单台计算机上处理大型数据集更加容易。

测试

图片
Louis Reed在Unsplash上拍摄的照片

我已经生成了两个具有100万行和1000列的CSV文件。文件大小为18.18 GB,总共36.36 GB。文件具有0到100之间均匀分布的随机数。

图片

两个带有随机数据的CSV文件

import pandas as pd
import numpy as np
from os import path
n_rows = 1_000_000
n_cols = 1000
for i in range(1, 3):
    filename = 'analysis_%d.csv' % i
    file_path = path.join('csv_files', filename)
    df = pd.DataFrame(np.random.uniform(0, 100, size=(n_rows, n_cols)), columns=['col%d' % i for i in range(n_cols)])
    print('Saving', file_path)
    df.to_csv(file_path, index=False)
df.head()

图片

本测试在32 GB主内存的MacBook Pro上运行的,这台电脑的功能相当强大。在测试Pandas数据框的限制时,我惊讶地发现,在这样的机器上触发内存错误是一个很大的挑战!

当内存达到极限时,macOS将数据从主内存转储到SSD。pandas Dataframe的上限是计算机上100 GB的可用磁盘空间。

当Mac需要内存时,它将会将当前未使用的内容推送到交换文件中以进行临时存储。当再次需要访问时,它将从交换文件中读取数据并返回到内存中。

我花了一些时间思考如何解决这个问题,这样实验才能公平。我想到的第一个想法是禁用交换,以便每个库仅具有可用的主内存。花了几个小时后,我无法禁用交换功能。

第二个想法比较野蛮。我事先将SSD填满,使得操作系统无法使用交换功能,因为设备上已经没有可用空间。

图片

实验期间,您的磁盘几乎已满

这个做法成功了!Pandas无法读取两个18 GB的文件,Jupyter Kernel崩溃了。如果我要再次重复此实验,我将创建一个内存更少的虚拟机。这样,将更容易显示这些工具的局限性。

Dask或Vaex可以帮助我们处理这些大文件吗?哪一个更快?让我们找出答案。

Vaes决战Dask

在这里插入图片描述
Frida Bredesen在Unsplash上拍摄的照片

在设计实验时,我考虑了执行数据分析时的基本操作,例如分组,过滤和可视化数据。我想出了以下操作:

• 计算列的第十个分位数;

• 添加一个新列;

• 按列过滤;

• 按列分组并汇总;

• 可视化列。

以上所有操作都使用单个列执行计算,例如:

# filtering with a single column
df[df.col2 > 10]

因此,我很想尝试一项操作,该操作需要处理所有数据:

• 计算所有列的总和。

这可以通过将计算分解为较小的块来实现。例如。分别读取每一列并计算总和,最后一步计算总和。这些类型的计算问题被称为“令人尴尬的并行” ,因为无需花费任何努力就可以将问题分成单独的任务。

Vaex

图片
照片由照片朗蒂上Unsplash

让我们从Vaex开始。该实验的设计遵循了每种工具的最佳实践:对Vaex使用二进制HDF5格式。因此,我们需要将CSV文件转换为HDF5格式(分层数据格式版本5)。

import glob
import vaex
csv_files = glob.glob('csv_files/*.csv')
for i, csv_file in enumerate(csv_files, 1):
    for j, dv in enumerate(vaex.from_csv(csv_file, chunk_size=5_000_000), 1):
        print('Exporting %d %s to hdf5 part %d' % (i, csv_file, j))
        dv.export_hdf5(f'hdf5_files/analysis_{i:02}_{j:02}.hdf5')

Vaex需要405秒的时间才能将两个CSV文件(36.36 GB)转换为两个HDF5文件,这些文件合计16 GB。从文本格式转换为二进制格式可减小文件大小。

使用Vaex打开HDF5数据集:

dv = vaex.open('hdf5_files/*.hdf5')

Vaex需要1218秒来读取HDF5文件。我预计它会更快,因为Vaex自称可以立即打开二进制格式的文件。

引自Vaex文档:

无论磁盘上的文件大小如何,打开此类数据都是瞬间的:Vaex只会对数据进行内存映射,而不是在内存中读取数据。这是处理大于可用RAM的大型数据集的最佳方式。

Vaex展示头:

dv.head()

Vaex需要1189秒来显示文件头。我不确定为什么显示每列的前5行花了这么长时间。

用Vaex计算第十个分位数:

注意,Vaex具有percentile_approx函数,该函数计算分位数的近似值。

quantile = dv.percentile_approx('col1', 10)

Vaex需要0秒来计算col1列的第十个分位数的近似值。

使用Vaex添加新列:

dv ['col1_binary'] = dv.col1> dv.percentile_approx('col1'10

Vaex具有虚拟列的概念,该表达式将表达式存储为列。它不占用任何内存,并在需要时动态计算。虚拟列的处理方式与普通列相同。如预期的那样,Vaex只要0秒就完成了上述命令。

用Vaex过滤数据:

Vaex有选择的概念,我没有使用过,因为Dask不支持选择,这会使实验不公平。除了Vaex不会复制数据外,下面的过滤器类似于使用Pandas过滤。

dv = dv [dv.col2> 10]

Vaex需要0秒来执行上面的过滤器。

使用Vaex分组和汇总数据:

下面的命令与pandas稍有不同,因为它结合了分组和聚合。该命令将数据按col1_binary分组,并计算col3的平均值:

group_res = dv.groupby(by=dv.col1_binary, agg={'col3_mean': vaex.agg.mean('col3')})

图片

用Vaex计算平均值

Vaex只要0秒来完成上面的命令。

可视化直方图:

可视化大数据对于传统工具而言是个大问题。让我们尝试使用Vaex制作col3的直方图。

plot = dv.plot1d(dv.col3, what='count(*)', limits=[0, 100])

图片

使用Vaex可视化数据

Vaex需要0秒就完成了上图的绘制,快得令人惊讶。

计算所有列的总和

一次处理单个列时,内存不是问题。让我们尝试使用Vaex计算数据集中所有数字的总和。

sum = np.sum(dv.sum(dv.column_names))

Vaex需要40秒来计算所有列的总和。

Dask

图片
照片由凯利期Sikkema上Unsplash

现在,让我们重复上面的操作,但使用Dask。在运行Dask命令之前,Jupyter内核已重新启动。

我们没有使用Dask的read_csv函数直接读取CSV文件,而是将CSV文件转换为HDF5以示公平。

import dask.dataframe as dd
ds = dd.read_csv('csv_files/*.csv')
ds.to_hdf('hdf5_files_dask/analysis_01_01.hdf5', key='table')

Dask进行转换所需的时间为763秒。我试图读取用Vaex转换的HDF5文件,但没有成功。

Dask的最佳做法:

HDF5是具有高性能需求的Pandas用户的通常选择。我们鼓励Dask DataFrame用户改为使用Parquet存储和加载数据。

使用Dask打开HDF5数据集:

import dask.dataframe as dd
ds = dd.read_csv('csv_files/*.csv')

Dask需要0秒来打开HDF5文件。这是因为我没有显式运行compute命令,该命令实际上会读取文件。

Dask展示头:

ds.head()

Dask需要9秒才能输出文件的前5行。

用Dask计算第十个分位数:

Dask具有分位数功能,可以计算实际分位数,而不是近似值。

quantile = ds.col1.quantile(0.1).compute()

Dask无法计算分位数, 因为Juptyter Kernel崩溃了。

使用Dask定义一个新列:

下面的函数使用分位数功能定义一个新的二进制列。Dask无法计算它,因为它使用了分位数。

ds['col1_binary'] = ds.col1 > ds.col1.quantile(0.1)

使用Dask过滤数据:

ds = ds[(ds.col2 > 10)]

由于Dask使用延迟执行方式,因此上面的命令需要0秒才能执行。

使用Dask分组和汇总数据:

group_res = ds.groupby('col1_binary').col3.mean().compute()

Dask无法将数据分组和汇总。

可视化col3的直方图:

plot = ds.col3.compute().plot.hist(bins=64, ylim=(13900, 14400))

Dask无法可视化数据。

计算所有列的总和:

suma = ds.sum().sum().compute()

Dask无法汇总所有数据。

实用结果

下表显示了Vaex vs Dask实验的执行时间。NA表示该工具无法处理数据,Jupyter Kernel崩溃了。

图片
实验中执行时间的摘要

结论

在这里插入图片描述
照片由约书亚金果上Unsplash

Vaex要求将CSV转换为HDF5格式,我对此并不介意,因为您可以去吃午饭,回来后便会转换数据。我也了解在恶劣的条件下(例如在实验中),内存很少时读取数据将花费更长的时间。

我不明白的是为什么Vaex需要1189秒显示文件的头5行!Vaex中的其他操作都经过了最优化,这使我们能够对大于主内存数据集的数据进行交互式数据分析。

我对Dask问题的理解是,它更适合于计算集群而不是单台计算机。Dask建立在Pandas之上,这意味着在Pandas运行缓慢的代码在Dask中运行依然缓慢。

实验的获胜者很明显。Vaex能够处理比笔记本电脑上的主内存文件更大的文件,而Dask则不能。这个实验有局限性,因为我是在单台计算机而不是计算群集上测试性能。

原文链接:https://towardsdatascience.com/are-you-still-using-pandas-to-process-big-data-in-2021-850ab26ad919

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值