有时你用Python的Pandas打开一个大数据集,尝试获得一些指标,整个事情只是可怕地冻结。
如果您使用大数据,您知道如果您正在使用Pandas,那么您可以等待一小段时间来获得一个简单的系列平均值,让我们甚至不会调用apply。这只是几百万行!当你达到数十亿美元时,你最好开始使用Spark或其他东西。
我不久前发现了这个工具:一种加速Python数据分析的方法,无需获得更好的基础设施或切换语言。如果您的数据集很大,它最终会感觉有限,但它比普通的Pandas更好地扩展,并且可能只适合您的问题 - 特别是如果您没有进行大量的重建索引。
Dask是一个开源项目,它为您提供NumPy Arrays,Pandas Dataframes和常规列表的抽象,允许您使用多核处理并行运行它们。
以下是教程中的摘录:
Dask提供模仿NumPy,列表和Pandas的高级Array,Bag和DataFrame集合,但可以在不适合主内存的数据集上并行运行。Dask的高级集合是大型数据集的NumPy和Pandas的替代品。
它听起来真棒!我开始为这篇文章尝试Dask Dataframes,并对它们进行了几个基准测试。
我首先做的是阅读官方文档,看看在Dask中建议做什么而不是常规的Dataframes。以下是官方文档中的相关部分:
然后在下面,它列出了一些在使用Dask Dataframes时非常快的事情:
#仅通过引用返回x> 5的行(写入它们会改变原始df)
df2 = df.loc[df['x'] > 5]
#通过引用仅返回x为0,1,2,3或4的行
df3 = df.x.isin(range(4))
#只返回x> 5的行,只读参考(无法写入)
df4 = df[df['x']>5]
Dask Dataframes与Pandas Dataframes具有相同的API,除了聚合和apply s被懒惰地评估,并且需要通过调用compute方法来计算。为了生成Dask Dataframe,您可以像在Pandas中一样调用read_csv方法,或者,如果给出Pandas Dataframe df,您只需调用
dd = ddf.from_pandas(df,npartitions = N)
其中ddf是您导入Dask Dataframes的名称,而npartitions是一个参数,告诉Dataframe如何对其进行分区。
根据StackOverflow的说法,建议将Dataframe划分为与计算机所拥有的核心数量相同的分区,或者是该数量的几倍,因为每个分区将在不同的线程上运行,如果有的话,它们之间的通信将变得过于昂贵许多。
我制作了一个Jupyter笔记本来试用这个框架,并在Github上提供它,以防你想要检查它甚至自己运行它。
我运行的基准测试可以在Github的笔记本中找到,但主要有:
def get_big_mean():
return dfn.salary.mean().compute()
def get_big_mean_old():
return df3.salary.mean()
def get_big_max():
return dfn.salary.max().compute()
def get_big_max_old():
return df3.salary.max()
def get_big_sum():
return dfn.salary.sum().compute()
def get_big_sum_old():
return df3.salary.sum()
def filter_df():
df = dfn[dfn['salary']>5000]
def filter_df_old():
df = df3[df3['salary']>5000]
这里df3是一个普通的Pandas Dataframe,拥有2500万行,使用上一篇文章中的脚本生成(列是名称,姓氏和薪水,从列表中随机抽样)。我拿了50行数据集并连接了500000次,因为我对分析本身并不太感兴趣,但只是在运行它的时候。
dfn就是基于df3的Dask Dataframe 。
我首先尝试使用3个分区进行测试,因为我只有4个内核,并且不想过度使用我的PC。我和Dask的结果非常差,并且还要等很多才能得到它们,但我担心这可能是因为我制作的分区太少了:
204.313940048 seconds for get_big_mean 39.7543280125 seconds for get_big_mean_old
131.600986004 seconds for get_big_max 43.7621600628 seconds for get_big_max_old
120.027213097 seconds for get_big_sum 7.49701309204 seconds for get_big_sum_old
0.581165790558 seconds for filter_df 226.700095892 seconds for filter_df_old
当我使用Dask时,您可以看到大多数操作变得慢得多。这给了我一些暗示我可能不得不使用更多分区。产生惰性评估所花费的金额也可以忽略不计(在某些情况下不到半秒),所以如果重复使用它,它就不会随着时间的推移而摊销。
我也用apply方法尝试了这个测试:
def f(x):
return (13*x+5)%7
def apply_random_old():
df3['random']= df3['salary'].apply(f)
def apply_random():
dfn['random']= dfn['salary'].apply(f).compute()
并有非常相似的结果:
369.541605949 seconds for apply_random 157.643756866 seconds for apply_random_old
因此,一般来说,大多数操作的速度都是原始操作的两倍,尽管过滤器的速度要快得多。我担心也许我应该在那个上调用计算器,所以把这个结果带上一粒盐。
在这些令人沮丧的结果之后,我决定我可能只是没有使用足够的分区。毕竟,这一点的重点是并行运行,所以也许我只需要更多并行化?所以我尝试了8个分区的相同测试,这就是我得到的(我省略了非并行数据帧的结果,因为它们基本相同):
3.08352184296 seconds for get_big_mean 1.3314101696 seconds for get_big_max 1.21639800072 seconds for get_big_sum 0.228978157043 seconds for filter_df
112.135010004 seconds for apply_random 50.2007009983 seconds for value_count_test
那就对了!大多数操作的运行速度比常规Dataframe快十倍,甚至申请速度也更快!我还运行了value_count测试,它只调用salary系列上的value_count方法。对于上下文,请记住,在经过十分钟的等待后,我在常规Dataframe上运行此测试时必须终止该过程。这次只用了50秒! 所以基本上我只是使用错误的工具,而且它非常快。比常规Dataframe快很多。
鉴于我们刚刚在一台相当旧的4核PC上运行了2500万行,我可以看到这在行业中将是多么巨大。所以我的建议是在下次必须在本地或从单个AWS实例处理数据集时尝试此框架。这很快。
原文:https://towardsdatascience.com/trying-out-dask-dataframes-in-python-for-fast-data-analysis-in-parallel-aa960c18a915