從分塊到並行:Dask使Pandas運行更快

當內存無法容納數據時,可以使用數據分塊的方法:以數據塊的形式分批加載到內存進行處理。這樣就可以通過加載數據集的子集,來逐步處理整個數據集。

但是,雖然分塊可以節省內存,但它並不能解決處理海量數據的另一個問題:計算力。

怎樣才能加快數據的處理速度呢?

一種方法是利用多個CPU:現在,幾乎每臺電腦都有一個以上的CPU。如果是2個cpu,那麼通常可以(幾乎)以2倍的速度運行代碼;若是4個cpu,那麼將獲得4倍的加速,以此類推。


另一種方法是利用數據分塊技術。它不但有助於減少內存的使用量,還可以支持並行。讓我們先了解一下其原理,然後在學習dask庫是如何實現並行的。


快速的回顧一下:數據分塊


在上一篇中,我們討論了怎樣通過按數據塊來加載數據集以減少內存開銷的方法,並演示瞭如何使用MapReduce 模式來構造代碼。

在這個例子中,我們嘗試計算出每個政黨在每一條街道上的選民數量:

從分塊到並行:Dask使Pandas運行更快

以數據塊處理數據的一個關鍵要求是:相關函數可以獨立運行。在上面的這個例子中,我們可以獨立的計算出某個數據塊中選民的數量,而不需要依賴於其它任何數據塊。

如果可以獨立的處理這些數據塊,那麼就意味著我們可以並行的處理多個數據塊。利用電腦的多個CPU,加快運算速度!稍加思考就會發現,減少相加運算的步驟,依然能保持運算的獨立性,當然就可以並行化運行:

A+B+C+D=(A+B)+(C+D)

那麼如何以最少的工作量實現並行呢?


Dask:一個並行處理庫

以可伸縮的方式做到並行的最簡單方法之一是使用Dask庫,這是一種適用於Python的靈活並行計算庫。

在許多其他功能中,Dask提供了一個模擬Pandas的API,<同時透明地實現了分塊和並行化


由於所有有難度的工作都由Dask來完成,所以我們可以更輕鬆的開始工作。具體來說,我們將不使用數據分塊,而是切換到Pandas代碼,該代碼可將所有數據整體加載到內存中:

從分塊到並行:Dask使Pandas運行更快

這當然不是理想的:它僅使用一個CPU,並且我們需要一次將所有數據加載到內存中。峰值內存使用情況如下所示:


從分塊到並行:Dask使Pandas運行更快


使用Dask庫模仿pandas的工作方式


Dask的工作方式包括兩個步驟:

  • 首先,設置一個計算任務,內部表示為操作圖。
  • 然後,在該圖上進行實際的計算。

當Dask模擬Pandas API時,它實際上並沒有計算任何東西。相反,它會記住您將要執行的第一步操作。僅在運行compute()命令之後,實際工作才會發生。

看起來很相似的代碼,但是幕後卻實現了數據分塊和並行化。

這是我們如何使用Dask進行此計算:

從分塊到並行:Dask使Pandas運行更快

請注意,大多數代碼未更改!但是,正如我們將看到的,執行時間更快,內存使用也更低:


從分塊到並行:Dask使Pandas運行更快


Dask(通常)使工作變得更輕鬆


簡單的讀取所有數據的panda代碼和Dask代碼非常相似。那麼,怎樣比較它們在內存使用上和在runtime上,以及在不採用多線程的情況下使用數據塊的方式加載數據上的差別呢?

從分塊到並行:Dask使Pandas運行更快


(如果您不知道wallclock和CPU時間之間的區別,請參閱本文了解詳細信息)。


一般來說,簡單版本在內存使用和CPU時間方面做得最差。CPU時間可能會稍差一些,因為它使用的算法無法在非常大的數據塊上很好地工作:分塊和Dask庫都是在更小的數據塊上工作。

分塊的版本佔用的內存最少,但是wallclock時間也好不到哪裡去。

Dask庫使用的內存比簡單版本少得多,並且完成得最快(假設您有多個CPU)。


當然,Dask庫並不是萬靈藥:

並行性有開銷,它不會總是讓事情完成得更快。而且它不會減少CPU時間,所以如果cpu負載已經飽和,它將不會提高wallclock時間。

需要進行一些調優。

更大的數據塊增加了內存的使用量,但是在一定程度上也增加了處理速度。

如果待處理任務足夠簡單或快速,單線程的pandas可能更快。


對於處理海量數據的緩慢任務,絕對應該嘗試Dask庫。正如您所看到的,它只需要對現有的panda代碼進行非常小的更改,就可以以更低的內存開銷獲得更快的運行速度。


英文原文:
https://pythonspeed.com/articles/faster-pandas-dask/
譯者:sky


分享到:


相關文章: