機器學習sklearn(四十):演算法例項(九)迴歸(二)隨機森林迴歸器 RandomForestRegressor
阿新 • • 發佈:2021-06-24
class sklearn.ensemble.RandomForestClassifier(n_estimators=’10’, criterion=’gini’, max_depth=None,min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=’auto’,max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False,n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None)
R平方被定義如下:
其中u是殘差平方和(MSE * N),v是總平方和,N是樣本數量,i是每一個數據樣本,fifi是模型迴歸出的數值,yi是樣本點i實際的數值標籤。y帽是真實數值標籤的平均數。R平方可以為正為負(如果模型的殘差平方和遠遠大於模型的總平方和,模型非常糟糕,R平方就會為負),而均方誤差永遠為正。
值得一提的是,雖然均方誤差永遠為正,但是sklearn當中使用均方誤差作為評判標準時,卻是計算”負均方誤差“(neg_mean_squared_error)。這是因為sklearn在計算模型評估指標的時候,會考慮指標本身的性質,均方誤差本身是一種誤差,所以被sklearn劃分為模型的一種損失(loss),因此在sklearn當中,都以負數表示。真正的均方誤差MSE的數值,其實就是neg_mean_squared_error去掉負號的數字。
重要屬性和介面
最重要的屬性和介面,都與隨機森林的分類器相一致,還是apply, fifit, predict和score最為核心。值得一提的是,隨機森林迴歸並沒有predict_proba這個介面,因為對於迴歸來說,並不存在一個樣本要被分到某個類別的概率問題,因此沒有predict_proba這個介面。
隨機森林迴歸用法
和決策樹完全一致,除了多了引數n_estimators。
1 重要引數,屬性與介面
criterion 迴歸樹衡量分枝質量的指標,支援的標準有三種: 1)輸入"mse"使用均方誤差mean squared error(MSE),父節點和葉子節點之間的均方誤差的差額將被用來作為特徵選擇的標準,這種方法通過使用葉子節點的均值來最小化L2損失 2)輸入“friedman_mse”使用費爾德曼均方誤差,這種指標使用弗裡德曼針對潛在分枝中的問題改進後的均方誤差 3)輸入"mae"使用絕對平均誤差MAE(mean absolute error),這種指標使用葉節點的中值來最小化L1損失 其中N是樣本數量,i是每一個數據樣本,fifi是模型迴歸出的數值,yi是樣本點i實際的數值標籤。所以MSE的本質,其實是樣本真實資料與迴歸結果的差異。在迴歸樹中,MSE不只是我們的分枝質量衡量指標,也是我們最常用的衡量回歸樹迴歸質量的指標,當我們在使用交叉驗證,或者其他方式獲取迴歸樹的結果時,我們往往選擇均方誤差作為我們的評估(在分類樹中這個指標是score代表的預測準確率)。在迴歸中,我們追求的是,MSE越小越好。 然而,迴歸樹的介面score返回的是R平方,並不是MSE。from sklearn.datasets import load_boston from sklearn.model_selection import cross_val_score from sklearn.ensemble import返回十次交叉驗證的結果,注意在這裡,如果不填寫scoring = "neg_mean_squared_error",交叉驗證預設的模型衡量指標是R平方,因此交叉驗證的結果可能有正也可能有負。而如果寫上scoring,則衡量標準是負MSE,交叉驗證的結果只可能為負。RandomForestRegressor boston = load_boston() regressor = RandomForestRegressor(n_estimators=100,random_state=0) cross_val_score(regressor, boston.data, boston.target, cv=10 ,scoring = "neg_mean_squared_error") sorted(sklearn.metrics.SCORERS.keys())
2 例項:用隨機森林迴歸填補缺失值
我們從現實中收集的資料,幾乎不可能是完美無缺的,往往都會有一些缺失值。面對缺失值,很多人選擇的方式是直接將含有缺失值的樣本刪除,這是一種有效的方法,但是有時候填補缺失值會比直接丟棄樣本效果更好,即便我們其實並不知道缺失值的真實樣貌。在sklearn中,我們可以使用sklearn.impute.SimpleImputer來輕鬆地將均值,中值,或者其他最常用的數值填補到資料中,在這個案例中,我們將使用均值,0,和隨機森林迴歸來填補缺失值,並驗證四種狀況下的擬合狀況,找出對使用的資料集來說最佳的缺失值填補方法。 1 匯入需要的庫import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.datasets import load_boston from sklearn.impute import SimpleImputer from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_val_score2. 以波士頓資料集為例,匯入完整的資料集並探索
dataset = load_boston() dataset.data.shape #總共506*13=6578個數據 X_full, y_full = dataset.data, dataset.target n_samples = X_full.shape[0] n_features = X_full.shape[1]3. 為完整資料集放入缺失值
#首先確定我們希望放入的缺失資料的比例,在這裡我們假設是50%,那總共就要有3289個數據缺失 rng = np.random.RandomState(0) missing_rate = 0.5 n_missing_samples = int(np.floor(n_samples * n_features * missing_rate)) #np.floor向下取整,返回.0格式的浮點數 #所有資料要隨機遍佈在資料集的各行各列當中,而一個缺失的資料會需要一個行索引和一個列索引 #如果能夠創造一個數組,包含3289個分佈在0~506中間的行索引,和3289個分佈在0~13之間的列索引,那我們就可 以利用索引來為資料中的任意3289個位置賦空值 #然後我們用0,均值和隨機森林來填寫這些缺失值,然後查看回歸的結果如何 missing_features = rng.randint(0,n_features,n_missing_samples) missing_samples = rng.randint(0,n_samples,n_missing_samples) #missing_samples = rng.choice(dataset.data.shape[0],n_missing_samples,replace=False) #我們現在取樣了3289個數據,遠遠超過我們的樣本量506,所以我們使用隨機抽取的函式randint。但如果我們需要 的資料量小於我們的樣本量506,那我們可以採用np.random.choice來抽樣,choice會隨機抽取不重複的隨機數, 因此可以幫助我們讓資料更加分散,確保資料不會集中在一些行中 X_missing = X_full.copy() y_missing = y_full.copy() X_missing[missing_samples,missing_features] = np.nan X_missing = pd.DataFrame(X_missing) #轉換成DataFrame是為了後續方便各種操作,numpy對矩陣的運算速度快到拯救人生,但是在索引等功能上卻不如 pandas來得好用4. 使用0和均值填補缺失值
#使用均值進行填補 from sklearn.impute import SimpleImputer imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean') X_missing_mean = imp_mean.fit_transform(X_missing) #使用0進行填補 imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0) X_missing_0 = imp_0.fit_transform(X_missing)5. 使用隨機森林填補缺失值
""" 使用隨機森林迴歸填補缺失值 任何迴歸都是從特徵矩陣中學習,然後求解連續型標籤y的過程,之所以能夠實現這個過程,是因為迴歸演算法認為,特徵 矩陣和標籤之前存在著某種聯絡。實際上,標籤和特徵是可以相互轉換的,比如說,在一個“用地區,環境,附近學校數 量”預測“房價”的問題中,我們既可以用“地區”,“環境”,“附近學校數量”的資料來預測“房價”,也可以反過來, 用“環境”,“附近學校數量”和“房價”來預測“地區”。而回歸填補缺失值,正是利用了這種思想。 對於一個有n個特徵的資料來說,其中特徵T有缺失值,我們就把特徵T當作標籤,其他的n-1個特徵和原本的標籤組成新 的特徵矩陣。那對於T來說,它沒有缺失的部分,就是我們的Y_test,這部分資料既有標籤也有特徵,而它缺失的部 分,只有特徵沒有標籤,就是我們需要預測的部分。 特徵T不缺失的值對應的其他n-1個特徵 + 本來的標籤:X_train 特徵T不缺失的值:Y_train 特徵T缺失的值對應的其他n-1個特徵 + 本來的標籤:X_test 特徵T缺失的值:未知,我們需要預測的Y_test 這種做法,對於某一個特徵大量缺失,其他特徵卻很完整的情況,非常適用。 那如果資料中除了特徵T之外,其他特徵也有缺失值怎麼辦? 答案是遍歷所有的特徵,從缺失最少的開始進行填補(因為填補缺失最少的特徵所需要的準確資訊最少)。 填補一個特徵時,先將其他特徵的缺失值用0代替,每完成一次迴歸預測,就將預測值放到原本的特徵矩陣中,再繼續填 補下一個特徵。每一次填補完畢,有缺失值的特徵會減少一個,所以每次迴圈後,需要用0來填補的特徵就越來越少。當 進行到最後一個特徵時(這個特徵應該是所有特徵中缺失值最多的),已經沒有任何的其他特徵需要用0來進行填補了, 而我們已經使用迴歸為其他特徵填補了大量有效資訊,可以用來填補缺失最多的特徵。 遍歷所有的特徵後,資料就完整,不再有缺失值了。 """ X_missing_reg = X_missing.copy() sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values for i in sortindex: #構建我們的新特徵矩陣和新標籤 df = X_missing_reg fillc = df.iloc[:,i] df = pd.concat([df.iloc[:,df.columns != i],pd.DataFrame(y_full)],axis=1) #在新特徵矩陣中,對含有缺失值的列,進行0的填補 df_0 =SimpleImputer(missing_values=np.nan, strategy='constant',fill_value=0).fit_transform(df) #找出我們的訓練集和測試集 Ytrain = fillc[fillc.notnull()] Ytest = fillc[fillc.isnull()] Xtrain = df_0[Ytrain.index,:] Xtest = df_0[Ytest.index,:] #用隨機森林迴歸來填補缺失值 rfc = RandomForestRegressor(n_estimators=100) rfc = rfc.fit(Xtrain, Ytrain) Ypredict = rfc.predict(Xtest) #將填補好的特徵返回到我們的原始的特徵矩陣中 X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] = Ypredict6. 對填補好的資料進行建模
#對所有資料進行建模,取得MSE結果 X = [X_full,X_missing_mean,X_missing_0,X_missing_reg] mse = [] std = [] for x in X: estimator = RandomForestRegressor(random_state=0, n_estimators=100) scores = cross_val_score(estimator,x,y_full,scoring='neg_mean_squared_error', cv=5).mean() mse.append(scores * -1)7. 用所得結果畫出條形圖
x_labels = ['Full data', 'Zero Imputation', 'Mean Imputation', 'Regressor Imputation'] colors = ['r', 'g', 'b', 'orange'] plt.figure(figsize=(12, 6)) ax = plt.subplot(111) for i in np.arange(len(mse)): ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center') ax.set_title('Imputation Techniques with Boston Data') ax.set_xlim(left=np.min(mse) * 0.9, right=np.max(mse) * 1.1) ax.set_yticks(np.arange(len(mse))) ax.set_xlabel('MSE') ax.set_yticklabels(x_labels) plt.show()