在 Python中處理大型機器學(xué)習(xí)數(shù)據(jù)集的簡單方法
本文的目標受眾:
- 想要對大量數(shù)據(jù)集執(zhí)行 Pandas/NumPy 操作的人。
- 希望使用Python在大數(shù)據(jù)上執(zhí)行機器學(xué)習(xí)任務(wù)的人。
本文將使用 .csv 格式的文件來演示 python 的各種操作,其他格式如數(shù)組、文本文件等也是如此。
為什么我們不能將 pandas 用于大型機器學(xué)習(xí)數(shù)據(jù)集呢?
我們知道 Pandas 使用計算機內(nèi)存 (RAM) 來加載您的機器學(xué)習(xí)數(shù)據(jù)集,但是,如果您的計算機有8 GB 的內(nèi)存 (RAM),那么為什么 pandas 仍然無法加載 2 GB 的數(shù)據(jù)集呢?原因是使用 Pandas 加載 2 GB 文件不僅需要 2 GB RAM,還需要更多內(nèi)存,因為總內(nèi)存需求取決于數(shù)據(jù)集的大小以及您將在該數(shù)據(jù)集上執(zhí)行的操作。
以下是加載到計算機內(nèi)存中的不同大小的數(shù)據(jù)集的快速比較:
此外,Pandas只使用操作系統(tǒng)的一個內(nèi)核,這使得處理速度很慢。換句話說,我們可以說pandas不支持并行(將一個問題分解成更小的任務(wù))。
假設(shè)電腦有 4 個內(nèi)核,下圖是加載 CSV 文件的時候 pandas 使用的內(nèi)核數(shù):
普遍不使用 pandas 處理大型機器學(xué)習(xí)數(shù)據(jù)集的主要原因有以下兩點,一是計算機內(nèi)存使用量,二是缺乏并行性。在 NumPy 和 Scikit-learn中,對于大數(shù)據(jù)集也面臨同樣的問題。
為了解決這兩個問題,可以使用名為Dask的python庫,它能夠使我們在大型數(shù)據(jù)集上執(zhí)行pandas、NumPy和ML等各種操作。
Dask是如何工作的?
Dask是在分區(qū)中加載你的數(shù)據(jù)集,而pandas通常是將整個機器學(xué)習(xí)數(shù)據(jù)集作為一個dataframe。在Dask中,數(shù)據(jù)集的每個分區(qū)都被認為是一個pandas dataframe。
Dask 一次加載一個分區(qū),因此您不必擔(dān)心出現(xiàn)內(nèi)存分配錯誤問題。
以下是使用 dask 在計算機內(nèi)存中加載不同大小的機器學(xué)習(xí)數(shù)據(jù)集的比較:
Dask 解決了并行性問題,因為它將數(shù)據(jù)拆分為多個分區(qū),每個分區(qū)使用一個單獨的內(nèi)核,這使得數(shù)據(jù)集上的計算更快。
假設(shè)電腦有 4 個內(nèi)核,以下是 dask 在加載 5 GB csv 文件時的方式:
要使用 dask 庫,您可以使用以下命令進行安裝:
pip install dask
Dask 有幾個模塊,如dask.array、dask.dataframe 和 dask.distributed,只有在您分別安裝了相應(yīng)的庫(如 NumPy、pandas 和 Tornado)后才能工作。
如何使用 dask 處理大型 CSV 文件?
dask.dataframe 用于處理大型 csv 文件,首先我嘗試使用 pandas 導(dǎo)入大小為 8 GB 的數(shù)據(jù)集。
import pandas as pd
df = pd.read_csv(“data.csv”)
它在我的 16 GB 內(nèi)存筆記本電腦中引發(fā)了內(nèi)存分配錯誤。
現(xiàn)在,嘗試使用 dask.dataframe 導(dǎo)入相同的 8 GB 數(shù)據(jù)
dask 只用了一秒鐘就將整個 8 GB 文件加載到 ddf 變量中。
讓我們看看 ddf 變量的輸出。
如您所見,執(zhí)行時間為 0.5 秒,這里顯示已劃分為 119 個分區(qū)。
您還可以使用以下方法檢查數(shù)據(jù)幀的分區(qū)數(shù):
默認情況下,dask 將我的 8 GB CSV 文件加載到 119 個分區(qū)(每個分區(qū)大小為 64MB),這是根據(jù)可用的物理內(nèi)存和電腦的內(nèi)核數(shù)來完成的。
還可以在加載 CSV 文件時使用 blocksize 參數(shù)指定我自己的分區(qū)數(shù)。
現(xiàn)在指定了一個字符串值為 400MB 的 blocksize 參數(shù),這使得每個分區(qū)大小為 400 MB,讓我們看看有多少個分區(qū)
關(guān)鍵點:使用 Dask DataFrames 時,一個好的經(jīng)驗法則是將分區(qū)保持在 100MB 以下。
使用以下方法可調(diào)用dataframe的特定分區(qū):
也可通過使用負索引來調(diào)用最后一個分區(qū),就像我們在調(diào)用列表的最后一個元素時所做的那樣。
讓我們看看數(shù)據(jù)集的形狀:
您可以使用 len() 檢查數(shù)據(jù)集的行數(shù):
Dask 已經(jīng)包含了示例數(shù)據(jù)集。我將使用時間序列數(shù)據(jù)向您展示 dask 如何對數(shù)據(jù)集執(zhí)行數(shù)學(xué)運算。
導(dǎo)入dask.datasets后,ddf_20y 加載了從 2000 年 1 月 1 日到 2021 年 12 月 31 日的時間序列數(shù)據(jù)。
讓我們看看我們的時間序列數(shù)據(jù)的分區(qū)數(shù)。
20 年的時間序列數(shù)據(jù)分布在 8035 個分區(qū)中。
在 pandas 中,我們使用 head 打印數(shù)據(jù)集的前幾行,dask 也是這樣。
讓我們計算一下 id 列的平均值。
dask不會打印dataframe的總行數(shù),因為它使用惰性計算(直到需要時才顯示輸出)。為了顯示輸出,我們可以使用compute方法。
假設(shè)我想對數(shù)據(jù)集的每一列進行歸一化(將值轉(zhuǎn)換為0到1之間),Python代碼如下:
循環(huán)遍歷列,找到每列的最小值和最大值,并使用簡單的數(shù)學(xué)公式對這些列進行歸一化。
關(guān)鍵點:在我們的歸一化示例中,不要認為會發(fā)生實際的數(shù)值計算,它只是惰性求值(在需要之前永遠不會向您顯示輸出)。
為什么要使用 Dask 數(shù)組?
Dask 將數(shù)組分成小塊,其中每個塊都是一個 NumPy 數(shù)組。
dask.arrays 用于處理大數(shù)組,以下Python代碼使用 dask 創(chuàng)建了一個 10000 x 10000 的數(shù)組并將其存儲在 x 變量中。
調(diào)用該 x 變量會產(chǎn)生有關(guān)數(shù)組的各種信息。
查看數(shù)組的特定元素
對dask 數(shù)組進行數(shù)學(xué)運算的Python示例:
正如您所看到的,由于延遲執(zhí)行,它不會向您顯示輸出。我們可以使用compute來顯示輸出:
dask 數(shù)組支持大多數(shù) NumPy 接口,如下所示:
- 數(shù)學(xué)運算:+, *, exp, log, ...
- sum(), mean(), std(), sum(axis=0), ...
- 張量/點積/矩陣乘法:tensordot
- 重新排序/轉(zhuǎn)置:transpose
- 切片:x[:100, 500:100:-2]
- 使用列表或 NumPy 數(shù)組進行索引:x[:, [10, 1, 5]]
- 線性代數(shù):svd、qr、solve、solve_triangular、lstsq
但是,Dask Array 并沒有實現(xiàn)完整 NumPy 接口。
你可以從他們的官方文檔中了解更多關(guān)于 dask.arrays 的信息。
什么是Dask Persist?
假設(shè)您想對機器學(xué)習(xí)數(shù)據(jù)集執(zhí)行一些耗時的操作,您可以將數(shù)據(jù)集持久化到內(nèi)存中,從而使數(shù)學(xué)運算運行得更快。
從 dask.datasets 導(dǎo)入了時間序列數(shù)據(jù)
讓我們?nèi)?shù)據(jù)集的一個子集并計算該子集的總行數(shù)。
計算總行數(shù)需要 27 秒。
我們現(xiàn)在使用 persist 方法:
持久化我們的子集總共花了 2 分鐘,現(xiàn)在讓我們計算總行數(shù)。
同樣,我們可以對持久化數(shù)據(jù)集執(zhí)行其他操作以減少計算時間。
persist應(yīng)用場景:
- 數(shù)據(jù)量大
- 獲取數(shù)據(jù)的一個子集
- 對子集應(yīng)用不同的操作
為什么選擇 Dask ML?
Dask ML有助于在大型數(shù)據(jù)集上使用流行的Python機器學(xué)習(xí)庫(如Scikit learn等)來應(yīng)用ML(機器學(xué)習(xí))算法。
什么時候應(yīng)該使用 dask ML?
- 數(shù)據(jù)不大(或適合 RAM),但訓(xùn)練的機器學(xué)習(xí)模型需要大量超參數(shù),并且調(diào)優(yōu)或集成技術(shù)需要大量時間。
- 數(shù)據(jù)量很大。
正如你所看到的,隨著模型大小的增加,例如,制作一個具有大量超參數(shù)的復(fù)雜模型,它會引起計算邊界的問題,而如果數(shù)據(jù)大小增加,它會引起內(nèi)存分配錯誤。因此,在這兩種情況下(紅色陰影區(qū)域)我們都使用 Dask 來解決這些問題。
如官方文檔中所述,dask ml 庫用例:
- 對于內(nèi)存問題,只需使用 scikit-learn(或其他ML 庫)。
- 對于大型模型,使用 dask_ml.joblib 和scikit-learn estimators。
- 對于大型數(shù)據(jù)集,使用 dask_ml estimators。
讓我們看一下 Dask.distributed 的架構(gòu):
Dask 讓您能夠在計算機集群上運行任務(wù)。在 dask.distributed 中,只要您分配任務(wù),它就會立即開始執(zhí)行。
簡單地說,client就是提交任務(wù)的你,執(zhí)行任務(wù)的是Worker,調(diào)度器則執(zhí)行兩者之間通信。
python -m pip install dask distributed –upgrade
如果您使用的是單臺機器,那么就可以通過以下方式創(chuàng)建一個具有4個worker的dask集群
如果需要dashboard,可以安裝bokeh,安裝bokeh的命令如下:
pip install bokeh
就像我們從 dask.distributed 創(chuàng)建客戶端一樣,我們也可以從 dask.distributed 創(chuàng)建調(diào)度程序。
要使用 dask ML 庫,您必須使用以下命令安裝它:
pip install dask-ml
我們將使用 Scikit-learn 庫來演示 dask-ml 。
假設(shè)我們使用 Grid_Search 方法,我們通常使用如下Python代碼
使用 dask.distributed 創(chuàng)建一個集群:
要使用集群擬合 scikit-learn 模型,我們只需要使用 joblib。