import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_excel('california.xlsx')
from sklearn.model_selection import train_test_split
X = df.drop(['price'],axis=1)
y = df['price']
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 然后將訓練集進一步劃分為訓練集和驗證集
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.125, random_state=42) # 0.125 x 0.8 = 0.1
# 數據集標準化
x_mean = X_train.mean()
x_std = X_train.std()
y_mean = y.mean()
y_std = y.std()
X_train = (X_train - x_mean)/x_std
y_train = (y_train-y_mean)/y_std
X_val = (X_val - x_mean)/x_std
y_val = (y_val - y_mean)/y_std
X_test = (X_test - x_mean)/x_std
y_test = (y_test - y_mean)/y_std
對加利福尼亞房價數據集進行處理,首先將數據集分割為訓練集、驗證集和測試集,然后對特征和目標變量進行標準化,以確保不同特征在同一尺度上進行模型訓練和評估
LightGBM模型參數
from ngboost import NGBRegressor
from catboost import CatBoostRegressor
import lightgbm as lgb
import xgboost as xgb
# LightGBM模型參數
params_lgb = {
'learning_rate': 0.02, # 學習率,控制每一步的步長,用于防止過擬合。典型值范圍:0.01 - 0.1
'boosting_type': 'gbdt', # 提升方法,這里使用梯度提升樹(Gradient Boosting Decision Tree,簡稱GBDT)
'objective': 'mse', # 損失函數,這里使用均方誤差(Mean Squared Error,簡稱MSE)
'metric': 'rmse', # 評估指標,這里使用均方根誤差(Root Mean Squared Error,簡稱RMSE)
'num_leaves': 127, # 每棵樹的葉子節點數量,控制模型復雜度。較大值可以提高模型復雜度但可能導致過擬合
'verbose': -1, # 控制 LightGBM 輸出信息的詳細程度,-1表示無輸出,0表示最少輸出,正數表示輸出更多信息
'seed': 42, # 隨機種子,用于重現模型的結果
'n_jobs': -1, # 并行運算的線程數量,-1表示使用所有可用的CPU核心
'feature_fraction': 0.8, # 每棵樹隨機選擇的特征比例,用于增加模型的泛化能力
'bagging_fraction': 0.9, # 每次迭代時隨機選擇的樣本比例,用于增加模型的泛化能力
'bagging_freq': 4 # 每隔多少次迭代進行一次bagging操作,用于增加模型的泛化能力
}
model_lgb = lgb.LGBMRegressor(**params_lgb)
XGBoost模型參數
# XGBoost模型參數
params_xgb = {
'learning_rate': 0.02, # 學習率,控制每一步的步長,用于防止過擬合。典型值范圍:0.01 - 0.1
'booster': 'gbtree', # 提升方法,這里使用梯度提升樹(Gradient Boosting Tree)
'objective': 'reg:squarederror', # 損失函數,這里使用平方誤差
'max_leaves': 127, # 每棵樹的葉子節點數量,控制模型復雜度。較大值可以提高模型復雜度但可能導致過擬合
'verbosity': 1, # 控制 XGBoost 輸出信息的詳細程度,0表示無輸出,1表示輸出進度信息
'seed': 42, # 隨機種子,用于重現模型的結果
'nthread': -1, # 并行運算的線程數量,-1表示使用所有可用的CPU核心
'colsample_bytree': 0.6, # 每棵樹隨機選擇的特征比例,用于增加模型的泛化能力
'subsample': 0.7, # 每次迭代時隨機選擇的樣本比例,用于增加模型的泛化能力
'early_stopping_rounds': 100, # 早停輪數,在驗證集上性能不提升時提前停止訓練
'eval_metric': 'rmse' # 評估指標,這里使用均方根誤差(Root Mean Squared Error,簡稱RMSE)
}
model_xgb = xgb.XGBRegressor(**params_xgb)
CatBoost模型參數
# CatBoost模型參數
params_cat = {
'learning_rate': 0.02, # 學習率,控制每一步的步長,用于防止過擬合。典型值范圍:0.01 - 0.1
'iterations': 1000, # 弱學習器(決策樹)的數量
'depth': 6, # 決策樹的深度,控制模型復雜度
'eval_metric': 'RMSE', # 評估指標,這里使用均方根誤差(Root Mean Squared Error,簡稱RMSE)
'random_seed': 42, # 隨機種子,用于重現模型的結果
'verbose': 100 # 控制CatBoost輸出信息的詳細程度,每100次迭代輸出一次
}
model_cat = CatBoostRegressor(**params_cat)
NGBoost模型參數
# NGBoost模型參數
params_ngb = {
'learning_rate': 0.02, # 學習率,控制每一步的步長,用于防止過擬合
'n_estimators': 1000, # 弱學習器(決策樹)的數量
'verbose': False, # 控制NGBoost輸出信息的詳細程度
'random_state': 42, # 隨機種子,用于重現模型的結果
'natural_gradient': True # 是否使用自然梯度來更新模型參數
}
model_ngb = NGBRegressor(**params_ngb)
模型訓練
# 定義平均模型
class AverageModel:
def __init__(self, models):
self.models = models
def fit(self, X, y, X_val, y_val):
for model in self.models:
if isinstance(model, lgb.LGBMRegressor):
model.fit(X, y, eval_set=[(X_val, y_val)], eval_metric='rmse', callbacks=[lgb.early_stopping(stopping_rounds=100)])
elif isinstance(model, xgb.XGBRegressor):
model.fit(X, y, eval_set=[(X_val, y_val)], verbose=False)
elif isinstance(model, CatBoostRegressor):
model.fit(X, y, eval_set=(X_val, y_val), use_best_model=True, verbose=False)
elif isinstance(model, NGBRegressor):
model.fit(X, y, X_val=X_val, Y_val=y_val)
def predict(self, X):
predictions = []
for model in self.models:
predictions.append(model.predict(X))
return sum(predictions) / len(predictions)
# 創建平均模型
average_model_four = AverageModel([model_lgb, model_xgb, model_cat, model_ngb])
# 訓練模型
average_model_four.fit(X_train, y_train, X_val, y_val)
定義了一個名為 AverageModel 的類,用于創建一個平均模型,通過集成四個模型的預測結果來提升預測的穩定性和準確性,在 fit 方法中,該類可以同時訓練傳入的多個模型,并使用驗證集進行早期停止策略來防止過擬合,在 predict 方法中,該類將多個模型的預測結果取平均作為最終的預測輸出
模型預測及評價
# 預測
y_pred_four = average_model_four.predict(X_test)
y_pred_list = y_pred_four.tolist()
mse = metrics.mean_squared_error(y_test, y_pred_list)
rmse = np.sqrt(mse)
mae = metrics.mean_absolute_error(y_test, y_pred_list)
r2 = metrics.r2_score(y_test, y_pred_list)
print("均方誤差 (MSE):", mse)
print("均方根誤差 (RMSE):", rmse)
print("平均絕對誤差 (MAE):", mae)
print("擬合優度 (R-squared):", r2)
集成CatBoost與NGBoost模型
# 定義平均模型
class AverageModel:
def __init__(self, models):
self.models = models
def fit(self, X, y, X_val, y_val):
for model in self.models:
if isinstance(model, NGBRegressor):
model.fit(X, y, X_val=X_val, Y_val=y_val) # NGBoost的fit方法接受驗證集參數
elif isinstance(model, CatBoostRegressor):
model.fit(X, y, eval_set=(X_val, y_val), use_best_model=True, verbose=False)
def predict(self, X):
predictions = []
for model in self.models:
predictions.append(model.predict(X))
return sum(predictions) / len(predictions)
# 創建平均模型
average_model_two = AverageModel([model_ngb, model_cat])
# 訓練模型
average_model_two.fit(X_train, y_train, X_val, y_val)
# 預測
y_pred_two = average_model_two.predict(X_test)
from sklearn import metrics
import numpy as np
y_pred_list = y_pred_two.tolist() # 或者 y_pred_array = np.array(y_pred)
mse = metrics.mean_squared_error(y_test, y_pred_list)
rmse = np.sqrt(mse)
mae = metrics.mean_absolute_error(y_test, y_pred_list)
r2 = metrics.r2_score(y_test, y_pred_list)
print("均方誤差 (MSE):", mse)
print("均方根誤差 (RMSE):", rmse)
print("平均絕對誤差 (MAE):", mae)
print("擬合優度 (R-squared):", r2)
由于前文梯度提升集成:LightGBM與XGBoost組合預測定義過常見的LightGBM與XGBoost模型,這里我們再定義并訓練了一個只包含NGBoost和CatBoost的平均模型,通過在訓練和驗證數據集上分別訓練這兩個模型,再對測試集進行預測,并計算均方誤差(MSE)、均方根誤差(RMSE)、平均絕對誤差(MAE)和擬合優度(R-squared),以評估組合模型的預測性能
可以發現在這個數據集上,NGBoost和CatBoost的平均模型的擬合優度(R-squared)相對于LightGBM、XGBoost、CatBoost和NGBoost的集成模型較好,可能是由于這兩個模型在這個數據集上的數據特征提取和預測方面具有更好的互補性和適應性,同時避免了過多模型組合可能帶來的復雜度和過擬合問題。當然,讀者也可以自行選擇不同的模型進行集成,并給不同的模型賦予不同的權重來進一步優化模型性能
可視化預測結果
plt.figure(figsize=(15, 5), dpi=300)
plt.subplot(1, 2, 1)
# 反標準化預測值
pred_two = y_pred_two * y_std + y_mean
y_test_rescaled = np.array(y_test * y_std + y_mean)
# 計算預測值與真實值差值的絕對值
alpha_values_two = abs(pred_two - y_test_rescaled.reshape(-1))
# 確保 alpha 值在 0 到 1 之間
alpha_values_two = np.clip(alpha_values_two, 0, 1)
plt.scatter(pred_two, y_test_rescaled, color='blue', edgecolor='k', s=50, alpha=alpha_values_two, label='預測值 vs 真實值')
plt.title('two model 預測值與真實值對比圖', fontsize=16)
plt.xlabel('預測值', fontsize=14)
plt.ylabel('真實值', fontsize=14)
max_val_two = max(max(pred_two), max(y_test_rescaled))
min_val_two = min(min(pred_two), min(y_test_rescaled))
plt.plot([min_val_two, max_val_two], [min_val_two, max_val_two], color='red', linestyle='--', linewidth=2, label='x=y')
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
plt.subplot(1, 2, 2)
pred_four = y_pred_four * y_std + y_mean
alpha_values_four = abs(pred_four - y_test_rescaled.reshape(-1))
alpha_values_four = np.clip(alpha_values_four, 0, 1)
plt.scatter(pred_four, y_test_rescaled, color='green', edgecolor='k', s=50, alpha=alpha_values_four, label='預測值 vs 真實值')
plt.title('four model 預測值與真實值對比圖', fontsize=16)
plt.xlabel('預測值', fontsize=14)
plt.ylabel('真實值', fontsize=14)
max_val_four = max(max(pred_four), max(y_test_rescaled))
min_val_four = min(min(pred_four), min(y_test_rescaled))
plt.plot([min_val_four, max_val_four], [min_val_four, max_val_four], color='red', linestyle='--', linewidth=2, label='x=y')
plt.grid(True, linestyle='--', alpha=0.7)
plt.legend()
plt.show()
兩幅可視化分別為NGBoost和CatBoost集成模型、LightGBM、XGBoost、CatBoost和NGBoost集成模型的可視化,圖中橫軸表示模型預測的值,縱軸表示真實的標簽值,每個點的透明度(alpha 值)根據預測值與真實值的差異大小動態調整,差異越大的點透明度越低,紅色虛線表示理想情況下預測值等于真實值的對角線