Dask的Merge操作性能对比
在前面的博客中,我们已经对Dask
做了一点简单的介绍了,在这篇博客中我们来对比一下Dask
的DataFrame
在不同条件下的运算性能,主要是连接操作的性能(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个字段。
我们使用如下语句进行关联:
df3 = df1.merge(df2, on="id", how="left")
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技术推送
