十種常見的迴歸演算法總結和介紹

語言: CN / TW / HK

線性迴歸是機器學習中最簡單的演算法,它可以通過不同的方式進行訓練。 在本文中,我們將介紹以下回歸演算法:線性迴歸、Robust 迴歸、Ridge 迴歸、LASSO 迴歸、Elastic Net、多項式迴歸、多層感知機、隨機森林迴歸和支援向量機。除此以外,本文還將介紹用於評估迴歸模型的最常用指標,包括均方誤差 (MSE)、均方根誤差 (RMSE) 和平均絕對誤差 (MAE)。

匯入庫和讀取資料

import pandas as pd
 import numpy as np
 import matplotlib.pyplot as plt
 import seaborn as sns
 import hvplot.pandas
 %matplotlib inline
 
 sns.set_style("whitegrid")
 plt.style.use("fivethirtyeight")
 
 USAhousing = pd.read_csv('../usa-housing/USA_Housing.csv')
 USAhousing.head()

探索性資料分析 (EDA)

下一步將建立一些簡單的圖表來檢查資料。 進行EDA將幫助我們熟悉資料和獲得資料的資訊,尤其是對迴歸模型影響最大的異常值。

USAhousing.info()
 
 <class 'pandas.core.frame.DataFrame'>
 RangeIndex: 5000 entries, 0 to 4999
 Data columns (total 7 columns):
  #   Column                       Non-Null Count Dtype  
 --- ------                       -------------- -----  
  0   Avg. Area Income             5000 non-null   float64
  1   Avg. Area House Age           5000 non-null   float64
  2   Avg. Area Number of Rooms     5000 non-null   float64
  3   Avg. Area Number of Bedrooms 5000 non-null   float64
  4   Area Population               5000 non-null   float64
  5   Price                         5000 non-null   float64
  6   Address                       5000 non-null   object
 dtypes: float64(6), object(1)
 memory usage: 273.6+ KB

檢視資料集的描述

USAhousing.describe()

訓練前的準備

我們將從訓練一個線性迴歸模型開始,訓練之前需要確定資料的特徵和目標,訓練的特徵的 X ,目標變數的 y ,在本例中我們的目標為 Price 列。

之後,將資料分成訓練集和測試集。 我們將在訓練集上訓練我們的模型,然後使用測試集來評估模型。

from sklearn.model_selection import train_test_split
 
 X = USAhousing[['Avg. Area Income', 'Avg. Area House Age', 'Avg. Area Number of Rooms',
                'Avg. Area Number of Bedrooms', 'Area Population']]
 y = USAhousing['Price']
 
 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

為了評估迴歸模型還建立了一些輔助函式。

from sklearn import metrics
 from sklearn.model_selection import cross_val_score
 
 def cross_val(model):
    pred = cross_val_score(model, X, y, cv=10)
    return pred.mean()
 
 def print_evaluate(true, predicted):  
    mae = metrics.mean_absolute_error(true, predicted)
    mse = metrics.mean_squared_error(true, predicted)
    rmse = np.sqrt(metrics.mean_squared_error(true, predicted))
    r2_square = metrics.r2_score(true, predicted)
    print('MAE:', mae)
    print('MSE:', mse)
    print('RMSE:', rmse)
    print('R2 Square', r2_square)
    print('__________________________________')
     
 def evaluate(true, predicted):
    mae = metrics.mean_absolute_error(true, predicted)
    mse = metrics.mean_squared_error(true, predicted)
    rmse = np.sqrt(metrics.mean_squared_error(true, predicted))
    r2_square = metrics.r2_score(true, predicted)
    return mae, mse, rmse, r2_square

訓練迴歸模型

對於線性迴歸而言,一般都會有以下的假設:

線性假設:線性迴歸假設輸入和輸出之間的關係是線性的。所以可能需要轉換資料以使關係線性化(例如,指數關係的對數轉換)。

去除噪音:線性迴歸假設您的輸入和輸出變數沒有噪聲。這對於輸出變數最重要,如果可能希望刪除輸出變數 (y) 中的異常值。

去除共線性:當具有高度相關的輸入變數時,線性迴歸將會過擬合。需要將輸入資料進行相關性計算並刪除最相關的。

高斯分佈:如果輸入和輸出變數具有高斯分佈,線性迴歸將會做出更可靠的預測。對於分佈的轉換可以對變數使用變換(例如 log 或 BoxCox)以使它們的分佈看起來更像高斯分佈。

對資料進行處理:使用標準化或歸一化重新調整輸入變數,線性迴歸通常會做出更可靠的預測。

from sklearn.preprocessing import StandardScaler
 from sklearn.pipeline import Pipeline
 
 pipeline = Pipeline([
    ('std_scalar', StandardScaler())
 ])
 
 X_train = pipeline.fit_transform(X_train)
 X_test = pipeline.transform(X_test)

下面我們開始進行迴歸迴歸演算法的示例

1、線性迴歸和評價指標

from sklearn.linear_model import LinearRegression
 
 lin_reg = LinearRegression(normalize=True)
 lin_reg.fit(X_train,y_train)

有了第一個模型,那麼就要知道評價模型的指標,以下是迴歸問題的三個常見評估指標:

平均絕對誤差 (MAE) 是誤差絕對值的平均值:

均方誤差 (MSE) 是均方誤差的平均值:

均方根誤差 (RMSE) 是均方誤差的平方根:

這三個指標中:

  • MAE 是最容易理解的,因為它是平均誤差。
  • MSE 比 MAE 更受歡迎,因為 MSE “懲罰”更大的錯誤,這在現實世界中往往很有用。
  • RMSE 比 MSE 更受歡迎,因為 RMSE 可以用“y”單位解釋

這些都是損失函式,我們的訓練目標就是最小化他們。

test_pred = lin_reg.predict(X_test)
 train_pred = lin_reg.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df = pd.DataFrame(
 data=[["Linear Regression", *evaluate(y_test, test_pred) ,
    cross_val(LinearRegression())]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', "Cross Validation"])
 
 Test set evaluation:
 _____________________________________
 MAE: 81135.56609336878
 MSE: 10068422551.40088
 RMSE: 100341.52954485436
 R2 Square 0.9146818498754016
 __________________________________
 Train set evaluation:
 _____________________________________
 MAE: 81480.49973174892
 MSE: 10287043161.197224
 RMSE: 101425.06180031257
 R2 Square 0.9192986579075526
 __________________________________

2、Robust迴歸

Robust迴歸是一種迴歸分析形式,它的目標是克服傳統引數和非引數方法的一些侷限性,旨在不受基礎資料生成過程違反迴歸假設的過度影響。

當資料包含異常值時,則會考慮Robust迴歸。 在存在異常值的情況下,最小二乘估計效率低下並且可能存在偏差。 因為最小二乘預測被拖向離群值,並且因為估計的方差被人為誇大,結果是離群值可以被掩蓋了。

隨機樣本共識——RANSAC

隨機樣本共識 (RANSAC) 是一種迭代方法,它從一組觀察到的包含異常值的資料中估計數學模型的引數,而異常值不會對估計值產生影響。 因此它也可以理解為一種異常值檢測方法。

一個基本的假設是,資料由“內值”和“異常值”組成,“內值”即資料的分佈可以用一組模型引數來解釋,但可能受噪聲影響,“異常值”是不符合模型的資料。RANSAC還假設,給定一組(通常很小)內點,存在一個程式可以估計模型的引數,以最優地解釋或擬合該資料。

from sklearn.linear_model import RANSACRegressor
 
 model = RANSACRegressor(base_estimator=LinearRegression(), max_trials=100)
 model.fit(X_train, y_train)
 
 test_pred = model.predict(X_test)
 train_pred = model.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('====================================')
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Robust Regression", *evaluate(y_test, test_pred) , cross_val(RANSACRegressor())]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', "Cross Validation"]
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 84645.31069259303
 MSE: 10996805871.555056
 RMSE: 104865.65630155115
 R2 Square 0.9068148829222649
 __________________________________
 ====================================
 Train set evaluation:
 _____________________________________
 MAE: 84956.48056962446
 MSE: 11363196455.35414
 RMSE: 106598.29480509592
 R2 Square 0.9108562888249323
 _________________________________

3、Ridge迴歸

Ridge迴歸通過對係數的大小施加懲罰來解決普通最小二乘法的一些問題。 Ridge係數最小化懲罰殘差平方和

alpha >= 0 是控制收縮量的複雜性引數:alpha 值越大,收縮量越大,因此係數對共線性的魯棒性更強。

Ridge迴歸是一個 L2 懲罰模型。 將權重的平方和新增到最小二乘成本函式。

from sklearn.linear_model import Ridge
 
 model = Ridge(alpha=100, solver='cholesky', tol=0.0001, random_state=42)
 model.fit(X_train, y_train)
 pred = model.predict(X_test)
 
 test_pred = model.predict(X_test)
 train_pred = model.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('====================================')
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Ridge Regression", *evaluate(y_test, test_pred) , cross_val(Ridge())]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', "Cross Validation"]
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 81428.64835535336
 MSE: 10153269900.892609
 RMSE: 100763.43533689494
 R2 Square 0.9139628674464607
 __________________________________
 ====================================
 Train set evaluation:
 _____________________________________
 MAE: 81972.39058585509
 MSE: 10382929615.14346
 RMSE: 101896.66145239233
 R2 Square 0.9185464334441484
 __________________________________

4、LASSO 迴歸

LASSO 迴歸是一種估計稀疏係數的線性模型。 在數學上,它由一個用 L1 先驗作為正則化器訓練的線性模型組成。 最小化的目標函式是:

from sklearn.linear_model import Lasso
 
 model = Lasso(alpha=0.1,
              precompute=True,
 #               warm_start=True,
              positive=True,
              selection='random',
              random_state=42)
 model.fit(X_train, y_train)
 
 test_pred = model.predict(X_test)
 train_pred = model.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('====================================')
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Lasso Regression", *evaluate(y_test, test_pred) , cross_val(Lasso())]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', "Cross Validation"]
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 81135.6985172622
 MSE: 10068453390.364521
 RMSE: 100341.68321472648
 R2 Square 0.914681588551116
 __________________________________
 ====================================
 Train set evaluation:
 _____________________________________
 MAE: 81480.63002185506
 MSE: 10287043196.634295
 RMSE: 101425.0619750084
 R2 Square 0.9192986576295505
 __________________________________

5、Elastic Net

Elastic Net 使用 L1 和 L2 先驗作為正則化器進行訓練。 這種組合允許學習一個稀疏模型,其中很少有像 Lasso 那樣的非零權重,同時仍然保持 Ridge 的正則化屬性。

當多個特徵相互關聯時,Elastic Net絡很有用。 Lasso 可能會隨機選擇關聯特徵其中之一,而 Elastic Net 可能會同時選擇兩者。 Elastic Net最小化的目標函式是:

from sklearn.linear_model import ElasticNet
 
 model = ElasticNet(alpha=0.1, l1_ratio=0.9, selection='random', random_state=42)
 model.fit(X_train, y_train)
 
 test_pred = model.predict(X_test)
 train_pred = model.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('====================================')
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Elastic Net Regression", *evaluate(y_test, test_pred) , cross_val(ElasticNet())]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', "Cross Validation"]
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 81184.43147330945
 MSE: 10078050168.470106
 RMSE: 100389.49232100991
 R2 Square 0.9146002670381437
 __________________________________
 ====================================
 Train set evaluation:
 _____________________________________
 MAE: 81577.88831531754
 MSE: 10299274948.101461
 RMSE: 101485.34351373829
 R2 Square 0.9192027001474953
 __________________________________

6、多項式迴歸

機器學習中的一種常見模式是使用在資料的非線性函式上訓練的線性模型。 這種方法保持了線性方法通常快速的效能,同時允許它們適應更廣泛的資料。

可以通過從係數構造多項式特徵來擴充套件簡單的線性迴歸。 在標準線性迴歸中,可能有一個看起來像這樣的二維資料模型:

如果我們想對資料擬合拋物面而不是平面,我們可以將特徵組合成二階多項式,使模型看起來像這樣:

這仍然是一個線性模型:那麼如果我們建立一個新的變數

通過重新標記資料,那麼公式可以寫成

可以看到到生成的多項式迴歸屬於上面的同一類線性模型(即模型在 w 中是線性的),並且可以通過相同的技術求解。 通過考慮使用這些基函式構建的高維空間內的線性擬合,該模型可以靈活地擬合更廣泛的資料範圍。

from sklearn.preprocessing import PolynomialFeatures
 
 poly_reg = PolynomialFeatures(degree=2)
 
 X_train_2_d = poly_reg.fit_transform(X_train)
 X_test_2_d = poly_reg.transform(X_test)
 
 lin_reg = LinearRegression(normalize=True)
 lin_reg.fit(X_train_2_d,y_train)
 
 test_pred = lin_reg.predict(X_test_2_d)
 train_pred = lin_reg.predict(X_train_2_d)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('====================================')
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Polynomail Regression", *evaluate(y_test, test_pred), 0]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', 'Cross Validation']
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 81174.51844119698
 MSE: 10081983997.620703
 RMSE: 100409.0832426066
 R2 Square 0.9145669324195059
 __________________________________
 ====================================
 Train set evaluation:
 _____________________________________
 MAE: 81363.0618562117
 MSE: 10266487151.007816
 RMSE: 101323.67517519198
 R2 Square 0.9194599187853729
 __________________________________

7、隨機梯度下降

梯度下降是一種非常通用的優化演算法,能夠為各種問題找到最佳解決方案。 梯度下降的一般思想是迭代地調整引數以最小化成本函式。 梯度下降測量誤差函式相對於引數向量的區域性梯度,它沿著梯度下降的方向前進。 一旦梯度為零,就達到了最小值。

from sklearn.linear_model import SGDRegressor
 
 sgd_reg = SGDRegressor(n_iter_no_change=250, penalty=None, eta0=0.0001, max_iter=100000)
 sgd_reg.fit(X_train, y_train)
 
 test_pred = sgd_reg.predict(X_test)
 train_pred = sgd_reg.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 print('====================================')
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Stochastic Gradient Descent", *evaluate(y_test, test_pred), 0]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', 'Cross Validation']
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 81135.56682170597
 MSE: 10068422777.172981
 RMSE: 100341.53066987259
 R2 Square 0.914681847962246
 __________________________________
 ====================================
 Train set evaluation:
 _____________________________________
 MAE: 81480.49901528798
 MSE: 10287043161.228634
 RMSE: 101425.06180046742
 R2 Square 0.9192986579073061
 __________________________________

8、多層感知機

多層感知機相對於簡單迴歸任務的好處是簡單的線性迴歸模型只能學習特徵和目標之間的線性關係,因此無法學習複雜的非線性關係。 由於每一層都存在啟用函式,多層感知機有能力學習特徵和目標之間的複雜關係。

from tensorflow.keras.models import Sequential
 from tensorflow.keras.layers import Input, Dense, Activation, Dropout
 from tensorflow.keras.optimizers import Adam
 
 X_train = np.array(X_train)
 X_test = np.array(X_test)
 y_train = np.array(y_train)
 y_test = np.array(y_test)
 
 model = Sequential()
 
 model.add(Dense(X_train.shape[1], activation='relu'))
 model.add(Dense(32, activation='relu'))
 # model.add(Dropout(0.2))
 
 model.add(Dense(64, activation='relu'))
 # model.add(Dropout(0.2))
 
 model.add(Dense(128, activation='relu'))
 # model.add(Dropout(0.2))
 
 model.add(Dense(512, activation='relu'))
 model.add(Dropout(0.1))
 model.add(Dense(1))
 
 model.compile(optimizer=Adam(0.00001), loss='mse')
 
 r = model.fit(X_train, y_train,
              validation_data=(X_test,y_test),
              batch_size=1,
              epochs=100)
 pd.DataFrame({'True Values': y_test, 'Predicted Values': pred}).hvplot.scatter(x='True Values', y='Predicted Values')
 pd.DataFrame(r.history)

pd.DataFrame(r.history).hvplot.line(y=['loss', 'val_loss'])
test_pred = model.predict(X_test)
 train_pred = model.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Artficial Neural Network", *evaluate(y_test, test_pred), 0]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', 'Cross Validation']
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 101035.09313018023
 MSE: 16331712517.46175
 RMSE: 127795.58880282899
 R2 Square 0.8616077649459881
 __________________________________
 Train set evaluation:
 _____________________________________
 MAE: 102671.5714851714
 MSE: 17107402549.511665
 RMSE: 130795.2695991398
 R2 Square 0.8657932776379376
 __________________________________

9、隨機森林迴歸

from sklearn.ensemble import RandomForestRegressor
 
 rf_reg = RandomForestRegressor(n_estimators=1000)
 rf_reg.fit(X_train, y_train)
 
 test_pred = rf_reg.predict(X_test)
 train_pred = rf_reg.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["Random Forest Regressor", *evaluate(y_test, test_pred), 0]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', 'Cross Validation']
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 94032.15903928125
 MSE: 14073007326.955029
 RMSE: 118629.70676417871
 R2 Square 0.8807476597554337
 __________________________________
 Train set evaluation:
 _____________________________________
 MAE: 35289.68268023927
 MSE: 1979246136.9966476
 RMSE: 44488.71921056671
 R2 Square 0.9844729124701823
 __________________________________

10、支援向量機

from sklearn.svm import SVR
 
 svm_reg = SVR(kernel='rbf', C=1000000, epsilon=0.001)
 svm_reg.fit(X_train, y_train)
 
 test_pred = svm_reg.predict(X_test)
 train_pred = svm_reg.predict(X_train)
 
 print('Test set evaluation:\n_____________________________________')
 print_evaluate(y_test, test_pred)
 
 print('Train set evaluation:\n_____________________________________')
 print_evaluate(y_train, train_pred)
 
 results_df_2 = pd.DataFrame(
 data=[["SVM Regressor", *evaluate(y_test, test_pred), 0]],
 columns=['Model', 'MAE', 'MSE', 'RMSE', 'R2 Square', 'Cross Validation']
 )
 
 results_df = results_df.append(results_df_2, ignore_index=True)
 
 Test set evaluation:
 _____________________________________
 MAE: 87205.73051021634
 MSE: 11720932765.275513
 RMSE: 108263.25676458987
 R2 Square 0.9006787511983232
 __________________________________
 Train set evaluation:
 _____________________________________
 MAE: 73692.5684807321
 MSE: 9363827731.411337
 RMSE: 96766.87310960986
 R2 Square 0.9265412370487783
 __________________________________

結果對比

以上就是我們常見的10個迴歸演算法,下面看看結果的對比

results_df

results_df.set_index('Model', inplace=True)
 results_df['R2 Square'].plot(kind='barh', figsize=(12, 8))

可以看到,雖然本例的差別很小(這是因為資料集的原因),但是每個演算法還是有細微的差別的,我們可以根據不同的實際情況選擇表現較好的演算法。

總結

在本文中,我們介紹了機器學習中的常見的線性迴歸演算法包括:

  • 常見的線性迴歸模型(Ridge、Lasso、ElasticNet……)
  • 模型使用的方法
  • 採用學習演算法對模型中的係數進行估計
  • 如何評估線性迴歸模型