問題
實(shí)際處理和解決機(jī)器學(xué)習(xí)問題過程中,我們會(huì)遇到一些“大數(shù)據(jù)”問題,比如有上百萬條數(shù)據(jù),上千上萬維特征,此時(shí)數(shù)據(jù)存儲(chǔ)已經(jīng)達(dá)到10G這種級(jí)別。這種情況下,如果還是直接使用傳統(tǒng)的方式肯定行不通,比如當(dāng)你想把數(shù)據(jù)load到內(nèi)存中轉(zhuǎn)成numpy數(shù)組,你會(huì)發(fā)現(xiàn)要么創(chuàng)建不了那么大的numpy矩陣,要么直接加載時(shí)報(bào)MemeryError。在這種情況下我了解了幾種選擇辦法,
- 對(duì)數(shù)據(jù)進(jìn)行降維
- 使用流式或類似流式處理
- 上大機(jī)器,高內(nèi)存的,或者用spark集群。
文檔
Sklearn里面提供一些流式處理方法。具體可以參考官方文檔:
講解了怎么處理 big data 文件:http://scikit-learn.org/stable/modules/scaling_strategies.html
通過一個(gè)例子講解了怎么用:http://scikit-learn.org/stable/auto_examples/applications/plot_out_of_core_classification.html
簡(jiǎn)單介紹
我看了上面兩個(gè)文檔,并使用介紹的SGDClassifier進(jìn)行分類,效果挺好的,這里記錄下用法。
要實(shí)現(xiàn)big data的處理,需要滿足三個(gè)條件:
1 . 有流式數(shù)據(jù)
2 . 能從數(shù)據(jù)中可以提取出特征
3 . 增量學(xué)習(xí)算法
1. 流式數(shù)據(jù)
第一個(gè)條件,要給算法流式數(shù)據(jù)或小batch的數(shù)據(jù),比如一次提供1000條這樣。這一塊是需要自己寫代碼提供的,可以實(shí)現(xiàn)一個(gè)生成器,每調(diào)用一次提供一份小batch數(shù)據(jù)。
2. 提取特征
第二個(gè)條件,可以使用任何一種sklearn中支持的特征提取方法。對(duì)于一些特殊情況,比如特征需要標(biāo)準(zhǔn)化或者是事先不知道特征值的情況下需要特殊處理。
3. 增量學(xué)習(xí)算法
對(duì)于第三個(gè)條件,sklearn中提供了很多增量學(xué)習(xí)算法。雖然不是所有的算法都可以增量學(xué)習(xí),但是學(xué)習(xí)器提供了 partial_fit的函數(shù)的都可以進(jìn)行增量學(xué)習(xí)。事實(shí)上,使用小batch的數(shù)據(jù)中進(jìn)行增量學(xué)習(xí)(有時(shí)候也稱為online learning)是這種學(xué)習(xí)方式的核心,因?yàn)樗茏屓魏我欢螘r(shí)間內(nèi)內(nèi)存中只有少量的數(shù)據(jù)。
sklearn提供很多增量學(xué)習(xí)算法:
- Classification
- sklearn.naive_bayes.MultinomialNB
- sklearn.naive_bayes.BernoulliNB
- sklearn.linear_model.Perceptron
- sklearn.linear_model.SGDClassifier
- sklearn.linear_model.PassiveAggressiveClassifier
- Regression
- sklearn.linear_model.SGDRegressor
- sklearn.linear_model.PassiveAggressiveRegressor
- Clustering
- sklearn.cluster.MiniBatchKMeans
- Decomposition / feature Extraction
- sklearn.decomposition.MiniBatchDictionaryLearning
- sklearn.decomposition.IncrementalPCA
- sklearn.decomposition.LatentDirichletAllocation
- sklearn.cluster.MiniBatchKMeans
其中對(duì)于分類問題,在第一次調(diào)用partial_fit時(shí)需要通過classes參數(shù)指定分類的類別。
另外有一點(diǎn)需要考慮,所有的學(xué)習(xí)器在學(xué)習(xí)過程中不會(huì)對(duì)每個(gè)樣例賦予同樣的權(quán)重。對(duì)于感知機(jī),它對(duì)于bad樣本會(huì)敏感,即使學(xué)習(xí)器已經(jīng)學(xué)習(xí)了很多樣本了,而對(duì)于SGD和PassiveAggressive,對(duì)于這種情況會(huì)更魯棒一點(diǎn),后者在學(xué)習(xí)的時(shí)候,后來學(xué)習(xí)樣本的權(quán)重會(huì)隨著學(xué)習(xí)器學(xué)習(xí)率的下降而降低。
實(shí)例
這里舉一個(gè)實(shí)際的例子。我這邊有上G的訓(xùn)練文件和測(cè)試文件,都是csv格式。因?yàn)闆]法直接都讀進(jìn)內(nèi)存處理,所以選擇增量學(xué)習(xí)的方式處理。
1. 生成一個(gè)文件流迭代器
def iter_minibatches(data_stream, minibatch_size=1000):
'''
迭代器
給定文件流(比如一個(gè)大文件),每次輸出minibatch_size行,默認(rèn)選擇1k行
將輸出轉(zhuǎn)化成numpy輸出,返回X, y
'''
X = []
y = []
cur_line_num = 0
csvfile = file(data_stream, 'rb')
reader = csv.reader(csvfile)
for line in reader:
y.append(float(line[0]))
X.append(line[1:]) # 這里要將數(shù)據(jù)轉(zhuǎn)化成float類型
cur_line_num += 1
if cur_line_num >= minibatch_size:
X, y = np.array(X), np.array(y) # 將數(shù)據(jù)轉(zhuǎn)成numpy的array類型并返回
yield X, y#就跟return一樣,唯一的區(qū)別就是,yield會(huì)停止在這里
X, y = [], []
cur_line_num = 0
csvfile.close()
# 生成測(cè)試文件
minibatch_test_iterators = iter_minibatches(test_file, minibatch_size=5000)
X_test, y_test = minibatch_test_iterators.next() # 得到一份測(cè)試文件
2. 增量訓(xùn)練
from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier() # SGDClassifier的參數(shù)設(shè)置可以參考sklearn官網(wǎng)
minibatch_train_iterators = iter_minibatches(data_part_file, minibatch_size=2000)
for i, (X_train, y_train) in enumerate(minibatch_train_iterators):
# 使用 partial_fit ,并在第一次調(diào)用 partial_fit 的時(shí)候指定 classes
sgd_clf.partial_fit(X_train, y_train, classes=np.array([0, 1]))
print("{} time".format(i)) # 當(dāng)前次數(shù)
print("{} score".format(sgd_clf.score(X_test, y_test))) # 在測(cè)試集上看效果
3. 結(jié)果
0 time
0.679 score
1 time
0.6954 score
2 time
0.712 score
3 time
0.7248 score
...
57 time
0.745 score
58 time
0.7394 score
59 time
0.7398 score
4. 一點(diǎn)補(bǔ)充
- 當(dāng)SGD的損失函數(shù)為log時(shí),SGD等價(jià)于LR。
- 數(shù)據(jù)只迭代一次分類器可能還沒完全收斂,可以多迭代幾次
- mini-batch的量不要設(shè)置太小,太小的話,需要多迭代幾次才能收斂