有時(shí)候你在做 Python 數(shù)據(jù)分析的時(shí)候,可能會(huì)出現(xiàn)這么個(gè)情況:用 Pandas 打開一個(gè)超大型數(shù)據(jù)集,想得到一些度量(metrics),然后就尷尬地卡住了。
大家都知道,如果你處理大數(shù)據(jù),手里用的是 Pandas,有時(shí)要等上一小時(shí)才能得到一個(gè) Series 的平均值,甚至都還沒調(diào)用 apply 函數(shù)。這還只是幾百萬行啊,如果是幾十億行,那最好還是用 Spark 之類的高級(jí)工具吧。
那么就沒有好辦法了嗎?有的,就有這么一個(gè)工具,能夠加速 Python 數(shù)據(jù)分析,既不需要你使用配置更高的硬件設(shè)施,也不必切換編程語言。當(dāng)然,如果你的數(shù)據(jù)集超級(jí)超級(jí)大,它的最終作用也會(huì)有限,但比普通的 Python 擴(kuò)展工具好多了。特別是如果你不用做大量的重建索引,那么這個(gè)工具非常適合你。
這個(gè)工具叫 Dask,數(shù)據(jù)科學(xué)家 Luciano Strika 專門試用了這個(gè)工具,并做了測(cè)試,發(fā)現(xiàn) Dask 在做并行數(shù)據(jù)分析時(shí),比常規(guī) Pandas 快出許多倍。
什么是Dask?
Dask 是一個(gè)開源項(xiàng)目,能提供 NumPy Arrays,Pandas Dataframes 和常規(guī)列表的抽象,允許你使用多核處理并行運(yùn)行它們。
下面這段直接摘自教程:
Dask 提供模仿了 NumPy,列表和 Pandas 的高級(jí) Array,Bag 以及 DataFrame 集合,但能夠在無法放入主內(nèi)存的數(shù)據(jù)集上并行運(yùn)行。對(duì)大型數(shù)據(jù)集來說,Dask 的高級(jí)集合是 NumPy 和 Pandas 的替代方案。
聽起來真不錯(cuò)!于是我(作者Luciano Strika)決定親自試試 Dask Dataframes,并對(duì)它們進(jìn)行了幾個(gè)基準(zhǔn)測(cè)試。
閱讀文檔
我首先閱讀了官方文檔,看看建議我們使用 Dask 做哪些工作。以下是官方文檔(docs.dask.org/en/latest)中的相關(guān)部分:
- 操縱大型數(shù)據(jù)集,即使這些數(shù)據(jù)集無法放入內(nèi)存
- 使用許多核來加速長(zhǎng)計(jì)算
- 使用標(biāo)準(zhǔn)Pandas操作(如 groupby,join 和時(shí)間序列計(jì)算)對(duì)大型數(shù)據(jù)集進(jìn)行分布式計(jì)算
然后在下面,它列出了一些如果使用 Dask Dataframes 會(huì)快速完成的事情:
- 算術(shù)運(yùn)算(乘以或添加到Series)
- 常見聚合(平均值,最小值,最大值,求和等)
- 調(diào)用 apply(只要它在索引中,也就是說,不是在 groupby('y')之后'y'不是索引)
- 調(diào)用 value_counts(),drop_duplicates()或corr()
- 使用 loc,isin 和行式選擇進(jìn)行過濾
如何使用 Dask Dataframes
Dask Dataframes 與 Pandas Dataframes 具有相同的 API,只是聚合和 apply 函數(shù)延遲執(zhí)行,并且需要通過調(diào)用 compute 方法來計(jì)算。要想生成 Dask Dataframe,可以像在 Pandas 中一樣調(diào)用 read_csv 方法,或者,如果給出 Pandas Dataframe df,只需調(diào)用
<pre class="ql-align-justify" style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">dd = ddf.from_pandas(df, npartitions=N)
</pre>
其中 ddf 是你導(dǎo)入 Dask Dataframes 的名稱,而 npartitions 是一個(gè)參數(shù),告訴 Dataframe 如何對(duì)其進(jìn)行分區(qū)。
根據(jù) StackOverflow 上的說法,建議將 Dataframe 劃分為與計(jì)算機(jī)核數(shù)數(shù)量相同的分區(qū),或者是該數(shù)量的幾倍,因?yàn)槊總€(gè)分區(qū)將在不同的線程上運(yùn)行。如果分區(qū)過多,它們之間的通信代價(jià)會(huì)高很多。
動(dòng)手吧:做點(diǎn)基準(zhǔn)測(cè)試
我寫了一個(gè) Jupyter notebook 試用這個(gè)框架,在 GitHub 上能看到,可以自己運(yùn)行一下:github.com/StrikingLoo/
我運(yùn)行的基準(zhǔn)測(cè)試可以在 Github 上的 Jupyter notebook 中找到,主要有以下要點(diǎn):
這里df3是一個(gè)常規(guī)的 Pandas Dataframe,擁有 2500 萬行,使用這段腳本生成,其中列是名稱,姓氏和薪水,從列表中隨機(jī)抽樣。我用了一個(gè)有 50 行的數(shù)據(jù)集并連接了 500000 次,因?yàn)槲覍?duì)分析本身并不太感興趣,但運(yùn)行它時(shí)才會(huì)。
dfn 就是基于 df3 的 Dask Dataframe。
第一批結(jié)果:不太樂觀
我首先嘗試使用 3 個(gè)分區(qū)進(jìn)行測(cè)試,因?yàn)槲业碾娔X只有 4 個(gè)內(nèi)核,不想過度使用它。這次使用 Dask 的結(jié)果非常差,而且還要等很久才能得到結(jié)果,不過我懷疑這可能是分區(qū)過少的原因:
可以看到在我使用 Dask 時(shí)大多數(shù)操作變慢了很多。這給了我一些啟示,可能必須使用更多分區(qū)才行。產(chǎn)生延遲計(jì)算所花的成本也可以忽略不計(jì)(在某些情況下不到半秒),所以如果重復(fù)使用它,成本不會(huì)隨著時(shí)間推移而攤銷。
我還用 apply 方法嘗試了這個(gè)測(cè)試:
并有非常相似的結(jié)果:
因此,一般來說,大多數(shù)操作的速度都是初始操作的兩倍,盡管過濾器的速度要快得多。我覺得或許應(yīng)該在上面調(diào)用 compute,所以對(duì)這個(gè)結(jié)果持保留態(tài)度。
更多分區(qū):加速驚人
得到前面這些不盡人意的結(jié)果之后,我決定我可能只是沒有使用足夠的分區(qū)。畢竟,整件事情的重點(diǎn)是并行運(yùn)行,所以或許我只需進(jìn)一步并行化?所以我嘗試了 8 個(gè)分區(qū)的相同測(cè)試,得到了如下結(jié)果(省略了非并行數(shù)據(jù)幀的結(jié)果,因?yàn)樗鼈兓鞠嗤?/p>
這就對(duì)了!大多數(shù)操作的運(yùn)行速度比常規(guī) Dataframe 快十倍,甚至 apply 的運(yùn)行速度也更快了!我還運(yùn)行了 value_count 測(cè)試,它只調(diào)用“薪水”Series 上的 value_count 方法。對(duì)于上下文,在我足足等 10 分鐘后在常規(guī) Dataframe 上運(yùn)行此測(cè)試時(shí),必須終止該過程。這次只用了 50 秒!
所以之前都沒用對(duì)工具,它的速度可比常規(guī) Dataframe 快多了。
最后再說一點(diǎn)
鑒于我是在一臺(tái)相當(dāng)舊的 4 核 PC 上運(yùn)行了 2500 萬行數(shù)據(jù),所以是相當(dāng)了不起的。所以我的建議是,下回你必須在本地或從單個(gè) AWS 實(shí)例上理數(shù)據(jù)集時(shí),一定要試試 Dask 這個(gè)框架。運(yùn)行速度簡(jiǎn)直不要太快。