増分学習: 巨大なデータを処理するランダム フォレスト

目次

1. 通常の学習と段階的な学習

1.1 一般的な学習

1.2 漸進的学習

2. Kaggle データに対する増分学習の適用


        初期のオープンソース機械学習アルゴリズム ライブラリである sklearn は、コンピューティング用の GPU にアクセスするためのインターフェイスをオープンしていません。つまり、sklearn のすべてのアルゴリズムは、より多くのコンピューティング リソースへのアクセスをサポートしていません。したがって、ランダム フォレストを使用して大量のデータを操作しようとすると、コンピューティング リソースが不足する可能性があります。幸いなことに、この問題を解決するには 2 つの方法があります。

        \弾丸 GPU に接続できる他の機械学習アルゴリズム ライブラリを使用して、xgboost などのランダム フォレストを実装します。

        \弾丸 sklearn によるトレーニングを継続しますが、増分学習を使用します。

        増分学習は機械学習において非常に一般的な方法であり、教師あり学習と教師なし学習の両方で普及しています。増分学習により、アルゴリズムは新しいデータに継続的にアクセスして現在のモデルを拡張できます。つまり、大量のデータをいくつかのサブセットに分割し、トレーニング用のモデルに入力できます。

1. 通常の学習と段階的な学習

1.1 一般的な学習

        一般に、モデルを一度トレーニングした後、新しいデータを使用してモデルをトレーニングすると、元のデータでトレーニングされたモデルが置き換えられます。たとえば、2 つのデータ セットがインポートされます。1 つはカリフォルニアの住宅価格データ セットで、もう 1 つは Kaggle の住宅価格データ セットです。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor as RFR
from sklearn.tree import DecisionTreeRegressor as DTR
from sklearn.model_selection import cross_validate,KFold
from sklearn.datasets import fetch_california_housing
from sklearn.metrics import mean_squared_error

# 加利福尼亚房价数据集
data=pd.read_csv('F:\\Jupyter Files\\机器学习进阶\\集成学习\\datasets\\House Price\\train_encode.csv',encoding='utf-8')
data.drop('Unnamed: 0', axis=1, inplace=True)
x=data.iloc[:,:-1]
y=data.iloc[:,-1]

x.shape  #(1460, 80)

# 加利福尼亚房价数据集
X_fc = fetch_california_housing().data
y_fc = fetch_california_housing().target

X_fc.shape  #(20640, 8)

\弾丸 カリフォルニアの住宅価格データセットをトレーニングします。

model = RFR(n_estimators=3, warm_start=False) #不支持增量学习的
model1 = model.fit(X_fc,y_fc)
#RMSE
(mean_squared_error(y_fc,model1.predict(X_fc)))**0.5
0.30123985583215596

\弾丸 フォレスト内のすべての木を表示すると、各木の乱数シードが表示されます。

model1.estimators_
[DecisionTreeRegressor(max_features='auto'、random_state=1785210460)、
 DecisionTreeRegressor(max_features='auto'、random_state=121562514)、
 DecisionTreeRegressor(max_features='auto'、random_state=1271073231)]

\弾丸 model1 が kaggle の住宅価格データセット x、y でトレーニングを続けます。

model1 = model1.fit(x.iloc[:,:8],y)
#注意!! x有80个特征,X_fc只有8个特征,输入同一个模型的数据必须结构一致
model1.estimators_
[DecisionTreeRegressor(max_features='auto'、random_state=349555903)、
 DecisionTreeRegressor(max_features='auto'、random_state=1253222501)、
 DecisionTreeRegressor(max_features='auto'、random_state=2145441582)]

model1 の元のツリーが消え、新しいツリーが元のツリーに置き換わります。

\弾丸 Model1 をカリフォルニアの住宅価格データセットでトレーニングさせます。

(mean_squared_error(y_fc,model1.predict(X_fc)))**0.5
235232.2375340384

RMSE は非常に大きいため、モデルには y_fc を予測する機能がなくなりました。モデル 1 の元のツリーが消失し、kaggle データセットに基づいてトレーニングされたツリーが元のツリーをカバーしていることは明らかです。そのため、モデル 1 には、それが見ていたカリフォルニアの住宅価格データ レポートの記憶がなくなりました。

        sklearn のこのカバレッジ ルールは相互検証の基礎です。各トレーニングは前のトレーニングの影響を受けないため、モデルを相互検証に使用できます。そうでないとデータ漏洩が発生します。しかし、増分学習では、元のデータでトレーニングされたツリーは置き換えられず、モデルは以前にトレーニングされたデータを一貫して記憶します。

1.2 漸進的学習

\弾丸 カリフォルニアの住宅価格データセットをトレーニングします。

# 增量学习
model = RFR(n_estimators=3, warm_start=True) #支持增量学习
model2 = model.fit(X_fc,y_fc)
model2.estimators_
[DecisionTreeRegressor(max_features=1.0、random_state=1192338237)、
 DecisionTreeRegressor(max_features=1.0、random_state=506683268)、
 DecisionTreeRegressor(max_features=1.0、random_state=654939120)]
(mean_squared_error(y_fc,model2.predict(X_fc)))**0.5
0.29385313927085455

\弾丸 model2 が kaggle の住宅価格データセット x、y でトレーニングを続けます。

model2 = model2.fit(x.iloc[:,:8],y)
model2.estimators_ 
[DecisionTreeRegressor(max_features=1.0、random_state=1192338237)、
 DecisionTreeRegressor(max_features=1.0、random_state=506683268)、
 DecisionTreeRegressor(max_features=1.0、random_state=654939120)]

増分学習ではツリーは変化しません

\弾丸 Model2 をカリフォルニアの住宅価格データセットでトレーニングさせます。

(mean_squared_error(y_fc,model2.predict(X_fc)))**0.5
0.29385313927085455

x と y がトレーニングされていても、model2 に設定されたカリフォルニアの住宅価格データのメモリはまだ存在しているため、X_fc と y_fc を予測するときに良好なスコアを達成できます。

        増分学習では、ツリーは変更されず、トレーニングされた結果が保持されます。ランダム フォレストなどのバギング モデルの場合、これは、以前のデータでトレーニングされたツリーが保持され、新しいツリーが新しいデータでトレーニングされ、古いツリーと新しいツリーが相互に影響を与えないことを意味します。

        ただし、ここには問題があります: 元のツリーは変更されていないにもかかわらず、増分学習では新しいツリーが追加されないようです。実際、ランダム フォレストの場合、新しいツリーを手動で追加する必要があります。

#调用模型的参数,可以通过这种方式修改模型的参数,而不需要重新实例化模型
model2.n_estimators += 2 #增加2棵树,用于增量学习
model2.fit(x.iloc[:,:8],y)
model2.estimators_ #原来的树还是没有变化,新增的树是基于新输入的数据进行训练的
[DecisionTreeRegressor(max_features=1.0、random_state=1192338237)、
 DecisionTreeRegressor(max_features=1.0、random_state=506683268)、DecisionTreeRegressor 
 (max_features=1.0、random_state=654939120)、
 DecisionTreeRegressor(max_features) =1.0、random_state=1440840641)、
 DecisionTreeRegressor(max_features=1.0) 、ランダム状態=1050229920)]

2. Kaggle データに対する増分学習の適用

        大きなデータに直面する場合、ループ モードを使用して巨大な CSV ファイルまたはデータベース ファイルの内容をバッチで読み取り、データをバッチで前処理し、それをモデルに段階的に学習します。

STEP1: トレーニングデータとテストデータのアドレスを定義する

trainpath = r"F:\Jupyter Files\机器学习进阶\集成学习\datasets\Big data\bigdata_train.csv"
testpath = r"F:\Jupyter Files\机器学习进阶\集成学习\datasets\Big data\bigdata_test.csv"

STEP2: csvのデータ総量を調べてみる

増分学習を使用することにした場合、データは非常に巨大であるため、直接開いて表示することも、直接トレーニングすることも、直接インポートすることも不可能である必要があります (たとえば、20 G 以上)。ただし、データを循環的にインポートする必要がある場合は、おおよその実際のデータ量を知る必要があるため、次の方法で開くことができない CSV 内のデータ量を取得できます。

  • 競技データセットの場合は、通常、競技ページで対応する手順を見つけることができます。
  • データベース データ セットの場合は、データベース内で統計を実行できます。
  • 対応する命令が見つからない場合は、deque ライブラリを使用して csv ファイルの最後の数行をインポートし、インデックスを表示できます。
  • データにインデックスがない場合、パンダに頼っておおよそのデータ範囲を見つけることしかできません。

方法 1: データセットにインデックスがある

#使用deque与StringIO辅助,导入csv文件最后的n行
from collections import deque #deque:双向队列
from io import StringIO
with open(trainpath, 'r') as data:
    q = deque(data, 5)
pd.read_csv(StringIO(''.join(q)), header=None)
0 1 2 3 4 5 6 7 8 9 ... 101 102 103 104 105 106 107 108 109 110
0 995029 3.0 3.0 5.0 5.0 2.0 3.0 2.0 5.0 5.0 ... 291658.0 666.0 469.0 37.0 1954.0 33.0 0.0 41.0 865.0 -70.6503
1 995030 2.0 4.0 4.0 2.0 4.0 2.0 4.0 4.0 4.0 ... 968800.0 666.0 469.0 6.0 208.0 30.0 0.0 208.0 19838.0 -123.0867
2 995031 2.0 1.0 3.0 2.0 5.0 1.0 5.0 4.0 4.0 ... 567037.0 93.0 541.0 596.0 2892.0 1602.0 0.0 144.0 2745.0 112.5000
3 995032 1.0 4.0 1.0 5.0 2.0 2.0 1.0 5.0 2.0 ... 989963.0 57.0 441.0 13.0 520.0 29.0 0.0 208.0 10546.0 -97.0000
4 995033 3.0 2.0 4.0 3.0 4.0 2.0 4.0 3.0 4.0 ... 443675.0 36.0 272.0 3.0 285.0 15.0 0.0 208.0 9322.0 -76.3729

最後の行のインデックスは 995033 であるため、トレーニング セットには 99w 個のデータがあることがわかります。

方法 2: データセットにインデックスがありません

データにインデックスがない場合は、パンダで Skiprows と nrows を使用してみてください。Skiprows : このインポートでは、最初の Skiprows 行がスキップされます。nrows : このインポートは nrows 行のみをインポートします。たとえば、skiprows=1000、nrows=1000 の場合、pandas は行 1001 ~ 2000 をインポートします。スキップロウがデータ量を超えると、EmptyDataError が報告されます。

for i in range(0,10**7,100000):
    df = pd.read_csv(trainpath,skiprows=i, nrows=1)
    print(i)
0 
100000 
200000 
300000 
400000 
500000 
600000 
700000 
800000 
900000
-------------------------------------------------- ------------------------- 
EmptyDataError トレースバック (最後に行われた最新の呼び出し)

90w は正常にインポートされましたが、100w ではエラーが報告されているため、データ量は 90 ~ 100w の間であることがわかります。データ量の特定の範囲を引き続き正確に測定することもできますが、一般的には 10 ワット以内のエリアを確認するだけで十分です。

STEP3: データ量を確認後、ループ範囲を準備する

looprange = range(0,10**6,50000)

STEP4: 段階的学習のモデルを確立し、テスト セットを定義する

reg = RFR(n_estimators=10
          ,random_state=1412
          ,warm_start=True
          ,verbose=True #增量学习的过程总是很漫长的,你可以选择展示学习过程
         )
#定义测试集
test = pd.read_csv(testpath,header="infer",index_col=0)
Xtest = test.iloc[:,:-1]
Ytest = test.iloc[:,-1]

STEP5: 循環インポートと増分学習を開始する

注: Skiprows+nrows がデータ量を超えると、残りのデータはすべてエクスポートされます。

for line in looprange:
    if line == 0:
        #首次读取时,保留列名,并且不增加树的数量
        header = "infer"
        newtree = 0
    else:
        #非首次读取时,不要列名,每次增加10棵树
        header = None
        newtree = 10
    
    trainsubset = pd.read_csv(trainpath, header = header, index_col=0, skiprows=line, nrows=50000)
    Xtrain = trainsubset.iloc[:,:-1]
    Ytrain = trainsubset.iloc[:,-1]
    reg.n_estimators += newtree
    reg = reg.fit(Xtrain,Ytrain)
    print("DONE",line+50000)
        
    #当训练集的数据量小于50000时,打断循环
    if Xtrain.shape[0] < 50000:
        break

すべてのデータのトレーニングが完了したら、テスト セットでテストします。

reg.score(Xtest,Ytest)
0.9903482355083931

        インクリメンタル学習を利用する場合、パラメータ調整が必要な場合は、パラメータ調整処理中に継続的に呼び出せるようにインクリメンタル学習ループを評価器や関数にパッケージ化する必要があり、この処理に必要な計算量は非常に多くなりますが、少なくとも、CPU 上の巨大なデータをトレーニングする方法はあります。

おすすめ

転載: blog.csdn.net/weixin_60200880/article/details/131824654