Dask的Merge操作性能对比

标签:#dask##python##分布式计算# 时间:2020/05/24 18:32:52 作者:小木

在前面的博客中,我们已经对Dask做了一点简单的介绍了,在这篇博客中我们来对比一下DaskDataFrame在不同条件下的运算性能,主要是连接操作的性能(merge)。

Dask中的DataFrame实际是多个pandas的DataFrame的集合,merge操作是最常见的操作之一。但是,不同情况下的merge操作对性能的影响很大。本节主要考虑以下因素来比较连接操作的性能。

1、DataFrame中列的数量
2、join的字段是否是index
3、join的字段是整形还是字符串
4、DataFrame中partition的数量
5、关联的列是否有序

这篇博文中的项目已经在Github中释放了,链接如下:
https://github.com/df19900725/datalearner_python_exp

为了对比,我们用generate_table_data.py来生成数据。

一、列的数量的影响

Dask可以读取文件夹下所有的文件,但是,你也可以选择读取所有的列,还是读取指定的列。这里我们生成两个数据:

第一个数据是10个文件,每个文件有100,0000行,每一行有50个字段。
第二个数据是2个文件,每个文件500,0000行,每一行是5个字段。

我们使用如下语句进行关联:

  1. df3 = df1.merge(df2, on="id", how="left")
  2. df3.to_csv(output_dir)

最后发现,读取所有的字段进行关联需要947秒,而仅仅读取2个字段进行关联只需要69秒。因此,尽量只读取你需要的数据进行关联,这将加快你的处理速度。

二、join的字段是否被设置成index

通常情况下,DataFrame格式的数据包含了index,也就是每一行的行名,index可以是根据需要生成的行号,也可以是指定的某一列,如ID列作为index。关联的时候,是以index进行关联还是以某一列关联效率是不同的。因为Dask中设置了index之后,这一列的数据将会进行排序和分割,形成不同的divisions,divisions包括每个partition索引的最小值和最后一个partition索引的最大值。这对关联和group都很有帮助。

在这个实验中,我们做了如下几个实验,注意,这些数据集的ID都是排序好的,同时,数据二,也就是要关联的数据的index设置与数据一是保持一致的:

实验组 数据 文件数 字段数 文件行数 字段类型 index 耗时(秒)
实验一 数据集一 1 10 1000,0000 string N 72
实验一 数据集一 1 10 1000,0000 string Y 57
实验一 数据集二 2 5 50,0000 string \ \
实验二 数据集一 1 10 1000,0000 integer N 54
实验二 数据集一 1 10 1000,0000 integer Y 33
实验二 数据集二 2 5 500000 integer \ \
实验三 数据集一 10 10 100,0000 string N 66
实验三 数据集一 10 10 100,0000 string Y 53
实验三 数据集二 2 5 50,0000 string \ \
实验四 数据集一 10 10 100,0000 integer N 43
实验四 数据集一 10 10 100,0000 integer Y 30
实验四 数据集二 2 5 500000 integer \ \

从以上四组实验中我们都可以发现,不管在什么情况下,把要关联的字段设置为index会加速关联的处理。

三、关联的字段是整型还是字符串

关联的时候需要设置以那一列关联,或者是以index关联,这一列的类型是字符串还是整型也将影响关联的效率。还是上述四组实验,我们更换一下对比的顺序:

实验组 数据 文件数 字段数 文件行数 字段类型 index 耗时(秒)
实验一 数据集一 1 10 1000,0000 string N 72
实验一 数据集一 1 10 1000,0000 integer N 54
实验一 数据集二 2 5 50,0000 \ N \
实验二 数据集一 1 10 1000,0000 string Y 57
实验二 数据集一 1 10 1000,0000 string Y 33
实验二 数据集二 2 5 500000 integer Y \
实验三 数据集一 10 10 100,0000 string N 66
实验三 数据集一 10 10 100,0000 integer N 43
实验三 数据集二 2 5 50,0000 string Y \
实验四 数据集一 10 10 100,0000 string Y 53
实验四 数据集一 10 10 100,0000 integer Y 30
实验四 数据集二 2 5 500000 integer Y \

从这四个实验来看,显然关联的列如果是integer类型,它的关联速度要远快于string类型。它的效果甚至比设置index还要好。

四、DataFrame中的partition数量

Dask中DataFrame的partition数量也会影响关联的速度,一般来说,单个文件如果能被放到内存中,那么几个文件读取就会有几个partition。在上述实验中我们也可以看到,partition的数量适当多一点也会加快运行的速度。但是这也不是绝对的。当partition数量过多的时候,也会消耗调度的资源。因此,分布式情况下,这种情况需要慎重考虑,官方推荐一般一个partition的大小为100MB最合适。但实际我们使用发现不一定,32MB有时候也很好。

五、关联的列是否有序

上述实验都是在有序的ID情况下进行关联得到的结果。但实际上很多时候未必ID是有序的。我们也构造了一个乱序的数据集。实验如下:

实验组 数据 文件数 字段数 文件行数 字段类型 index 有序 耗时(秒)
实验一 数据集一 10 10 100,0000 string N N 62
实验一 数据集一 10 10 100,0000 string N Y 66
实验一 数据集二 2 5 50,0000 string N \
实验二 数据集一 10 10 100,0000 string Y N 120
实验二 数据集一 10 10 100,0000 string Y Y 53
实验二 数据集二 2 5 500000 string Y \
实验二 数据集一 10 10 100,0000 integer N N 47
实验二 数据集一 10 10 100,0000 integer N Y 43
实验二 数据集二 2 5 500000 integer N \
实验二 数据集一 10 10 100,0000 integer Y N 59
实验二 数据集一 10 10 100,0000 integer Y Y 30
实验二 数据集二 2 5 500000 integer Y \

如上表所示,当关联的字段是index的时候,乱序要比有序慢很多,但如果是其他的列,那么乱序并不比排序的结果慢。这个应该是由于乱序的话设置index是需要时间的。

六、总结

根据这些实验其实我们也可以看到,如果希望提高dask的merge效率,有几个比较值得操作的是将关联的字段尽量设置为整型的字段,整型的列对关联的效率的提升非常有帮助,其次是要将关联的列设置为index,这会提高dask对dataframe的理解,进而提升关联的速度,最后,还是最好将数据排个序,虽然这是比较耗时的,但对于merge的提升也是客观的。

欢迎大家关注DataLearner官方微信,接受最新的AI技术推送
Back to Top