sklearn 中的模型對於大數據集如何處理?

今天用sklearn的svm.svc訓練模型,fit的時候出現了MemoryError。

另外在用cross_validation.cross_val_score做交叉檢驗的時候也出現了同樣的問題。

由於數據比較稀疏,改用了linearsvc,不會出現這種錯誤了,訓練的也比較快。

但是考慮到這種情況,如果數據集比較大,沒辦法一次讀入內存或者一次訓練完成的話,sklearn有沒有提供分批讀入並訓練的方式呢?

還請大神賜教。


partial_fit增量式計算

類似於深度學習裡面的batch訓練


請看文檔,sklearn提供這麼全的文檔不是為了好玩:

6. Strategies to scale computationally: bigger data

Out-of-core classification of text documents

簡單來說,有partial_fit的演算法都可以分批train,但你要自己寫分批讀入的代碼,畢竟只有你自己知道你的數據是什麼格式。


背景

一般來說,在使用 sklearn 對數據建模時,一旦模型表現不夠理想,通常首先想到的就是增加訓練數據集。然而尷尬的是,數據量的增加往往得受限於硬體條件和工具性能,比如像下圖這樣,數據量大約 30W 左右,即使伺服器有 64G 內存,我試過很多次,如果要使用批量訓練的方式,不管是用 notebook 還是寫成 .py 腳本跑,仍然會出現 MemoryError Kernel Restarting 的錯誤。

一開始,我覺得代碼可能有問題,試著人肉去調節一些超參數,但是並不能解決該問題,只能通過減少訓練數據來避免此錯誤。後來聯繫運維調用查看日誌才發現問題所在,原來在進行訓練的時候機器的內存佔用率會變得異常很高。

批量訓練與增量訓練的區別

後來在小組 leader 的提示下,嘗試使用增量訓練的方法。

批量訓練與增量訓練的不同之處在於,批量訓練在訓練時需要一次性把所有數據載入到內存中。什麼是增量訓練?增量學習適合解決數據量劇增的短板,不同於批次訓練在訓練時一次性 feed 進入所有的數據集,增量訓練每輪只訓練一部分數據,再接受到新的樣例時,僅需根據新的樣例對模型進行更新 。

通過下面這段代碼,可以看出增量訓練和批量訓練在 feed 模型數據的方式上是不同的,增量訓練需要一個數據迭代生成器,即如果每次訓練用 1W 條數據,get_minibatch 函數便會執行 size = 10000 次;而批量訓練則一次性把所有的訓練數據全部載入進入了內存,然後再進行擬合。

舉個例子,假設給一個從未接觸機器學習的人解決機器學習難題,批量訓練是扔給他一大堆書和代碼然後要求他一次性學完馬上給出答案;增量訓練是你先學學微積分、線性代數、概率統計,小考一次,發現微積分還有待加強,下一輪的學習就側重對微積分的複習,如此往複,最後再完成機器學習的任務,它是一個不斷學習的過程。顯然,前者的方式很容易讓人崩潰。

你也可以在 sklearn 測試多個分類器效果,但是目前適合增量學習(能夠 partial_fit())的分類器有限制,參考6. Strategies to scale computationally: bigger data。

關於如何用 Python 實現增量學習,其實和批量訓練差不多,只是 feed 數據的方式不同,可參考 Python Machine Learning 一書第八章 246 頁 Working with bigger data - online algorithms and out-of-core learning 的內容和 sklearn 中給出的例子。

訓練結果對比

從下面的匯總結果,增量訓練能夠覆蓋到全部有效的數據,也能覆蓋所有的類別,覆蓋率優於批量訓練,但是效果卻不太理想,驗證集的查准率和查全率表現很差,暫時我也不知道是什麼原因。

因為問題限定在 sklearn 工具下,其實如果 sklearn 解決不了可以轉投其他框架如 tensorflow,又或者轉變思路用啟發式的方法將數據按照一個一個類別劃分,並分別訓練分類器也是個不錯的辦法。

推薦閱讀

  1. http://scikit-learn.org/stable/auto_examples/applications/plot_out_of_core_classification.html
  2. Sebastian Raschka. Python and Machine Learning(需要電子版請留言)
  3. Introduction to Online Machine Learning : Simplified
  4. 6. Strategies to scale computationally: bigger data


有的,linearsvc,還有lr/sgd這樣的模型,都可以分批訓練。但是非線性svm是不可以的。

另外如果你數據集稀疏的話就應該用稀疏矩陣,這樣不需要分批訓練也不會超過內存,如果是非線性svm這樣的模型,你應該用svd先降維,這樣也不會內存不足。如果數據集完全超過了內存量級,並且你不滿足於lr這樣的模型的話,你只能自己去寫一個


看了上面的匿名用戶的回答,然後去看了sklearn的文檔,解決了我的問題。

順便寫了一個博客記錄增量學習的用法:使用sklearn進行增量學習


大量數據的是NLP嗎?

說可能你不愛聽的,有些東西個人電腦是搞不動的。但是你要是非要想搞,你可以有以下選擇:

1.把整塊數據分成batches,每次訓練讀取一個,訓練完釋放空間,然後讀下一個。

2.使用稀疏矩陣以及支持稀疏矩陣的方法。


路過這個問題,樓上有答主提到了分批讀入的問題,提供兩段可以分批讀入的簡單代碼,不過不保證適用於題主的數據集,只是做個參考而已。

第一種是用csv讀入:

import os, csv
local_path = os.getcwd()
source = "你自己數據所在的位置"
SEP = "," # 分割符
with open(local_path+"\"+source, "r") as R:
iterator = csv.DictReader(R, delimiter=SEP)
for n, row in enumerate(iterator):
if n==0:
header = row
else:
# 你對自己數據進行的預處理程序
# 你所用到的機器學習演算法程序
pass
print ("Total rows: %i" % (n+1))
print ("Sample values: %s" % str(row))

舉個例子我這裡使用的是網上可以下載到的Bike-sharing dataset,那麼最後的輸出為:

Total rows: 17379
Sample values: {"mnth": "12", "cnt": "49", "holiday": "0", "instant":
"17379", "temp": "0.26", "dteday": "2012-12-31", "hr": "23", "season":
"1", "registered": "37", "windspeed": "0.1343", "atemp": "0.2727",
"workingday": "1", "weathersit": "1", "weekday": "1", "hum": "0.65",
"yr": "1", "casual": "12"}

當然這裡的Sample values的值是最後一個樣本的。

第二種是用pandas的read_csv讀入,其實程序和上一段差不多,就多了一個CHUNK_SIZE:

import pandas as pd
CHUNK_SIZE = 1000
with open(數據所在的路徑, "r") as R:
iterator = pd.read_csv(R, chunksize=CHUNK_SIZE)
for n, data_chunk in enumerate(iterator):
print ("Size of uploaded chunk: %i instances, %i features" %
(data_chunk.shape))
# 你對自己數據進行的預處理程序
# 你所用到的機器學習演算法程序
pass

推薦用第二種,理由的話引用一本書里的內容(其實是我懶...得...翻):

1.You can keep your code consistent if you change your source type, that is,you need to redefine just the streaming iterator

2.You can access a large number of different formats such as CSV, plain TXT,HDF, JSON, and SQL query for a specific database

3.The data is streamed into chunks of the desired size as DataFrame data structures so that you can access the features in a positional way or by recalling their label, thanks to .loc , .iloc , .ix methods typical of slicing and dicing in a pandas dataframe

如果題主覺得太簡單了可以忽視...


注意設置cross_val_score里的pre_dispatch。這個不調很容易MemoryError。

可以參考下文:

sklearn cross_val_score中的參數pre_dispatch-SofaSofa


建議使用支持scipy sparse matrix的演算法 RF好像就可以 如果你一定要dense matrix的話 有些演算法使可以使用Online learning的


推薦閱讀:

有沒有一些入門級的機器學習或數據挖掘的書推薦呢?演算法理論實戰都行的。
有哪些免費軟體能夠根據數據生成分析圖,簡易一些的,能夠讓數據分析的新手快速掌握數據分析方法?
數據分析和挖掘有哪些公開的數據來源?
數據埋點是什麼?設置埋點的意義是什麼?
產品數據分析需要注意哪些問題?

TAG:Python | 數據挖掘 | 數據分析 | 機器學習 | 大數據 |