在評估任何複雜模型之前,建立一個簡單的基準模型是非常重要的。這不僅提供了比較的基準,還能幫助我們理解特徵的預測能力。
使用DummyRegressor建立基準
scikit-learn的DummyRegressor
允許我們建立一個非常簡單的模型作為基準:
# 匯入函式庫
from sklearn.datasets import load_boston
from sklearn.dummy import DummyRegressor
from sklearn.model_selection import train_test_split
# 載入資料
boston = load_boston()
# 建立特徵和目標
features, target = boston.data, boston.target
# 分割訓練集和測試集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=0)
# 建立虛擬迴歸器
dummy = DummyRegressor(strategy='mean')
# "訓練"虛擬迴歸器
dummy.fit(features_train, target_train)
# 取得R方分數
print(dummy.score(features_test, target_test))
# 輸出:-0.0011193592039553391
這段程式碼建立了一個虛擬迴歸器,它使用訓練集的平均值來預測所有樣本。首先,載入波士頓房價資料集並分割為訓練集和測試集。然後建立一個DummyRegressor
並設定策略為'mean'
,這意味著它會以訓練集的平均值作為預測值。擬合模型後,計算其在測試集上的R方分數。負值接近於0的R方分數表明這個模型幾乎沒有解釋能力。
為了比較,我們可以訓練一個簡單的線性迴歸模型並評估其效能:
# 匯入函式庫
from sklearn.linear_model import LinearRegression
# 訓練簡單的線性迴歸模型
ols = LinearRegression()
ols.fit(features_train, target_train)
# 取得R方分數
print(ols.score(features_test, target_test))
# 輸出:0.63536207866746675
這段程式碼訓練了一個線性迴歸模型並計算其在測試集上的R方分數。R方分數為0.635表明該模型能夠解釋目標變數約63.5%的方差,這比虛擬迴歸器的效能要好得多。這證明瞭我們的特徵確實包含有用的訊息,並且線性迴歸模型能夠有效地利用這些訊息。
DummyRegressor的應用價值
DummyRegressor
允許我們建立一個非常簡單的模型,作為比較實際模型的基準。這在模擬產品或系統中"天真"的現有預測過程時特別有用。例如,一個產品最初可能被硬編碼為假設所有新使用者第一個月都會消費100美元,無論他們的特徵如何。如果我們將這種假設編碼到基準模型中,我們就能具體說明使用機器學習方法的好處。
DummyRegressor
使用strategy
引數來設定預測方法,包括使用訓練集中的平均值或中位數。此外,如果我們將strategy
設為'constant'
並使用constant
引數,我們可以設定虛擬迴歸器為每個觀測值預測某個常數值:
# 建立預測所有觀測值為20的虛擬迴歸器
clf = DummyRegressor(strategy='constant', constant=20)
clf.fit(features_train, target_train)
# 評估分數
print(clf.score(features_test, target_test))
# 輸出:-0.065105020293257265
這段程式碼建立了一個虛擬迴歸器,它對所有輸入資料都預測常數值20。擬合模型後,計算其在測試集上的R方分數。負值表明這個固定預測值20的模型比使用平均值作為預測的模型表現更差。
關於score
方法,預設情況下,它回傳決定係數(R方,R²)分數:
R² = 1 - Σ(yi - ŷi)² / Σ(yi - ȳ)²
其中yi
是目標觀測值的真實值,ŷi
是預測值,ȳ
是目標向量的平均值。
R²
越接近1,表示特徵解釋的目標向量方差越多。當R²為負值時,表明模型的預測比簡單地使用平均值作為預測還要差。
建立基準分型別
對於分類別務,同樣重要的是建立一個簡單的基準分類別來比較我們的實際模型。
使用DummyClassifier建立基準
scikit-learn的DummyClassifier
提供了一個簡單的基準分類別:
# 匯入函式庫
from sklearn.datasets import load_iris
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import train_test_split
# 載入資料
iris = load_iris()
# 建立目標向量和特徵矩陣
features, target = iris.data, iris.target
# 分割為訓練集和測試集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=0)
# 建立虛擬分類別
dummy = DummyClassifier(strategy='uniform', random_state=1)
# "訓練"模型
dummy.fit(features_train, target_train)
# 取得準確率分數
print(dummy.score(features_test, target
分型別評估:超越表面準確率的深度分析
在機器學習領域,分類別的評估往往比訓練模型本身更為關鍵。一個經過精心設計的評估方法能夠揭示模型的真實能力,並指導後續的最佳化向。在實務應用中,我發現許多開發者過度依賴準確率(accuracy)這一單一指標,而忽略了在不平衡資料集上的潛在陷阱。
本文將帶領你從基礎評估指標開始,逐步深入到ROC曲線分析和閾值調整的高階技巧,協助你全面掌握二元分類別的評估方法。
基礎評估指標:超越準確率的迷思
準確率作為最直觀的評估指標,其定義簡單明瞭:正確預測的觀測值比例。然而,這種表面上的簡單性掩蓋了其在實際應用中的潛在問題。
混淆矩陣的四個關鍵元素
要理解各種評估指標,必須先掌握混淆矩陣的基本概念:
- 真陽性(TP):正確預測為正類別的觀測值數量
- 真陰性(TN):正確預測為負類別的觀測值數量
- 假陽性(FP):錯誤預測為正類別的觀測值數量,又稱第一類別誤
- 假陰性(FN):錯誤預測為負類別的觀測值數量,又稱第二類別誤
根據這些元素,準確率的計算公式為:
準確率 = (TP + TN) / (TP + TN + FP + FN)
讓我們使用scikit-learn實作一個簡單的準確率評估:
# 載入必要的套件
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
# 生成特徵矩陣與目標向量
X, y = make_classification(n_samples=10000,
n_features=3,
n_informative=3,
n_redundant=0,
n_classes=2,
random_state=1)
# 建立邏輯迴歸模型
logit = LogisticRegression()
# 使用準確率進行交叉驗證
cross_val_score(logit, X, y, scoring="accuracy")
這段程式碼首先使用make_classification
建立了一個人工合成的二元分類別題,包含10,000個樣本和3個特徵。接著建立一個邏輯迴歸模型,並使用cross_val_score
函式進行交叉驗證,評估指標設為準確率。輸出結果是一個包含三個值的陣列(預設為3折交叉驗證),每個值代表一次驗證的準確率,大約都在95%左右。
準確率的陷阱:不平衡資料集問題
雖然準確率直觀易懂,但在處理不平衡資料集時會導致嚴重誤導。想像一個極端情況:在一個罕見癌症檢測模型中,只有0.1%的人口患有該癌症。如果我們簡單地預測所有人都沒有癌症,準確率就高達99.9%,但這樣的模型毫無預測價值。
這種現象稱為「準確率悖論」,也是為什麼我們需要其他評估指標的主要原因。
進階評估指標:精確率、召回率與F1分數
為了克服準確率的侷限性,機器學習實踐中引入了三個關鍵指標:精確率、召回率和F1分數。
精確率:預測為正的準確性
精確率測量的是模型預測為正類別的準確程度:
精確率 = TP / (TP + FP)
具有高精確率的模型非常「謹慎」,只有在非常確定時才會預測一個觀測值為正類別。在scikit-learn中,可以這樣評估精確率:
# 使用精確率進行交叉驗證
cross_val_score(logit, X, y, scoring="precision")
召回率:識別正類別的能力
召回率衡量模型識別所有正類別觀測值的能力:
召回率 = TP / (TP + FN)
具有高召回率的模型較為「樂觀」,傾向於預測更多觀測值為正類別,以避免漏掉真正的正類別。評估召回率的程式碼如下:
# 使用召回率進行交叉驗證
cross_val_score(logit, X, y, scoring="recall")
F1分數:精確率和召回率的調和平均
在實務應用中,我們通常需要在精確率和召回率之間取得平衡,而F1分數正是為此設計的指標:
F1 = 2 × (精確率 × 召回率) / (精確率 + 召回率)
F1分數是精確率和召回率的調和平均數,給予兩者同等權重。當F1分數高時,表示模型在精確率和召回率方面都表現良好:
# 使用F1分數進行交叉驗證
cross_val_score(logit, X, y, scoring="f1")
上述三個程式碼片段分別使用精確率、召回率和F1分數作為評估指標進行交叉驗證。輸出結果顯示,在這個平衡的資料集上,三種指標的結果非常接近,都在95%左右。這是因為我們使用的是人工生成的平衡資料集。在實際應用中,尤其是面對不平衡資料集時,這些指標通常會有明顯差異。
直接計算評估指標
除了使用cross_val_score
進行交叉驗證外,我們也可以在已有預測結果的情況下直接計算評估指標:
# 載入套件
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 建立訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X,
y,
test_size=0.1,
random_state=1)
# 訓練模型並預測
y_hat = logit.fit(X_train, y_train).predict(X_test)
# 計算準確率
accuracy_score(y_test, y_hat)
這段程式碼首先使用train_test_split
將資料分成訓練集和測試集,測試集佔總資料的10%。接著使用訓練集訓練邏輯迴歸模型,並對測試集進行預測,得到預測值y_hat
。最後使用accuracy_score
函式運算預測值與實際值的準確率,結果約為94.7%。
這種方法特別適用於需要進一步分析模型預測結果的情況,例如當我們需要繪製混淆矩陣或計算其他未包含在cross_val_score
中的評估指標時。
ROC曲線:評估分類別閾值的強大工具
在二元分類別題中,模型通常會為每個觀測值輸出一個屬於正類別的機率,然後設定一個閾值(預設通常為0.5):高於閾值則預測為正類別,低於閾值則預測為負類別。
ROC曲線(Receiver Operating Characteristic curve)是評估不同機率閾值下分類別效能的強大工具。它透過繪製不同閾值下的真陽性率(TPR)與假陽性率(FPR)來展示模型的表現:
# 載入套件
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.model_selection import train_test_split
# 建立特徵矩陣和目標向量
features, target = make_classification(n_samples=10000,
n_features=10,
n_classes=2,
n_informative=3,
random_state=3)
# 分割訓練集和測試集
features_train, features_test, target_train, target_test = train_test_split(
features, target, test_size=0.1, random_state=1)
# 建立分類別
logit = LogisticRegression()
# 訓練模型
logit.fit(features_train, target_train)
# 取得預測機率
target_probabilities = logit.predict_proba(features_test)[:,1]
# 計算真陽性率和假陽性率
false_positive_rate, true_positive_rate, threshold = roc_curve(target_test,
target_probabilities)
# 繪製ROC曲線
plt.title("Receiver Operating Characteristic")
plt.plot(false_positive_rate, true_positive_rate)
plt.plot([0, 1], ls="--")
plt.plot([0, 0], [1, 0], c=".7"), plt.plot([1, 1], c=".7")
plt.ylabel("True Positive Rate")
plt.xlabel("False Positive Rate")
plt.show()
這段程式碼首先建立了一個更複雜的分類別題,包含10,000個樣本和10個特徵,但只有3個特徵是有訊息的。然後將資料分割為訓練集和測試集,訓練邏輯迴歸模型,並取得模型對測試集的預測機率。
接著使用roc_curve
函式運算不同閾值下的真陽性率(TPR)和假陽性率(FPR),並繪製ROC曲線。在這個曲線中:
- 左上角(0,1)代表完美分類別FPR=0, TPR=1)
- 對角線代表隨機猜測的效果
- 曲線越靠近左上角,表示模型效能越好
閾值調整:平衡敏感度與特異性
分類別的閾值調整是一項重要的模型微調技術,能夠根據具體業務需求最佳化型表現。
理解預測機率
使用predict_proba
方法,我們可以取得模型對每個觀測值的預測機率:
# 取得預測機率
logit.predict_proba(features_test)[0:1]
這會回傳類別array([[ 0.8688938, 0.1311062]])
的結果,表示第一個觀測值有約87%的機率屬於負類別,13%的機率屬於正類別。
我們可以透過classes_
屬性檢視類別標籤的順序:
logit.classes_
輸出array([0, 1])
表示第一列是類別0的機率,第二列是類別1的機率。
閾值調整的實際應用
閾值調整是根據業務需求平衡真陽性率(TPR)和假陽性率(FPR)的過程:
# 檢視特定閾值的TPR和FPR
print("閾值:", threshold[116])
print("真陽性率:", true_positive_rate[116])
print("假陽性率:", false_positive_rate[116])
這會輸出閾值約為0.53時,TPR約為0.81,FPR約為0.15。
如果我們提高閾值要求,例如將閾值提高到約0.8:
print("閾值:", threshold[45])
print("真陽性率:", true_positive_rate[45])
print("假陽性率:", false_positive_rate[45])
結果顯示TPR降至約0.56,但FPR也大幅降至約0.05。
這個閾值調整的過程展示了分類別的關鍵權衡:提高閾值會降低FPR(減少假警示),但也會降低TPR(增加漏報);相反,降低閾值會提高TPR(減少漏報),但也會提高FPR(增加假警示)。
在實際應用中,這種權衡需要根據具體業務成本來決定。例如:
- 在癌症診斷中,漏診的成本遠高於誤診,因此我們可能會選擇較低的閾值,提高TPR,即使這會增加FPR
- 在垃圾郵件過濾中,將正常郵件誤判為垃圾郵件的成本較高,因此可能選擇較高的閾值,降低FPR,即使這會降低TPR
ROC 曲線的進階應用與模型評估
ROC 曲線不僅能視覺化呈現真陽性率(TPR)與假陽性率(FPR)之間的權衡關係,更是評估模型整體效能的重要工具。當一個模型表現越好,其 ROC 曲線會越接近左上角,導致曲線下面積越大。這就是為何曲線下面積(AUCROC)成為判斷模型在所有可能閾值下整體品質的通用指標。
曲線下面積的計算與解釋
AUCROC 的值越接近 1,代表模型效能越佳。在 scikit-learn 中,我們可以使用 roc_auc_score
函式輕鬆計算這個指標:
# 計算 ROC 曲線下面積
roc_auc_score(target_test, target_probabilities)
執行上述程式碼後,得到的結果是 0.9073,表示這個模型有著優秀的效能。從我的經驗來看,AUCROC 值超過 0.9 的模型在大多數應用場景中都能提供相當可靠的預測結果。
AUCROC 實際上代表了一個重要概念:從所有正類別本和負類別本的配對中隨機選取一對,模型正確將正樣本的預測機率排在負樣本之前的機率。值為 0.9073 意味著模型有 90.73% 的機會正確排序一對正負樣本,這是評估二元分類別能力的直觀方式。
多類別分類別的評估策略
當面對三個或更多類別的分類別題時,評估模型效能需要不同的策略。這類別題在實際應用中非常見,比如我在處理影像識別和自然語言處理任務時經常遇到的情況。
使用交叉驗證與多類別評估指標
對於多類別分類別,我們可以使用交叉驗證搭配能處理多個類別的評估指標:
# 載入必要的函式庫rom sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
# 生成特徵矩陣和目標向量
features, target = make_classification(
n_samples=10000,
n_features=3,
n_informative=3,
n_redundant=0,
n_classes=3,
random_state=1
)
# 建立邏輯迴歸模型
logit = LogisticRegression()
# 使用準確率進行交叉驗證
cross_val_score(logit, features, target, scoring='accuracy')
這段程式碼首先生成了一個具有 10,000 個樣本、3 個特徵的合成資料集,其中目標變數有 3 個類別。然後建立邏輯迴歸模型並使用準確率作為評估指標進行交叉驗證。結果顯示模型在三個折疊上的準確率分別約為 0.837、0.826 和 0.813,表現相當穩定與良好。
處理類別不平衡的評估策略
當類別分佈不平衡時(這在實際專案中極為常見),單純使用準確率可能會產生誤導。在這種情況下,我們需要採用其他評估指標。
許多原本為二元分類別計的指標可以擴充套件到多類別情境。精確度(Precision)、召回率(Recall)和 F1 分數是三個常用的指標,可以透過將多類別問題視為一組二元分類別題來應用:
# 使用巨集均 F1 分數進行交叉驗證
cross_val_score(logit, features, target, scoring='f1_macro')
這段程式碼使用了 f1_macro
作為評估指標,這意味著系統會為每個類別計算 F1 分數,然後取平均值,每個類別權重相同。結果顯示模型在三個折疊上的巨集均 F1 分數分別約為 0.836、0.826 和 0.813,與準確率結果相當接近,表明各個類別的效能相對平均。
平均方法的選擇
在多類別評估中,平均方法的選擇至關重要:
巨集均(macro):計算每個類別的指標分數平均值,每個類別權重相同。當你希望所有類別被平等對待時使用,即使某些類別的樣本數量很少。
加權平均(weighted):計算每個類別的指標分數平均值,但根據該類別在資料中的比例加權。當你希望反映資料集中實際的類別分佈時使用。
微平均(micro):將所有類別的觀測值-類別組合視為整體來計算指標。當你更關注整體效能而非各個類別的效能時使用。
我在處理多類別問題時,經常先使用巨集均來確保模型對所有類別都有不錯的表現,然後再根據業務需求考慮其他平均方法。
透過混淆矩陣視覺化分類別效能
當我們擁有測試資料的預測類別和真實類別時,視覺化比較模型品質的最佳方法之一就是使用混淆矩陣。
建立與解釋混淆矩陣
混淆矩陣比較預測類別和真實類別,提供直觀與詳細的模型效能視覺化:
# 載入必要的函式庫mport matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import pandas as pd
# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target
class_names = iris.target_names
# 建立訓練集和測試集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=1
)
# 建立邏輯迴歸模型
classifier = LogisticRegression()
# 訓練模型並進行預測
target_predicted = classifier.fit(features_train, target_train).predict(features_test)
# 建立混淆矩陣
matrix = confusion_matrix(target_test, target_predicted)
# 建立 pandas 資料框
dataframe = pd.DataFrame(matrix, index=class_names, columns=class_names)
# 建立熱圖
sns.heatmap(dataframe, annot=True, cbar=None, cmap="Blues")
plt.title("混淆矩陣")
plt.tight_layout()
plt.ylabel("真實類別")
plt.xlabel("預測類別")
plt.show()
這段程式碼使用鳶尾花資料集建立了一個邏輯迴歸分類別,並使用混淆矩陣視覺化其效能。程式首先將資料分割為訓練集和測試集,然後訓練模型並在測試集上進行預測。接著建立混淆矩陣並使用 Seaborn 的熱圖功能將其視覺化。這種視覺化方法讓我們能夠一目瞭然地看出模型在哪些類別上表現良好,以及常見的錯誤模式。
混淆矩陣的優勢
混淆矩陣是分類別效能視覺化的有效工具,主要有以下優勢:
直觀解釋性:每列代表預測類別,每行顯示真實類別,每個單元格顯示一種可能的真實-預測類別組合。
錯誤模式識別:不僅能看出模型錯在哪裡,還能看出錯誤的方式。例如,上面的模型能輕易區分 Iris setosa,但在區分 Iris virginica 和 Iris versicolor 時較為困難。
適用於任何類別數量:混淆矩陣適用於任何數量的類別,雖然類別太多時可能難以閱讀。
完美的模型在混淆矩陣中只有對角線上有數值,其餘位置都是零。而表現不佳的模型則會使觀測值計數均勻分佈在各個單元格中。
迴歸模型的評估技巧
迴歸問題需要不同的評估指標,因為我們預測的是連續值而非離散類別。
均方誤差(MSE)的應用
均方誤差是評估迴歸模型最常用的指標之一:
# 載入必要的函式庫rom sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
# 生成特徵矩陣和目標向量
features, target = make_regression(
n_samples=100,
n_features=3,
n_informative=3,
n_targets=1,
noise=50,
coef=False,
random_state=1
)
# 建立線性迴歸模型
ols = LinearRegression()
# 使用負均方誤差進行交叉驗證
cross_val_score(ols, features, target, scoring='neg_mean_squared_error')
這段程式碼生成了一個迴歸問題的合成資料集,並使用線性迴歸模型進行建模。scikit-learn 中的交叉驗證函式要求所有指標都是越高越好,因此使用負均方誤差(值越接近零表示模型越好)。結果顯示模型在三個折疊上的負均方誤差分別約為 -1718、-3103 和 -1377,表明模型在第二個折疊上表現較差。
判定係數(R²)的應用
判定係數(R²)是另一個常用的迴歸評估指標:
# 使用 R² 進行交叉驗證
cross_val_score(ols, features, target, scoring='r2')
這段程式碼使用 R² 作為評估指標進行交叉驗證。R² 值介於 0 和 1 之間,越接近 1 表示模型解釋的變異比例越高。結果顯示模型在三個折疊上的 R² 值分別約為 0.878、0.764 和 0.892,整體表現良好,能解釋大部分的目標變數變異。
均方誤差的數學解釋
均方誤差的正式定義為:
MSE = (1/n) × Σ(y_i - ŷ_i)²
其中 n 是觀測值數量,y_i 是第 i 個觀測值的真實值,ŷ_i 是模型對第 i 個觀測值的預測值。
MSE 測量所有預測值與真實值之間距離的平方和。MSE 值越高,總平方誤差越大,模型表現越差。平方誤差有許多數學優勢,包括使所有誤差值為正,但一個經常被忽視的含義是平方會懲罰少數大誤差甚於多數小誤差,即使誤差的絕對值總和相同。
例如,假設有兩個模型 A 和 B,各有兩個觀測值:
- 模型 A 的誤差為 0 和 10,因此其 MSE 為 (0² + 10²)/2 = 50
- 模型 B 的誤差為 5 和 5,因此其 MSE 為 (5² + 5²)/2 = 25
從上面的計算可以看出,即使兩個模型的誤差絕對值總和相同(都是 10),但由於平方的作用,模型 B 的 MSE 更低,因此被認為更優。這突顯了 MSE 對極端誤差特別敏感的特性。
在實際應用中,我發現根據問題的性質選擇合適的評估指標至關重要。如果極端誤差對業務影響較大,MSE 是個不錯的選擇;而如果希望獲得更容易解釋的整體效能指標,則 R² 可能更為適合。
模型評估是機器學習流程中不可或缺的一環。透過正確理解和應用不同的評估指標,我們能夠更全面地瞭解模型的優缺點,並據此進行改進。無論是使用 ROC 曲線評估二元分類別,利用混淆矩陣
迴歸與分群模型的評估技巧:從基礎到進階
在機器學習專案中,選擇正確的評估指標是決定模型成敗的關鍵因素之一。不同類別的模型需要不同的評估方法,而理解這些評估指標的內涵與限制,能夠幫助我們更準確地判斷模型效能。
迴歸模型評估:均方誤差(MSE)的深度解析
均方誤差(Mean Squared Error, MSE)是評估迴歸模型的基本指標。在實作中,MSE計算方式非常直觀:
import numpy as np
from sklearn.metrics import mean_squared_error
# 真實值
y_true = [10, 20, 30, 40]
# 預測值
y_pred = [8, 22, 31, 38]
# 計算MSE
mse = mean_squared_error(y_true, y_pred)
print(f"MSE: {mse}")
這段程式碼展示瞭如何使用scikit-learn計算均方誤差。我們定義了真實值和預測值兩組資料,然後使用mean_squared_error
函式運算MSE。MSE的計算原理是將每個預測值與真實值的差異平方後取平均,這樣做的好處是能夠放大較大的誤差,使模型對離群值更為敏感。
MSE的有趣特性在於它對誤差大小的敏感度。舉個例子來說:
- 模型A:兩個預測的誤差分別為0和10,MSE為
(0² + 10²)/2 = 100/2 = 50
- 模型B:兩個預測的誤差都是5,MSE為
(5² + 5²)/2 = 50/2 = 25
這兩個模型的總誤差都是10,但MSE會認為模型B(MSE=25)優於模型A(MSE=50)。這是因為MSE透過平方操作,對大誤差的懲罰更為嚴厲。在實務中,這個特性通常是有益的,因為我們往往更關注那些偏差較大的預測。
在使用scikit-learn時有一點需要特別注意:該函式庫認為評估指標是越高越好,但MSE顯然是越低越好。因此scikit-learn提供了neg_mean_squared_error
這個評估引數,它計算的是MSE的負值。
R平方(R²):解釋變異的能力
除了MSE,R平方(R²)也是評估迴歸模型的重要指標。R平方衡量的是模型解釋目標變數變異的比例:
from sklearn.metrics import r2_score
# 真實值
y_true = [10, 20, 30, 40]
# 預測值
y_pred = [8, 22, 31, 38]
# 計算R平方
r2 = r2_score(y_true, y_pred)
print(f"R²: {r2}")
R平方的計算公式為:R² = 1 - (殘差平方和/總變異平方和)。其中殘差平方和是預測值與真實值差的平方和,總變異平方和是真實值與真實值平均數差的平方和。
R平方的值範圍在0到1之間,越接近1表示模型解釋的變異越多,模型表現越好。在某些情況下,R平方也可能為負值,這表示模型的預測甚至不如簡單地預測目標變數的均值。
從實務角度看,R平方有一個很好的特性:它具有明確的解釋性。例如,R平方為0.75意味著模型解釋了75%的目標變數變異。這種直觀的解釋使R平方在與非技術背景的利益相關者溝通時特別有用。
分群模型的評估挑戰
評估分群模型是機器學習中的一個獨特挑戰。與監督式學習不同,分群屬於無監督學習,通常沒有真實的標籤可以用來比較。
在實務中,我發現大多數人希望能像評估分型別那樣評估分群模型,但事實上這通常是不可能的。如果你已經有了標籤資料,那麼使用無監督學習方法而非監督學習方法可能是在為難自己。
儘管如此,我們仍然可以評估分群本身的品質。直觀上,好的分群應該具有兩個特性:
- 同一群集內的觀測值之間距離很小(高密度群集)
- 不同群集之間的距離很大(群集間分離良好)
輪廓係數(Silhouette Coefficient)是同時衡量這兩個特性的指標:
import numpy as np
from sklearn.metrics import silhouette_score
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# 生成特徵矩陣
features, _ = make_blobs(
n_samples=1000,
n_features=10,
centers=2,
cluster_std=0.5,
shuffle=True,
random_state=1
)
# 使用K-means進行分群
model = KMeans(n_clusters=2, random_state=1).fit(features)
# 取得預測的群集
predicted_clusters = model.labels_
# 評估模型
score = silhouette_score(features, predicted_clusters)
print(f"輪廓係數: {score}")
這段程式碼首先生成具有明顯兩群結構的合成資料,然後使用K-means演算法進行分群,最後計算輪廓係數評估分群品質。
輪廓係數的計算根據每個觀測值與同群集內其他觀測值的平均距離(a_i),以及與最近的不同群集中觀測值的平均距離(b_i)。對於觀測值i,其輪廓係數為:
s_i = (b_i - a_i) / max(a_i, b_i)
輪廓係數的值範圍在-1到1之間。接近1表示該觀測值與自己的群集非常比對,而與其他群集分離良好;接近0表示觀測值位於群集邊界附近;負值表示該觀測值可能被分到錯誤的群集。
silhouette_score
函式回傳的是所有觀測值輪廓係數的平均值。在實務應用中,我通常將輪廓係數作為調整分群引數(如K-means中的k值)的指導。
建立自定義評估指標
有時標準評估指標可能無法完全滿足特定問題的需求。在這種情況下,建立自定義評估指標是個不錯的選擇:
from sklearn.metrics import make_scorer, r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.datasets import make_regression
# 生成特徵矩陣和目標向量
features, target = make_regression(
n_samples=100,
n_features=3,
random_state=1
)
# 建立訓練集和測試集
features_train, features_test, target_train, target_test = train_test_split(
features, target, test_size=0.10, random_state=1
)
# 建立自定義指標
def custom_metric(target_test, target_predicted):
# 計算R平方分數
r2 = r2_score(target_test, target_predicted)
# 回傳R平方分數
return r2
# 建立評分器並指定較高分數更好
score = make_scorer(custom_metric, greater_is_better=True)
# 建立嶺迴歸模型
classifier = Ridge()
# 訓練模型
model = classifier.fit(features_train, target_train)
# 應用自定義評分器
result = score(model, features_test, target_test)
print(f"自定義評分: {result}")
這段程式碼展示瞭如何建立自定義評估指標並將其與scikit-learn的模型評估流程整合。雖然此例中的自定義指標僅是對內建R²評分的封裝,但它展示了基本原理。
在實際應用中,我常需要建立複合指標,例如結合業務成本和模型準確性的評估標準。make_scorer
函式使這一過程變得簡單:只需定義一個接受真實值和預測值的函式,並使用make_scorer
將其轉換為scikit-learn相容的評分器。
需要特別注意的是greater_is_better
引數,它指定了更高的分數是否意味著更好的模型。對於像R²這樣的指標,較高的值確實表示更好的表現;但對於像MSE這樣的指標,情況則相反。
視覺化訓練集大小對模型表現的影響
瞭解訓練集大小如何影響模型表現是機器學習實踐中的重要環節。學習曲線是一種有效的視覺化工具:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
# 載入資料
digits = load_digits()
# 建立特徵矩陣和目標向量
features, target = digits.data, digits.target
# 為不同訓練集大小建立CV訓練和測試分數
train_sizes, train_scores, test_scores = learning_curve(
# 分類別
RandomForestClassifier(),
# 特徵矩陣
features,
# 目標向量
target,
# 折數
cv=10,
# 效能指標
scoring='accuracy',
# 使用所有CPU核心
n_jobs=-1,
# 50個訓練集大小點
train_sizes=np.linspace(0.01, 1.0, 50)
)
# 計算訓練集分數的均值和標準差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
# 計算測試集分數的均值和標準差
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 繪製線條
plt.plot(train_sizes, train_mean, '--', color="#111111", label="訓練分數")
plt.plot(train_sizes, test_mean, color="#111111", label="交叉驗證分數")
# 繪製誤差帶
plt.fill_between(
train_sizes,
train_mean - train_std,
train_mean + train_std,
color="#DDDDDD"
)
plt.fill_between(
train_sizes,
test_mean - test_std,
test_mean + test_std,
color="#DDDDDD"
)
# 建立圖表
plt.title("學習曲線")
plt.xlabel("訓練集大小")
plt.ylabel("準確率")
plt.legend(loc="best")
plt.tight_layout()
plt.show()
這段程式碼生成學習曲線,展示了隨著訓練集大小增加,模型在訓練集和交叉驗證集上的表現變化。
學習曲線是診斷模型是否存在高偏差(欠擬合)或高方差(過擬合)問題的有力工具。透過觀察曲線,可以獲得以下洞察:
如果訓練分數和交叉驗證分數都很低,與兩條曲線接近,這表明模型存在高偏差問題(欠擬合)。增加模型複雜度可能有所幫助。
如果訓練分數遠高於交叉驗證分數,這表明模型存在高方差問題(過擬合)。增加訓練資料或減少模型複雜度可能是解決方案。
如果隨著訓練集大小增加,交叉驗證分數持續提高與未出現平台期,這表明增加更多訓練資料可能會進一步提升模型效能。
在實務中,我經常使用學習曲線來決定是否值得收集更多資料,或者是否應該調整模型複雜度。這種視覺化方法比單純依賴數字指標能提供更豐富的洞察。
評估指標選擇的實用建議
在選擇評估指標時,我建議考慮以下幾點:
業務目標對齊:評估指標應該反映業務實際關心的問題。例如,如果錯誤預測的成本不對稱(如醫療診斷),則應選擇能反映這種不對稱性的指標。
模型類別比對
模型評估與選擇的系統性方法
機器學習工作流程中,模型訓練完成後的評估與選擇環節往往決定了最終系統的實際效能。在實務中,這個過程不僅是檢視幾個數字那麼簡單,而是需要系統性地分析模型表現、理解資料需求,以及最佳化引數設定。本文將帶領讀者深入瞭解這些關鍵技術,從視覺化評估到自動化選擇,建立完整的模型評估與最佳化程。
學習曲線:理解資料需求與模型潛力
在機器學習專案中,一個常見的問題是:「我們是否需要更多資料?」這個看似簡單的問題實際上需要透過系統性分析才能得到答案。學習曲線(Learning Curve)提供了直觀的方式來評估模型隨著訓練資料增加而表現的變化趨勢。
以隨機森林分類別為例,我想了解模型在不同訓練集大小下的表現:
import matplotlib.pyplot as plt
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import learning_curve
# 載入資料
# 假設features是特徵矩陣,target是目標向量
features = ... # 您的特徵矩陣
target = ... # 您的目標向量
# 設定不同的訓練集大小比例
train_sizes = np.linspace(0.01, 1.0, 50)
# 計算學習曲線
train_sizes, train_scores, test_scores = learning_curve(
RandomForestClassifier(),
features,
target,
train_sizes=train_sizes,
cv=5,
scoring='accuracy',
n_jobs=-1
)
# 計算平均值和標準差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 繪製學習曲線
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_mean, label='訓練準確率', color='blue', marker='o')
plt.plot(train_sizes, test_mean, label='驗證準確率', color='green', marker='s')
# 繪製誤差範圍
plt.fill_between(train_sizes, train_mean - train_std, train_mean + train_std,
alpha=0.15, color='blue')
plt.fill_between(train_sizes, test_mean - test_std, test_mean + test_std,
alpha=0.15, color='green')
plt.title('隨機森林學習曲線')
plt.xlabel('訓練樣本數量')
plt.ylabel('準確率')
plt.legend(loc='lower right')
plt.grid(True)
plt.show()
這段程式碼展示瞭如何使用scikit-learn的learning_curve
函式來分析模型隨訓練資料量增加的表現變化。關鍵步驟包括:
- 設定50個不同的訓練集大小比例,從使用1%的資料到100%的資料
- 對每個訓練集大小進行5折交叉驗證,計算訓練和驗證準確率
- 計算每個大小下的平均準確率和標準差,用於繪製主線和誤差範圍
- 繪製訓練和驗證準確率隨訓練集大小變化的曲線圖
透過這種方式,我們可以直觀地看出:
- 如果驗證準確率曲線在增加資料時仍有明顯上升趨勢,則表明模型可能從更多資料中獲益
- 若曲線已趨於平緩,則增加資料可能帶來的收益有限
- 訓練和驗證準確率的差距反映了模型的過擬合程度
在實際專案中,我發現這種分析對於決定是否投入資源收集更多資料特別有價值,能避免不必要的資料收整合本。
評估指標綜合報告:快速診斷分類別表現
評估分類別效能時,單一指標往往無法全面反映模型的優劣。在實務中,我常使用scikit-learn的classification_report
函式來取得包含精確率、召回率和F1分數等多個指標的綜合報告。
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
class_names = iris.target_names
# 建立訓練集和測試集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=1)
# 建立並訓練邏輯迴歸模型
classifier = LogisticRegression()
model = classifier.fit(features_train, target_train)
target_predicted = model.predict(features_test)
# 生成分類別告
print(classification_report(target_test,
target_predicted,
target_names=class_names))
這段程式碼示範瞭如何使用classification_report
函式來取得分類別效能的全面評估。輸出報告包含每個類別的精確率、召回率、F1分數和支援度(樣本數量),以及所有類別的平均值。
對於鳶尾花分類別務,報告可能顯示:
- setosa類別精確率、召回率和F1分數都達到1.00,表示完美分類別- versicolor類別較高的精確率(1.00)但召回率較低(0.62),意味著模型能準確識別此類別但有些versicolor樣本被誤分為其他類別
- virginica類別較低的精確率(0.60)但召回率很高(1.00),說明模型將所有virginica樣本都正確識別,但也誤將一些其他類別的樣本分類別virginica
在實際工作中,我發現這種報告對於快速診斷模型在不同類別上的表現特別有價值,尤其是在處理不平衡分類別題時。解讀這些指標時,需要結合具體業務場景考慮哪些指標更重要 - 例如在醫療診斷中,高召回率(減少漏診)可能比高精確率更為重要。
超引數效果視覺化:理解模型敏感度
在選擇模型超引數時,瞭解模型效能如何隨著超引數變化而變化是非常有價值的。透過繪製驗證曲線,我們可以直觀地瞭解這種關係。
以下是一個分析隨機森林分類別中樹的數量對模型效能影響的例子:
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import validation_curve
# 載入手寫數字資料集
digits = load_digits()
features, target = digits.data, digits.target
# 建立超引數值範圍
param_range = np.arange(1, 250, 2)
# 計算不同超引數值下的訓練和測試準確率
train_scores, test_scores = validation_curve(
RandomForestClassifier(),
features,
target,
param_name="n_estimators",
param_range=param_range,
cv=3,
scoring="accuracy",
n_jobs=-1)
# 計算平均值和標準差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 繪製驗證曲線
plt.figure(figsize=(10, 6))
plt.plot(param_range, train_mean, label="訓練分數", color="blue")
plt.plot(param_range, test_mean, label="交叉驗證分數", color="green")
# 繪製誤差範圍
plt.fill_between(param_range, train_mean - train_std,
train_mean + train_std, alpha=0.15, color="blue")
plt.fill_between(param_range, test_mean - test_std,
test_mean + test_std, alpha=0.15, color="green")
# 設定圖表
plt.title("隨機森林驗證曲線")
plt.xlabel("樹的數量")
plt.ylabel("準確率")
plt.legend(loc="lower right")
plt.grid(True)
plt.show()
這段程式碼展示瞭如何使用validation_curve
函式來分析隨機森林分類別效能如何隨著樹的數量變化。透過這種視覺化,我們可以觀察到幾個關鍵點:
- 當樹的數量很少時,訓練和驗證準確率都較低,表明模型存在欠擬合
- 隨著樹數量增加,兩條曲線都上升,但最終趨於平緩
- 當曲線趨於平緩後,繼續增加樹的數量帶來的效能提升有限,但會增加計算成本
在實際應用中,這種分析有助於找到計算成本和模型效能之間的平衡點。例如,在這個例子中,我們可能發現使用約100棵樹就能達到接近最佳效能,無需使用250棵樹帶來的額外計算負擔。
這種視覺化方法適用於各種超引數,如SVM的C值、正則化強度、神經網路的層數等,幫助我們更深入地理解模型行為和超引數敏感度。這在計算資源有限的環境中尤為重要。
模型選擇:尋找最佳參陣列合的系統方法
在機器學習實踐中,選擇最佳模型不僅涉及選擇演算法類別,還包括為每個演算法找到最佳的超參陣列合。這個過程稱為模型選擇(Model Selection)或超引數調優(Hyperparameter Tuning)。
網格搜尋:徹底尋找最佳參陣列合
網格搜尋(Grid Search)是一種暴力搜尋方法,它會嘗試超引數空間中所有可能的組合,找出最佳設定。雖然計算成本較高,但它確保了我們不會遺漏任何潛在的最佳設定。
以邏輯迴歸為例,我們可以搜尋不同的正則化類別和強度:
import numpy as np
from sklearn import linear_model, datasets
from sklearn.model_selection import GridSearchCV
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立邏輯迴歸模型
logistic = linear_model.LogisticRegression()
# 設定超引數候選值
penalty = ['l1', 'l2']
C = np.logspace(0, 4, 10) # 10^0 到 10^4 之間的10個值
hyperparameters = dict(C=C, penalty=penalty)
# 建立網格搜尋
grid_search = GridSearchCV(logistic, hyperparameters, cv=5, verbose=1, n_jobs=-1)
# 執行網格搜尋
best_model = grid_search.fit(features, target)
# 輸出最佳引數
print("最佳參陣列合:", best_model.best_params_)
print("最佳交叉驗證分數:", best_model.best_score_)
# 使用最佳模型進行預測
predictions = best_model.predict(features)
這段程式碼展示瞭如何使用GridSearchCV
來系統性地搜尋最佳超參陣列合。在這個例子中,我們:
- 設定了兩種正則化類別(L1和L2)和10個不同的正則化強度值
- 這建立了總共20種不同的參陣列合
- 每種組合都使用5折交叉驗證進行評估
- 使用所有可用的CPU核心(
n_jobs=-1
)來加速搜尋過程 - 最後選擇具有最高交叉驗證分數的參陣列合
網格搜尋的主要優點是徹底性,它會嘗試所有指定的參陣列合。然而,當超引數空間很大或計算資源有限時,這種方法可能效率不高。
在實際專案中,我通常先使用較粗糙的網格進行初步搜尋,確定引數的大致範圍,然後在這個範圍內進行更細緻的搜尋。這種策略在保持結果品質的同時提高了效率。
隨機搜尋:在大型引數空間中的高效探索
當超引數空間非
深入模型選擇:從窮舉搜尋到人工智慧
模型選擇是機器學習工作流程中的關鍵環節,它直接影響模型的效能和泛化能力。在實際應用中,我們常需要從眾多可能的模型設定中挑選出最佳的一個。這個過程不僅包括選擇合適的學習演算法,還涉及調整演算法中的各種超引數。
超引數調整的藝術與科學
超引數是模型訓練前必須設定的引數,它們無法從資料中學習得到。以邏輯迴歸為例,正則化強度(C)和正則化類別(penalty)就是典型的超引數。選擇適當的超引數值對模型效能至關重要,但這往往需要透過反覆試驗才能確定。
在本文中,玄貓將介紹三種高效的模型選擇策略:窮舉網格搜尋、隨機搜尋以及跨演算法模型選擇。每種方法各有優缺點,適用於不同的場景。
窮舉網格搜尋:尋找最佳模型的全面方法
網格搜尋是一種全面但計算成本較高的方法。它透過嘗試所有可能的超參陣列合,確保不會遺漏任何潛在的最佳模型。
網格搜尋的工作原理
在網格搜尋中,我們首先定義每個超引數的可能值集合,然後系統地訓練和評估使用每種值組合的模型。這個過程通常結合交叉驗證,以確保模型選擇的穩健性。
以下是使用scikit-learn的GridSearchCV實作網格搜尋的範例:
# 載入必要的函式庫mport numpy as np
from sklearn import linear_model, datasets
from sklearn.model_selection import GridSearchCV
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立邏輯迴歸模型
logistic = linear_model.LogisticRegression()
# 定義超引數搜尋空間
penalty = ['l1', 'l2']
C = np.logspace(0, 4, 10)
hyperparameters = dict(C=C, penalty=penalty)
# 建立網格搜尋
gridsearch = GridSearchCV(
logistic, hyperparameters, cv=5, verbose=0, n_jobs=-1
)
# 訓練網格搜尋模型
best_model = gridsearch.fit(features, target)
這段程式碼展示瞭如何使用GridSearchCV進行超引數調整。首先載入常用的科學計算和機器學習函式庫後準備鳶尾花資料集。接著建立邏輯迴歸模型並定義兩個超引數的搜尋空間:正則化類別(penalty)和正則化強度(C)。
C值使用np.logspace()
產生10個對數等距的值,從10^0到10^4,這樣的設計能夠高效地探索不同數量級的正則化強度。GridSearchCV將嘗試所有penalty和C值的組合(共20種),並使用5折交叉驗證評估每個組合的效能。引數n_jobs=-1
指示使用所有可用的CPU核心進行平行計算,加速搜尋過程。
檢視網格搜尋結果
網格搜尋完成後,我們可以檢視找到的最佳超引數:
# 檢視最佳超引數
print('最佳正則化類別:', best_model.best_estimator_.get_params()['penalty'])
print('最佳C值:', best_model.best_estimator_.get_params()['C'])
值得注意的是,GridSearchCV在確定最佳超引數後,會自動使用這些超引數在整個資料集上重新訓練一個模型。這個模型可以像其他scikit-learn模型一樣使用:
# 使用最佳模型預測
predictions = best_model.predict(features)
網格搜尋的實用技巧
在使用網格搜尋時,有幾個實用的技巧值得注意:
verbose引數:對於耗時較長的搜尋,設定
verbose
引數(值範圍1-3)可以顯示搜尋進度,提供即時反饋。搜尋空間設計:設計合理的搜尋空間至關重要。對於連續引數,通常使用對數刻度更有效,因為它可以在較廣的範圍內探索不同數量級的值。
計算資源考量:網格搜尋的計算成本隨著超參陣列合數量呈指數增長。在資源有限的情況下,可能需要考慮更高效的方法。
隨機搜尋:計算效率與搜尋效果的平衡
當超引數空間非常大或計算資源有限時,窮舉網格搜尋可能變得不切實際。在這種情況下,隨機搜尋提供了一個計算效率更高的替代方案。
隨機搜尋的工作原理
隨機搜尋不是嘗試所有可能的超參陣列合,而是從使用者供的分佈中隨機抽樣指定數量的組合。研究表明,在許多情況下,隨機搜尋能以較少的計算資源達到與網格搜尋相當的效果。
以下是使用RandomizedSearchCV實作隨機搜尋的範例:
# 載入必要的函式庫rom scipy.stats import uniform
from sklearn import linear_model, datasets
from sklearn.model_selection import RandomizedSearchCV
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立邏輯迴歸模型
logistic = linear_model.LogisticRegression()
# 建立超引數搜尋空間
penalty = ['l1', 'l2']
C = uniform(loc=0, scale=4) # 均勻分佈
hyperparameters = dict(C=C, penalty=penalty)
# 建立隨機搜尋
randomizedsearch = RandomizedSearchCV(
logistic, hyperparameters, random_state=1, n_iter=100, cv=5,
verbose=0, n_jobs=-1
)
# 訓練隨機搜尋模型
best_model = randomizedsearch.fit(features, target)
這段程式碼展示瞭如何使用RandomizedSearchCV進行超引數隨機搜尋。與網格搜尋不同,我們為C值定義了一個均勻分佈(從0到4),而不是固定的值集合。
引數n_iter=100
指定要嘗試的隨機組合數量。雖然我們的超引數空間理論上有無限多種組合(因為C是從連續分佈中抽樣),但隨機搜尋只會嘗試100個組合。這大減少了計算成本,同時仍能有效探索超引數空間。
random_state=1
設定隨機種子,確保結果可重現。與GridSearchCV一樣,RandomizedSearchCV也使用交叉驗證評估每個模型,並在搜尋完成後使用最佳超引數在整個資料集上重新訓練模型。
分散式抽樣的優勢
隨機搜尋的一個關鍵優勢是能夠使用分佈而不僅是離散值。例如,我們可以從均勻分佈中抽樣C值:
# 從均勻分佈中抽樣10個值
uniform(loc=0, scale=4).rvs(10)
這允許我們更靈活地探索超引數空間,尤其是當我們不確定引數的最佳範圍時。
隨機搜尋與網格搜尋的比較
隨機搜尋在以下情況特別有用:
高維超引數空間:當超引數量增加時,網格搜尋的計算成本呈指數增長,而隨機搜尋的效率優勢更加明顯。
計算資源有限:隨機搜尋允許我們精確控制要評估的模型數量,更好地管理計算資源。
部分超引數更重要:在許多實際問題中,只有少數超引數對模型效能有顯著影響。隨機搜尋能更有效地探索這些重要維度。
跨演算法模型選擇:尋找最佳學習演算法
有時候我們不僅需要調整超引數,還需要選擇最適合問題的學習演算法。scikit-learn提供了一種優雅的方式來同時搜尋不同的學習演算法及其各自的超引數。
使用Pipeline和GridSearchCV進行跨演算法搜尋
以下範例展示如何在邏輯迴歸和隨機森林之間選擇最佳模型:
# 載入必要的函式庫mport numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
# 設定隨機種子
np.random.seed(0)
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立管道
pipe = Pipeline([("classifier", RandomForestClassifier())])
# 建立包含多個學習演算法的搜尋空間
search_space = [
{"classifier": [LogisticRegression()],
"classifier__penalty": ['l1', 'l2'],
"classifier__C": np.logspace(0, 4, 10)},
{"classifier": [RandomForestClassifier()],
"classifier__n_estimators": [10, 100, 1000],
"classifier__max_features": [1, 2, 3]}
]
# 建立網格搜尋
gridsearch = GridSearchCV(pipe, search_space, cv=5, verbose=0)
# 訓練網格搜尋模型
best_model = gridsearch.fit(features, target)
這段程式碼展示瞭如何使用Pipeline和GridSearchCV結合,同時搜尋不同的學習演算法及其超引數。我們建立了一個包含兩個學習演算法的搜尋空間:邏輯迴歸和隨機森林。對於每個演算法,我們定義了其特定的超引數搜尋範圍。
關鍵點在於使用classifier__
字首來指定每個演算法的超引數。這種方式允許我們為不同的演算法定義不同的超引數集合。GridSearchCV會嘗試每個演算法及其所有超參陣列合,並選擇整體表現最佳的模型。
檢視跨演算法搜尋結果
搜尋完成後,我們可以檢視最佳模型使用的演算法及其超引數:
# 檢視最佳模型
best_algorithm = best_model.best_estimator_.get_params()["classifier"]
print(best_algorithm)
這種方法的強大之處在於它不僅能幫助我們選擇最佳的超引數,還能選擇最適合資料的學習演算法。這在實際應用中尤為重要,因為不同的問題可能需要不同的演算法類別。
模型選擇的進階考量
在實際應用模型選擇技術時,還有一些重要的考量因素:
評估指標的選擇
預設情況下,scikit-learn的模型選擇工具使用演算法的標準評分函式(如分類別的準確率)。但在許多實際問題中,我們可能需要最佳化他指標,如精確率、召回率或F1分數。可以透過scoring
引數指定評估指標:
# 使用F1分數作為評估指標
gridsearch = GridSearchCV(
model, hyperparameters, cv=5, scoring='f1_macro'
)
處理預處理步驟
實際機器學習流程通常包括資料預處理步驟。我們可以將這些步驟納入Pipeline中,與模型選擇結合:
# 建立包含預處理和分類別管道
pipe = Pipeline([
("scaler", StandardScaler()),
("classifier", RandomForestClassifier())
])
# 搜尋空間也可以包含預處理步驟的引數
search_space = [
{"scaler": [StandardScaler(), MinMaxScaler()],
"classifier": [LogisticRegression()],
"classifier__C": np.logspace(0, 4, 10)}
]
這種方法確保了預處理步驟也被納入交叉驗證過程,避免了資料洩漏問題。
計算效率與平行計算
模型選擇過程可能非常耗時,尤其是對於大型資料集和複雜模型。scikit-learn提供了幾種方式來提高
前處理與模型選擇整合:提升模型選擇的可靠性
在機器學習工作流程中,模型選擇是一個至關重要的環節,而這個環節常需要與資料前處理步驟緊密結合。許多開發者犯的一個常見錯誤是先對整個資料集進行前處理,然後才進行交叉驗證和模型選擇。這種做法會導致資訊洩漏問題,因為測試資料的特性被用於訓練過程。
資料前處理與模型選擇的正確整合方法
當我們處理特徵工程與模型選擇時,正確的流程應該是將前處理步驟納入交叉驗證的範圍內。scikit-learn 提供了優雅的解決方案:
# 載入必要的函式庫mport numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
# 設定隨機種子
np.random.seed(0)
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立前處理物件,包含標準化與PCA
preprocess = FeatureUnion([
("std", StandardScaler()),
("pca", PCA())
])
# 建立管道
pipe = Pipeline([
("preprocess", preprocess),
("classifier", LogisticRegression())
])
# 定義引數搜尋空間
search_space = [{
"preprocess__pca__n_components": [1, 2, 3],
"classifier__penalty": ["l1", "l2"],
"classifier__C": np.logspace(0, 4, 10)
}]
# 建立網格搜尋
clf = GridSearchCV(pipe, search_space, cv=5, verbose=0, n_jobs=-1)
# 訓練模型
best_model = clf.fit(features, target)
這段程式碼示範瞭如何正確整合前處理步驟與模型選擇。關鍵在於使用 FeatureUnion
和 Pipeline
元件:
FeatureUnion
允許我們組合多個前處理步驟,例如標準化和主成分析(PCA)Pipeline
將前處理和分類別連線成一個單一物件,確保在交叉驗證的每個折疊中,前處理步驟都只應用於訓練資料- 在
search_space
中,我們同時搜尋模型引數(classifier__C
,classifier__penalty
)和前處理引數(preprocess__pca__n_components
) - 使用
n_jobs=-1
啟用平行處理加速搜尋過程
這種做法解決了一個常被忽略的問題:確保前處理步驟僅根據訓練資料擬合,而不會"看到"測試資料。當我在處理金融預測模型時,曾經忽略了這一點,導致模型在實際應用中表現遠遜於交叉驗證結果。
前處理引數的最佳選擇
一個常被忽略的事實是,前處理步驟通常有自己的引數需要調整。例如,使用PCA時,我們需要決定要保留多少個主成分。這些引數的選擇會直接影響模型效能,因此應該被視為超引數的一部分進行調整。
使用上述方法,我們可以輕鬆檢視產生最佳模型的前處理引數:
# 檢視最佳模型的PCA元件數量
best_model.best_estimator_.get_params()['preprocess__pca__n_components']
# 輸出: 1
這表示在鳶尾花資料集上,使用1個主成分結合適當的分類別引數產生了最佳模型。這種發現可能會讓人意外,因為它意味著資料的大部分變異可以被單一主成分捕捉,這為我們提供了對資料結構的深入理解。
平行化加速模型選擇流程
在實際應用中,我們經常需要評估數千個候選模型,這可能需要數小時甚至數天的計算時間。透過利用現代電腦的多核心處理能力,我們可以大幅縮短模型選擇時間。
利用多核心加速網格搜尋
scikit-learn 的 GridSearchCV 提供了簡單的平行處理功能:
# 載入必要的函式庫mport numpy as np
from sklearn import linear_model, datasets
from sklearn.model_selection import GridSearchCV
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立邏輯迴歸模型
logistic = linear_model.LogisticRegression()
# 定義候選正則化引數
penalty = ["l1", "l2"]
C = np.logspace(0, 4, 1000)
# 建立超引數選項
hyperparameters = dict(C=C, penalty=penalty)
# 建立平行網格搜尋 (使用所有可用核心)
gridsearch = GridSearchCV(logistic, hyperparameters, cv=5, n_jobs=-1, verbose=1)
# 訓練模型
best_model = gridsearch.fit(features, target)
這段程式碼展示瞭如何使用平行處理加速模型選擇:
- 我們定義了2000個候選模型 (2種懲罰類別 × 1000種C值)
- 關鍵引數是
n_jobs=-1
,它告訴 scikit-learn 使用所有可用的CPU核心 verbose=1
引數讓我們能看到平行處理的進度- 在現代四核心電腦上,這可以將處理時間減少約75%
當我在處理包含數萬個樣本的客戶流失預測專案時,將 n_jobs
從預設的1改為-1,將網格搜尋時間從約5小時減少到僅約80分鐘。這種簡單的調整可以極大地提高實驗迭代速度。
平行化的注意事項
雖然平行化處理可以顯著加速模型選擇,但也有一些注意事項:
- 記憶體使用量會隨著平行任務數量增加
- 並不是所有演算法都能有效平行化
- 在某些情況下,過度平行可能導致系統效能瓶頸
在實踐中,我發現對於中小型資料集,設定 n_jobs=-1
通常是最佳選擇;而對於特大型資料集,可能需要限制平行任務數量以避免記憶體耗盡。
演算法專用方法:更高效的模型選擇策略
除了通用的網格搜尋和隨機搜尋方法外,某些學習演算法擁有專門設計的交叉驗證方法,可以更高效地找到最佳超引數。
使用演算法特定的交叉驗證方法
scikit-learn 為多種常用演算法提供了內建的交叉驗證版本:
# 載入必要的函式庫rom sklearn import linear_model, datasets
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立交叉驗證邏輯迴歸
logit = linear_model.LogisticRegressionCV(Cs=100)
# 訓練模型
logit.fit(features, target)
這段程式碼展示瞭如何使用演算法特定的交叉驗證方法:
LogisticRegressionCV
是邏輯迴歸的交叉驗證版本,它能夠自動找到最佳的C值- 引數
Cs=100
指定生成100個候選C值進行測試 - 這些演算法特定方法通常比通用網格搜尋更高效,因為它們利用了演算法的特性進行最佳化4. 其他類別的方法包括
RidgeCV
、LassoCV
和ElasticNetCV
這些專用方法的主要優勢在於效率。例如,LogisticRegressionCV
使用特殊技術來加速超引數搜尋,而不是簡單地訓練100個不同的模型。在大規模資料集上,這種方法可以節省大量計算資源。
專用方法的侷限性
雖然演算法特定的交叉驗證方法效率更高,但它們也有一些限制:
- 僅適用於特定演算法,不是通用解決方案
- 通常只能調整部分超引數,而非所有引數
- 自定義的評估指標選項可能有限
在我的實踐中,我發現這些方法在初步探索階段特別有用,可以快速找到合理的引數範圍,然後再使用更全面的網格搜尋進行精細調整。
模型選擇流程的綜合策略
經過多年的機器學習實踐,我逐漸形成了一套綜合性的模型選擇策略:
- 初步探索階段:使用演算法特定的交叉驗證方法(如
LogisticRegressionCV
)快速確定合理的引數範圍 - 精細調整階段:使用
Pipeline
和FeatureUnion
整合前處理步驟,並利用GridSearchCV
進行更全面的引數搜尋 - *計算效率最佳化:設定
n_jobs=-1
啟用平行處理,大幅減少訓練時間 - 模型評估階段:對最終選定的模型使用獨立測試集進行評估,確保結果可靠性
這種分階段的方法既保證了模型選擇的全面性,又避免了不必要的計算資源浪費。
管道(Pipeline)技術的進階使用
除了基本的前處理整合外,scikit-learn 的 Pipeline 還有更多進階用法:
動態前處理選擇
我們可以將前處理方法的選擇也納入超引數搜尋範圍:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
# 建立管道
pipe = Pipeline([
("scaler", StandardScaler()), # 初始值,將在搜尋中被替換
("classifier", SVC())
])
# 定義引數搜尋空間,包括前處理方法選擇
search_space = [{
"scaler": [StandardScaler(), MinMaxScaler()],
"classifier__C": [0.1, 1, 10, 100],
"classifier__kernel": ["linear", "rbf"]
}]
# 建立網格搜尋
search = GridSearchCV(pipe, search_space, cv=5, n_jobs=-1)
這種方法讓我們能夠同時比較不同的前處理方法與模型參陣列合,找出最佳解決方案。
條件引數搜尋
對於某些參陣列合,有些引數可能只在特定條件下才有意義。例如,SVM 的 gamma
引數只在使用 RBF 核函式時才相關:
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
# 定義條件引數搜尋空間
param_grid = [
# RBF核引數
{"kernel": ["rbf"], "C": [1, 10, 100], "gamma": [0.1, 0.01, 0.001]},
# 線性核引數
{"kernel": ["linear"], "C": [1, 10, 100]}
]
# 建立網格搜尋
search = GridSearchCV(SVC(), param_grid, cv=5)
這種方法避免了測試無意義的參陣列合,提高了搜尋效率。
模型選擇過程中的常見陷阱
在實施模型選擇策略時,需要注意幾個常見陷阱:
資訊洩漏
前文已經討論了前處理步驟中的資訊洩漏問題。另一個常見的資訊洩漏來源是在整個資料集上進行特徵選擇,然後再進行交叉驗證。正確做法是將特徵選擇納入交叉驗證管道中。
過度調參
過度調參是另一個常見問題。測試太多參陣列合可能導致偶然發現表現良好的組合,但這些組合在新資料上表現不佳。解決方法是:
- 使用巢狀交叉驗
模型選擇的進階評估策略
在機器學習專案中,選擇最佳模型並不只是訓練後檢視準確率那麼簡單。一個常見的錯誤是在選擇最佳超引數後,使用相同的資料來評估模型表現,這會導致樂觀偏差。本文將探討如何正確評估模型表現,並介紹線性迴歸的基本實作與進階技巧。
LogisticRegressionCV 的限制
在模型選擇工具中,scikit-learn 提供了一些內建交叉驗證的類別,如 LogisticRegressionCV
。雖然這類別具使用方便,但它們有一個重要限制:只能搜尋單一超引數的範圍值。
以 LogisticRegressionCV
為例,它只能搜尋正則化引數 C 的不同值,無法同時考慮其他超引數(如正則化懲罰範數)。這個限制普遍存在於 scikit-learn 的模型特定交叉驗證類別中,使得它們在複雜的超引數調校任務中不夠靈活。
模型選擇後的效能評估:巢狀交叉驗證
避免評估偏差的關鍵技術
當我們透過網格搜尋或隨機搜尋找到最佳模型後,如何公正評估其效能?這個問題比想像中更重要與常被忽視。
讓我展示如何使用巢狀交叉驗證來解決這個問題:
# 載入必要的函式庫mport numpy as np
from sklearn import linear_model, datasets
from sklearn.model_selection import GridSearchCV, cross_val_score
# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立邏輯迴歸模型
logistic = linear_model.LogisticRegression()
# 建立C引數的候選值範圍(20個值)
C = np.logspace(0, 4, 20)
# 設定超引數選項
hyperparameters = dict(C=C)
# 建立網格搜尋物件
gridsearch = GridSearchCV(logistic, hyperparameters, cv=5, n_jobs=-1, verbose=0)
# 進行巢狀交叉驗證並輸出平均分數
mean_score = cross_val_score(gridsearch, features, target).mean()
print(f"平均分數: {mean_score}")
這段程式碼展示了巢狀交叉驗證的實作方式。首先建立了一個邏輯迴歸模型,定義了超引數 C 的 20 個可能值(從 10^0 到 10^4 的對數間隔),然後設定了網格搜尋。
最關鍵的部分是最後一行:我們對網格搜尋物件本身進行了交叉驗證。這建立了「巢狀」的交叉驗證結構—內層交叉驗證(GridSearchCV)用於找出最佳模型,外層交叉驗證(cross_val_score)則提供無偏的效能評估。
巢狀交叉驗證的深層理解
巢狀交叉驗證可能是機器學習中較難理解的概念之一。讓我們分解這個過程:
標準k折交叉驗證:在 k 折交叉驗證中,我們將資料分為 k 個部分,每次用 k-1 部分訓練模型,然後在剩下的一部分上評估模型。重複 k 次,每次使用不同的測試折。
模型選擇中的交叉驗證:在 GridSearchCV 或 RandomizedSearchCV 中,我們使用交叉驗證來評估哪種超參陣列合產生最佳模型。
評估問題:關鍵問題是,如果我們用資料選擇了最佳超引數,就不能再用相同的資料來評估模型效能,因為這會導致樂觀偏差。
巢狀交叉驗證解決方案:巢狀交叉驗證包含兩層交叉驗證—內層用於模型選擇,外層用於無偏評估。
為了更清楚理解,我進行了一個簡單實驗。首先,設定 verbose=1 來觀察過程:
# 設定詳細輸出
gridsearch = GridSearchCV(logistic, hyperparameters, cv=5, verbose=1)
# 執行內層交叉驗證找出最佳模型
best_model = gridsearch.fit(features, target)
# 輸出:Fitting 5 folds for each of 20 candidates, totalling 100 fits
# 進行巢狀交叉驗證(預設3折)
scores = cross_val_score(gridsearch, features, target)
# 輸出:三次「Fitting 5 folds for each of 20 candidates, totalling 100 fits」
從輸出可以看到,內層交叉驗證訓練了 20 個候選模型,每個進行 5 次訓練,總共 100 個模型。然後,外層交叉驗證進行 3 次評估,每次都重新執行內層交叉驗證,總計訓練了 300 個模型。
這種方法雖然計算成本高,但提供了對模型真實效能的無偏估計,避免了過度樂觀的評估結果。
線性迴歸基礎:擬合一條線
線性迴歸是最簡單但仍然強大的監督學習演算法之一。即使有時因為過於基本而不被視為「機器學習」,它仍然是處理定量目標變數(如房價、年齡)的有效方法。
基本線性迴歸實作
以下是使用 scikit-learn 實作的簡單線性迴歸:
# 載入必要的函式庫rom sklearn.linear_model import LinearRegression
from sklearn.datasets import load_boston
# 載入資料(只使用兩個特徵以便解釋)
boston = load_boston()
features = boston.data[:,0:2]
target = boston.target
# 建立線性迴歸模型
regression = LinearRegression()
# 訓練模型
model = regression.fit(features, target)
這段程式碼建立了一個基本的線性迴歸模型。為了簡化說明,我們只使用了波士頓房價資料集的前兩個特徵。線性迴歸假設特徵與目標向量之間的關係大致是線性的,模型可以表示為:
y = β₀ + β₁x₁ + β₂x₂ + ε
其中 β₀ 是截距,β₁ 和 β₂ 是係數,ε 是誤差項。
訓練完模型後,我們可以檢視這些引數:
# 檢視截距
print(model.intercept_) # 輸出: 22.46681692105723
# 檢視特徵係數
print(model.coef_) # 輸出: [-0.34977589, 0.11642402]
線性迴歸的直覺解釋
線性迴歸的主要優勢在於其可解釋性。模型係數直接表示特徵對目標變數的影響程度。
在波士頓房價資料集中,第一個特徵是每居民犯罪率。模型的係數約為 -0.35,由於目標變數是以千美元計的房價,這意味著:
# 第一個係數乘以1000
print(model.coef_[0]*1000) # 輸出: -349.77588707748947
這表示每增加一個單位的人均犯罪率,房價將減少約350美元!
這種直接解釋是線性迴歸在實務應用中的重要優勢,特別是在需要理解特徵影響的場景中。
處理互動效應:特徵間的相依關係
在實際應用中,一個特徵對目標變數的影響常依賴於另一個特徵的值。這種情況稱為「互動效應」。
建立互動項
scikit-learn 提供了 PolynomialFeatures
來處理特徵間的互動效應:
# 載入必要的函式庫rom sklearn.linear_model import LinearRegression
from sklearn.datasets import load_boston
from sklearn.preprocessing import PolynomialFeatures
# 載入資料
boston = load_boston()
features = boston.data[:,0:2]
target = boston.target
# 建立互動項
interaction = PolynomialFeatures(
degree=3, include_bias=False, interaction_only=True)
features_interaction = interaction.fit_transform(features)
# 建立線性迴歸模型
regression = LinearRegression()
# 訓練模型
model = regression.fit(features_interaction, target)
這段程式碼使用 PolynomialFeatures
來建立特徵間的互動項。引數設定為:
degree=3
:允許最多三個特徵間的互動include_bias=False
:不增加偏置列(都是1的列)interaction_only=True
:只包含互動項,不包含單個特徵的高次方項
互動效應的一個經典例子是咖啡甜度的問題:想像我們有兩個二元特徵—是否加糖(sugar)和是否攪拌(stirred)。僅加糖而不攪拌(sugar=1, stirred=0)不會使咖啡變甜(糖沉在底部),只攪拌不加糖(sugar=0, stirred=1)同樣不會增加甜度。只有同時加糖和攪拌(sugar=1, stirred=1)才會使咖啡變甜。
在這種情況下,糖和攪拌對甜度的影響是相互依賴的。我們需要建立一個互動項來捕捉這種關係。
互動效應的實際應用
在實際模型中,互動效應可以大幅提升預測能力。例如,在房價預測中,房屋面積與位置的互動可能比單獨考慮這兩個因素更重要—相同面積的房屋在不同區域的價格差異可能很大。
透過 PolynomialFeatures
處理後,我們的特徵矩陣不僅包含原始特徵,還包含特徵間的互動項,使模型能夠捕捉到這種複雜的關係。
在建模過程中,識別和處理互動效應是提升模型效能的重要策略,特別是當我們有理由相信特徵間存在相互影響時。
線性迴歸的實用價值
雖然線性迴歸是最基本的預測模型之一,但它在實際應用中仍然具有顯著價值:
高度可解釋性:線性迴歸的係數直接反映特徵對目標的影響,便於向非技術人員解釋結果。
計算效率:與複雜模型相比,線性迴歸訓練和預測速度快,適合大規模應用。
作為基線模型:在嘗試更複雜模型前,線性迴歸常作為基準效能參考。
特徵重要性評估:透過係數大小,可以初步評估特徵的重要性。
健壯性:在資料有限的情況下,線性迴歸往往比複雜模型更不易過擬合。
當我處理預測問題時,通常會先嘗試線性迴歸,再根據需要考慮更複雜的模型。這種「簡單優先」的方法往往能節省時間並提供有價值的洞見。
模型選擇和評估是機器學習流程中至關重要的環節。巢狀交叉驗證提供了一種無偏評估模型效能的方法,雖然計算成本較高,但能避免過度樂觀的評估結果。線性迴歸雖簡單,但在實際應用中具有顯著價值,特別是在處理特徵間存在互動效應的情況時。
在實踐中,我發現平衡模型複雜度和解釋性是關鍵。有時候一個可解釋的線性模型比黑盒複雜模型更有價值,尤其是在需要向利益相關者解釋結果的業務環境中。最終,選擇合適的模型和評估策略應該根據具體問題和應用場景,而不僅是追求最高的準確率。
超越線性:處理特徵間互動作用
在實際的資料分析工作中,我常發現變數之間的關係並非單純的線性關係。特徵之間往往存在互動作用,這意味著一個特徵的效果會受到另一個特徵值的影響。以製作咖啡為例,糖的甜度感受會因是否攪拌而有所不同 - 攪拌均勻的咖啡中,糖的甜味更容易被感知。
建立互動項模型
當特徵間存在互動作用時,我們可以線上性迴歸模型中加入一個新的特徵,即兩個互動特徵值的乘積:
y = β₀ + β₁x₁ + β₂x₂ + β₃x₁x₂ + ε
這裡的 x₁
和 x₂
分別代表兩個特徵的值(例如糖的量和是否攪拌),而 x₁x₂
代表它們之間的互動作用。
手動建立互動項
以下程式碼示如何手動建立互動項:
# 匯入必要的函式庫
import numpy as np
# 假設 features 是我們的特徵矩陣
# 檢視第一個觀測值的特徵值
features[0]
# 輸出: array([ 6.32000000e-03, 1.80000000e+01])
# 對每個觀測值,將第一個和第二個特徵值相乘
interaction_term = np.multiply(features[:, 0], features[:, 1])
# 檢視第一個觀測值的互動項
interaction_term[0]
# 輸出: 0.11376
這段程式碼先展示了原始特徵矩陣中第一個觀測值的兩個特徵值:約0.00632和18.0。然後使用NumPy的multiply()
函式,將每個觀測值的第一個特徵和第二個特徵相乘,建立出互動項。對於第一個觀測值,互動項的值為0.00632 × 18.0 = 0.11376。這種方法直觀地展示瞭如何手動建立特徵間的互動作用。
使用PolynomialFeatures自動建立互動項
當我們需要考慮多個特徵之間的所有可能互動作用時,手動建立互動項會變得繁瑣。scikit-learn的PolynomialFeatures
提供了一個便捷的解決方案:
# 使用scikit-learn自動建立互動項
from sklearn.preprocessing import PolynomialFeatures
# 只建立互動項,不包含偏差項,不建立多項式特徵
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
features_interaction = poly.fit_transform(features)
# 檢視第一個觀測值的原特徵和互動項
features_interaction[0]
# 輸出: array([ 6.32000000e-03, 1.80000000e+01, 1.13760000e-01])
這段程式碼用PolynomialFeatures
自動建立了所有可能的互動項。引數interaction_only=True
指定只生成互動項而不生成多項式特徵,include_bias=False
表示不增加偏差項(全為1的列),degree=2
設定最高考慮兩個特徵的互動。
輸出結果顯示,處理後的第一個觀測值包含原始的兩個特徵值(0.00632和18.0)以及它們的互動項(0.11376)。這與我們手動計算的結果一致。
PolynomialFeatures
的強大之處在於,當面對多個特徵時,它能自動生成所有可能的互動組合,省去了手動計算的麻煩。這對於探索性資料分析和特徵工程非常有用,尤其是當我們不確定哪些特徵之間可能存在互動作用時。
建模非線性關係:多項式迴歸
在許多實際問題中,變數之間的關係往往是非線性的。例如,學習時間與考試成績的關係:從0小時到1小時的學習可能帶來顯著提升,但從99小時到100小時的額外學習可能只有微小改善。這種遞減效應無法用簡單的線性關係捕捉。
多項式迴歸實作
多項式迴歸是線性迴歸的擴充套件,透過增加多項式特徵來模擬非線性關係:
# 匯入必要的函式庫
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_boston
from sklearn.preprocessing import PolynomialFeatures
# 載入資料,僅使用一個特徵
boston = load_boston()
features = boston.data[:,0:1]
target = boston.target
# 建立多項式特徵:x^2和x^3
polynomial = PolynomialFeatures(degree=3, include_bias=False)
features_polynomial = polynomial.fit_transform(features)
# 建立並擬合線性迴歸模型
regression = LinearRegression()
model = regression.fit(features_polynomial, target)
這段程式碼用波士頓房價資料集,但只選取了第一個特徵進行演示。PolynomialFeatures
被設定為生成最高3次方的多項式特徵(原始特徵x、x²和x³)。引數include_bias=False
表示不增加常數項(全為1的列)。
然後,我們使用普通的LinearRegression
模型擬合這些多項式特徵。這種方法的妙處在於,我們仍然使用線性迴歸模型,只是輸入的特徵已經轉換為多項式形式。
多項式特徵的生成過程
為了理解多項式特徵的生成,讓我們看具體的計算過程:
# 檢視第一個觀測值
features[0]
# 輸出: array([ 0.00632])
# 計算第一個觀測值的二次方
features[0]**2
# 輸出: array([ 3.99424000e-05])
# 計算第一個觀測值的三次方
features[0]**3
# 輸出: array([ 2.52435968e-07])
# 檢視生成的多項式特徵
features_polynomial[0]
# 輸出: array([ 6.32000000e-03, 3.99424000e-05, 2.52435968e-07])
這段程式碼示了多項式特徵的具體計算過程。對於第一個觀測值0.00632:
- 原始值:0.00632
- 二次方:0.00632² ≈ 0.0000399424
- 三次方:0.00632³ ≈ 0.000000252436
PolynomialFeatures
生成的結果正是這三個值的組合。這樣,我們的線性迴歸模型實際上變成了:
y = β₀ + β₁x + β₂x² + β₃x³ + ε
這已經是一個可以捕捉非線性關係的模型,雖然我們仍然使用線性迴歸的框架。
多項式迴歸的靈活性在於可以透過調整多項式的次數來控制模型的複雜度。更高次數的多項式能捕捉更複雜的非線性關係,但也更容易過擬合。在實踐中,我通常從低次多項式開始,根據交叉驗證結果決定是否增加多項式的次數。
使用正則化降低模型方差
在建立複雜模型(如高次多項式迴歸)時,過擬合是一個常見問題。過擬合的模型在訓練資料上表現優異,但在新資料上泛化能力差。正則化是一種減少模型方差、提高泛化能力的重要技術。
正則化線性迴歸的實作
以下範例展示如何使用脊迴歸(Ridge Regression)實作正則化:
# 匯入必要的函式庫
from sklearn.linear_model import Ridge
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler
# 載入資料
boston = load_boston()
features = boston.data
target = boston.target
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立帶有alpha值的脊迴歸
regression = Ridge(alpha=0.5)
# 擬合模型
model = regression.fit(features_standardized, target)
這段程式碼先使用StandardScaler
對特徵進行標準化,這是應用正則化技術前的重要步驟,因為正則化對特徵的尺度敏感。
然後,我們使用Ridge
建立一個脊迴歸模型,設定alpha=0.5
作為正則化強度引數。alpha值越大,正則化效果越強,模型越簡單(係數越小);alpha值越小,模型越接近普通線性迴歸。
需要注意的是,特徵標準化對於正則化模型尤為重要。如果不進行標準化,那些尺度較大的特徵會受到更少的懲罰,這違背了正則化的初衷。
正則化的原理與類別
標準線性迴歸試圖最小化殘差平方和(RSS):
RSS = Σ(yᵢ - ŷᵢ)²
而正則化迴歸則在RSS基礎上增加了一個懲罰項,用於控制模型複雜度:
脊迴歸(Ridge Regression):增加係數平方和的懲罰
目標函式 = RSS + α·Σβⱼ²
套索迴歸(Lasso Regression):增加係數絕對值和的懲罰
目標函式 = (1/2n)·RSS + α·Σ|βⱼ|
這兩種正則化技術的主要區別在於懲罰項的形式。脊迴歸傾向於縮小所有係數但不會使其精確為零,而套索迴歸則傾向於產生稀疏解,即一些係數會變為精確零。
在實踐中,我發現脊迴歸通常能提供稍好的預測效能,而套索迴歸則產生更易解釋的模型(因為它能自動進行特徵選擇)。如果希望兼顧兩者優勢,可以考慮使用彈性網(Elastic Net),它結合了脊迴歸和套索迴歸的懲罰項。
正則化技術的一個關鍵挑戰是選擇適當的alpha值。通常,我會使用交叉驗證來尋找最佳的alpha值,即在不同alpha值下評估模型效能,選擇泛化誤差最小的那個。
正則化技術的實際應用
正則化不僅是一種防止過擬合的技術,在許多實際場景中也有其獨特的價值。從我的經驗來看,以下幾種情況特別適合使用正則化:
處理高維資料
當特徵數量接近或超過觀測數量時,普通線性迴歸容易過擬合,甚至無法求解(矩陣不可逆)。在這種情況下,正則化提供了一個穩定的解決方案。
例如,在基因表達分析中,我們可能有成千上萬個基因特徵,但只有少量樣本。使用正則化技術如脊迴歸,可以有效處理這種「p > n」的情況。
多重共線性問題
當特徵間存在高度相關性時,普通線性迴歸的係數估計會變得不穩定,標準誤差增大。正則化可以穩定這些估計。
例如,在房價預測中,房屋面積、臥室數量和浴室數量往往高度相關。正則化可以平衡這些相關特徵的影響,防止某一特徵的係數過大或符號不合理。
模型選擇與特徵選擇
套索迴歸(Lasso)的一個重要特性是能夠將不重要特徵的係數壓縮為零,從而自動完成特徵選擇。這在處理有大量潛在預測變數但只有少數真正相關的情況下特別有用。
例如,在客戶流失預測中,我們可能有數百個客戶特徵,但真正影響流失的可能只有少數幾個。套索
正則化與特徵選擇:開發精簡有效的預測模型
在機器學習的世界裡,我們常面臨一個重要的平衡課題:模型需要足夠複雜以捕捉資料中的模式,但又不能過於複雜導致過度擬合。這種「複雜度與泛化能力」的權衡,正是我多年來在建構預測模型時最常思考的問題。
正則化的核心思想:控制模型複雜度
無論我們選擇嵴迴歸(Ridge Regression)還是套索迴歸(Lasso Regression),兩者都透過在損失函式中加入係數值的懲罰項來控制模型的複雜度。其中的超引數α(在scikit-learn中透過alpha引數設定)決定了我們對係數的懲罰程度,α值越高,模型就越簡單。
讓我們來看如何使用嵴迴歸並找到最佳的α值:
# 載入必要的函式庫
from sklearn.linear_model import RidgeCV
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_boston
# 載入資料
boston = load_boston()
features = boston.data
target = boston.target
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立具有三個alpha值的嵴迴歸模型
regr_cv = RidgeCV(alphas=[0.1, 1.0, 10.0])
# 訓練線性迴歸模型
model_cv = regr_cv.fit(features_standardized, target)
# 檢視係數
print(model_cv.coef_)
# 檢視最佳的alpha值
print(f"最佳的alpha值:{model_cv.alpha_}")
上面的程式碼示瞭如何使用RidgeCV自動選擇最佳的α值。我們首先載入波士頓房價資料集,然後對特徵進行標準化處理(這一步在正則化模型中非常重要,因為係數的大小會受到特徵尺度的影響)。接著我們建立一個RidgeCV模型,並提供三個候選的α值:0.1、1.0和10.0。模型會自動選擇使驗證誤差最小的α值,在這個案例中是1.0。
值得注意的是,在正則化模型中,標準化特徵是必不可少的步驟。這是因為正則化會懲罰所有係數的總和,如果特徵的尺度不一致,那麼尺度較大的特徵對應的係數自然會較小,從而受到的懲罰也較小,這會導致模型偏向於使用尺度較大的特徵。
套索迴歸:實作特徵選擇的利器
在處理高維度資料時,我經常使用套索迴歸來自動選擇最重要的特徵。套索迴歸的獨特之處在於它可以將某些係數完全壓縮到零,相當於將對應的特徵從模型中剔除。
以下是套索迴歸的實作範例:
# 載入必要的函式庫
from sklearn.linear_model import Lasso
# 建立套索迴歸模型,alpha值設為0.5
regression = Lasso(alpha=0.5)
# 訓練模型
model = regression.fit(features_standardized, target)
# 檢視係數
print(model.coef_)
在這個例子中,我們使用α=0.5建立了一個套索迴歸模型。觀察輸出的係數,會發現部分係數已經變成零,這意味著套索迴歸自動幫我們排除了一些不重要的特徵。
如果我增加α值到更高,例如10:
# 建立較高alpha值的套索迴歸
regression_a10 = Lasso(alpha=10)
model_a10 = regression_a10.fit(features_standardized, target)
print(model_a10.coef_)
這時我們會發現所有係數都變為零,意味著模型變得極度簡單,甚至沒有使用任何特徵。
這種特性使得套索迴歸成為特徵選擇的強大工具。假設我們有100個特徵,透過調整α值,我們可以讓模型只使用其中最重要的10個特徵,既降低了模型的複雜度,又提高了模型的可解釋性。
正則化選擇:何時選擇嵴迴歸或套索迴歸?
在實際應用中,何時應該使用嵴迴歸,何時應該使用套索迴歸?以下是我的經驗法則:
當所有特徵都可能有貢獻時:嵴迴歸適合於你認為大多數特徵都對預測有所貢獻的情況,它會保留所有特徵但減小其影響。
當需要自動特徵選擇時:套索迴歸適合於你希望模型自動選擇最重要的特徵子集的情況,特別是當你面對高維度資料時。
當特徵間存在高度相關性時:嵴迴歸通常比套索迴歸更穩定,特別是當特徵間存在高度相關性時。
當模型可解釋性至關重要時:套索迴歸生成的模型通常更容易解釋,因為它只使用一部分特徵。
決策樹:從根節點到葉節點的預測之路
轉向另一類別大的模型—決策樹。與線性模型不同,決策樹是一種非引數化、監督式學習方法,可用於分類別迴歸任務。決策樹的基本結構是一系列決策規則(例如「如果性別是男性…」)的串聯。
決策樹的基本原理與應用
決策樹之所以受歡迎,很大程度上是因為它的可解釋性。我們可以將完整的決策過程視覺化,使模型變得直觀易懂。在決策樹中,每個決策規則發生在決策節點,規則建立的分支導向新的節點。沒有決策規則的分支末端稱為葉節點。
從這個基本的樹狀結構,衍生出了各種擴充套件方法,如隨機森林和堆積積式模型。接下來,我們將探討如何訓練、處理、調整、視覺化和評估各種樹狀模型。
訓練決策樹分類別
使用scikit-learn的DecisionTreeClassifier可以輕鬆訓練一個決策樹分類別:
# 載入函式庫
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立決策樹分類別物件
decisiontree = DecisionTreeClassifier(random_state=0)
# 訓練模型
model = decisiontree.fit(features, target)
# 進行預測
observation = [[5, 4, 3, 2]]
print(model.predict(observation))
# 檢視預測的類別機率
print(model.predict_proba(observation))
這段程式碼示範瞭如何使用決策樹進行分類別我們使用鳶尾花資料集,建立了一個決策樹分類別,並使用預設的Gini不純度作為分割標準。訓練完成後,我們可以使用model.predict()方法對新觀測值進行預測,也可以使用model.predict_proba()方法檢視預測的類別機率。
決策樹分類別嘗試找到能夠最大程度減少節點不純度的決策規則。預設情況下,DecisionTreeClassifier使用Gini不純度:
G(t) = 1 - Σ(p_i²)
其中G(t)是節點t的Gini不純度,p_i是節點t中類別c的觀測值比例。尋找能夠增加純度的決策規則的過程會遞迴進行,直到所有葉節點都是純的(即只包含一個類別)或達到某個任意的切斷點。
如果我們想使用不同的不純度測量方法,可以透過criterion引數來設定:
# 使用熵作為標準建立決策樹分類別
decisiontree_entropy = DecisionTreeClassifier(criterion='entropy', random_state=0)
# 訓練模型
model_entropy = decisiontree_entropy.fit(features, target)
訓練決策樹迴歸器
決策樹不僅可以用於分類別務,也可以用於迴歸任務。使用scikit-learn的DecisionTreeRegressor:
# 載入函式庫
from sklearn.tree import DecisionTreeRegressor
from sklearn import datasets
# 載入資料,僅使用前兩個特徵
boston = datasets.load_boston()
features = boston.data[:,0:2]
target = boston.target
# 建立決策樹迴歸器物件
decisiontree = DecisionTreeRegressor(random_state=0)
# 訓練模型
model = decisiontree.fit(features, target)
# 進行預測
observation = [[0.02, 16]]
print(model.predict(observation))
決策樹迴歸的工作原理與決策樹分類別,但不同的是,它不是減少Gini不純度或熵,而是預設測量潛在分割如何減少均方誤差(MSE):
MSE = (1/n) * Σ(y_i - ŷ_i)²
其中y_i是目標的真實值,ŷ_i是預測值。在scikit-learn中,可以使用DecisionTreeRegressor進行決策樹迴歸。一旦我們訓練了決策樹,就可以用它來預測觀測值的目標值。
與DecisionTreeClassifier一樣,我們可以使用criterion引數來選擇所需的分割品質測量方法。例如,我們可以構建一個減少平均絕對誤差(MAE)的樹:
# 使用MAE作為標準建立決策樹迴歸器
decisiontree_mae = DecisionTreeRegressor(criterion="mae", random_state=0)
# 訓練模型
model_mae = decisiontree_mae.fit(features, target)
決策樹的視覺化:讓模型更直觀
決策樹的一大優勢是可以視覺化,這大提升了模型的可解釋性。使用scikit-learn的export_graphviz函式,我們可以將決策樹模型匯出為Graphviz格式:
# 載入函式庫
from sklearn.tree import export_graphviz
import graphviz
# 建立決策樹分類別
decisiontree = DecisionTreeClassifier(random_state=0)
model = decisiontree.fit(features, target)
# 匯出決策樹為DOT格式
dot_data = export_graphviz(
model,
out_file=None,
feature_names=iris.feature_names,
class_names=iris.target_names,
filled=True,
rounded=True,
special_characters=True
)
# 將DOT資料轉換為圖形
graph = graphviz.Source(dot_data)
透過視覺化,我們可以清楚地看到決策樹的結構,包括每個節點的決策規則、不純度以及分類別果。這使得我們能夠更好地理解模型的決策邏輯,並有助於解釋模型為何做出特定預測。
防止過度擬合:決策樹的剪枝技術
決策樹的一個主要挑戰是容易過度擬合,特別是當樹深度增加時。為瞭解決這個問題,我們可以採用剪枝技術來限制樹的複雜性。
預剪枝:在樹生長過程中進行控制
預剪枝是在樹生長過程中設定限制條件,防止樹過度生長。在scikit-learn中,我們可以透過設定各種引數來實作預剪枝:
# 使用預剪枝技術建立決策樹
controlled_tree = DecisionTreeClassifier(
max_depth=3, # 最大深度
min_samples_split=10, # 分割所需的最小樣本數
min_samples_leaf=5, # 葉節點所需的最小樣本數
random_state=0
)
# 訓練模型
controlled_model = controlled_tree.fit(features, target)
這段程式碼展示瞭如何透過設定max_depth、min_samples_split和min_samples_leaf引數來控制決策樹的生長。max_depth
決策樹模型的視覺化:讓複雜決策過程一目瞭然
在機器學習領域中,決策樹是最直觀與易於理解的模型之一。它的最大優勢在於我們能夠將整個訓練過程視覺化,幫助我們理解模型如何做出決策。這種視覺化能力使決策樹成為機器學習中最具解釋性的模型之一。
使用DOT格式視覺化決策樹
我們可以將決策樹模型匯出為DOT格式(一種圖形描述語言),然後將其視覺化:
# 載入必要的函式庫
import pydotplus
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
from IPython.display import Image
from sklearn import tree
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 建立決策樹分類別物件
decisiontree = DecisionTreeClassifier(random_state=0)
# 訓練模型
model = decisiontree.fit(features, target)
# 建立DOT資料
dot_data = tree.export_graphviz(decisiontree,
out_file=None,
feature_names=iris.feature_names,
class_names=iris.target_names)
# 繪製圖形
graph = pydotplus.graph_from_dot_data(dot_data)
# 顯示圖形
Image(graph.create_png())
上述程式碼首先載入必要的函式庫括用於決策樹分類別DecisionTreeClassifier
和用於視覺化的pydotplus
。接著,我載入了鳶尾花(Iris)資料集,這是機器學習中的經典資料集。
訓練好模型後,使用tree.export_graphviz()
函式將決策樹模型匯出為DOT格式,這種格式非常適合表示圖形結構。在匯出過程中,我指定了特徵名稱和類別名稱,讓視覺化結果更加直觀。最後,使用pydotplus
將DOT資料轉換為可檢視形,並顯示出來。
解讀決策樹視覺化結果
當我們分析視覺化後的決策樹時,可以觀察到許多有價值的訊息:
在根節點,決策規則是:如果花瓣寬度小於或等於0.8,則走向左分支;否則走向右分支。
我們可以看到基尼不純度指數(0.667)、觀測數量(150)、每個類別的觀測數量([50,50,50]),以及如果我們在該節點停止,觀測將被預測為哪個類別(setosa)。
從視覺化中我們發現,僅透過一個決策規則(petal width (cm) <= 0.8),模型就能完美識別所有的setosa類別觀測值。
更進一步,再加上一個使用相同特徵的決策規則(petal width (cm) <= 1.75),決策樹就能正確分類別50個觀測值中的144個。這表明花瓣寬度是一個非常重要的特徵!
匯出視覺化結果
如果我們想在其他應用程式或報告中使用決策樹,可以輕鬆地將視覺化結果匯出為PDF或PNG圖片:
CODE_BLOCK_79
這部分程式碼展示瞭如何將視覺化的決策樹儲存為PDF和PNG格式的檔案。這對於報告撰寫或簡報製作非常有用。使用__INLINE_CODE_106__和__INLINE_CODE_107__方法可以輕鬆實作這一點,並且函式會回傳__INLINE_CODE_108__表示操作成功。
值得注意的是,macOS使用者可能需要安裝GraphViz的執行檔才能執行上述程式碼。這可以使用Homebrew完成:INLINE_CODE_109。
雖然我們的範例視覺化的是決策樹分類別,但同樣的方法也可以用於視覺化決策樹迴歸器。視覺化決策樹的好處在於它幫助我們理解模型的決策過程,這對於模型解釋和最佳化非常有價值。
訓練隨機森林分類別:提升決策樹的預測能力
決策樹的一個常見問題是它們往往會過度擬合訓練資料(即過擬合問題)。這促使了一種被稱為隨機森林的整合學習方法的廣泛使用。
使用Scikit-learn訓練隨機森林分類別
以下是使用scikit-learn的RandomForestClassifier訓練隨機森林分型別的方法:
CODE_BLOCK_80
在這段程式碼中,我首先從__INLINE_CODE_110__模組中載入了__INLINE_CODE_111__。隨機森林是一種整合方法,它透過建立多個決策樹並結合它們的預測結果來提高準確性和控制過擬合。
建立分類別物件時,我設定了兩個引數:
- __INLINE_CODE_112__確保結果的可重現性
- __INLINE_CODE_44__利用所有可用的CPU核心來加速訓練過程
然後使用__INLINE_CODE_114__方法訓練模型,就像使用單一決策樹一樣簡單。
隨機森林的工作原理與優勢
在隨機森林中,多個決策樹被訓練,但每棵樹只接收觀測值的自助抽樣(bootstrapped sample)(即帶替換的隨機抽樣,樣本數量與原始觀測數量相同),與每個節點在確定最佳分割時只考慮特徵的子集。這片由隨機化決策樹組成的「森林」透過投票來確定預測類別。
使用訓練好的模型進行預測非常簡單:
CODE_BLOCK_81
隨機森林的關鍵引數
RandomForestClassifier使用了許多與DecisionTreeClassifier相同的引數。例如,我們可以更改用於評估分割品質的指標:
CODE_BLOCK_82
在這個範例中,我將分割品質的評估標準從預設的基尼不純度(Gini impurity)改為熵(entropy)。兩者都是衡量節點純度的方法,但計算方式不同。
除此之外,隨機森林還有一些特有或特別重要的引數:
max_features:確定每個節點要考慮的最大特徵數量。它可以接受多種引數形式,包括整數(特徵數量)、浮點數(特徵百分比)和"sqrt"(特徵數量的平方根)。預設值為"auto",其作用與"sqrt"相同。
bootstrap:決定是否使用帶替換的抽樣(預設設定)來建立每棵樹考慮的觀測值子集。
n_estimators:設定森林中要包含的決策樹數量。增加樹的數量通常會提高模型效能,但也會增加計算成本。
n_jobs:雖然不是隨機森林特有的引數,但由於我們實際上是訓練多個決策樹模型,所以設定__INLINE_CODE_44__來利用所有可用的CPU核心通常很有用。
這些引數讓隨機森林具有很高的靈活性,能夠適應不同的資料和問題。與單一決策樹相比,隨機森林通常能提供更好的預測效能和泛化能力。
訓練隨機森林迴歸器:處理連續型預測問題
除了分類別題,隨機森林也能有效處理迴歸問題。
使用Scikit-learn訓練隨機森林迴歸器
以下是使用scikit-learn的RandomForestRegressor訓練隨機森林迴歸模型的方法:
CODE_BLOCK_83
在這段程式碼中,我使用了波士頓房價資料集(Boston Housing Dataset),但只選擇了前兩個特徵來簡化範例。與分類別類別,__INLINE_CODE_116__也是從__INLINE_CODE_110__模組中載入的。
建立迴歸器物件時,我同樣設定了__INLINE_CODE_112__確保結果可重現性,以及__INLINE_CODE_44__利用所有可用的CPU核心。然後使用__INLINE_CODE_114__方法訓練模型。
隨機森林迴歸器的工作原理與分類別相似:它也是建立多棵決策樹,每棵樹使用觀測值的自助抽樣,與每個節點只考慮特徵的子集。不同的是,迴歸器預測的是連續值,而非類別。
隨機森林迴歸器的重要引數
與__INLINE_CODE_111__類別,__INLINE_CODE_116__也有一些重要的引數:
max_features:設定每個節點要考慮的最大特徵數量。預設為p個特徵,其中p是特徵總數。
bootstrap:設定是否使用帶替換的抽樣。預設為True。
n_estimators:設定要構建的決策樹數量。預設為10。
這些引數的調整對模型效能有顯著影響,因此在實際應用中,進行超引數調優通常是必要的。
隨機森林迴歸器在處理非線性關係和複雜特徵互動方面表現出色,是處理迴歸問題的強大工具。與線性迴歸相比,它不需要假設特徵和目標變數之間存線上性關係,這使它更適合處理真實世界的複雜資料。
識別隨機森林中的重要特徵:洞察模型決策依據
隨機森林的一個強大功能是能夠評估特徵的重要性,這對於理解模型和進行特徵選擇非常有價值。
計算和視覺化特徵重要性
以下是如何計算和視覺化隨機森林模型中各特徵重要性的方法:
CODE_BLOCK_84
這段程式碼展示瞭如何從訓練好的隨機森林模型中提
解讀特徵重要性:隨機森林模型的解釋力
在機器學習領域,理解模型如何做出決策至關重要。決策樹和隨機森林等樹狀模型的一大優勢就是它們的可解釋性。當我分析一個複雜的隨機森林模型時,首先會關注特徵重要性,這能幫助我理解哪些變數對預測結果影響最大。
特徵重要性的原理與計算
特徵重要性的基本原理非常直觀。當決策樹進行分割時,會選擇能最大程度減少不純度的特徵。在分類別題中,不純度通常用Gini指數或熵來衡量;而在迴歸問題中,則使用方差。那些能產生較大不純度減少的特徵,自然被視為更重要。
在scikit-learn中,可以輕鬆取得特徵重要性:
CODE_BLOCK_85
執行後會得到一個陣列,例如:
CODE_BLOCK_86
這些數值加總為1,數值越高表示特徵越重要。例如,在這個鳶尾花分型別中,第四個特徵(花瓣寬度,佔重要性約49%)是最重要的,其次是第三個特徵(花瓣長度,約37%)。
這個重要性陣列告訴我們,在鳶尾花分類別務中,花瓣的特徵(長度和寬度)比花萼特徵更具判別力。具體來說,花瓣寬度單獨就能解釋模型近一半的預測能力。這種數值化的重要性分析讓我們能夠客觀地評估特徵價值,而不僅僅依靠直覺。
特徵重要性的侷限性
在使用特徵重要性時,需要注意兩個關鍵問題:
類別特徵的處理:當我們將名義類別特徵(如顏色、城市)轉換為多個二元特徵(one-hot編碼)時,該特徵的重要性會被分散到這些二元特徵上。這可能導致每個二元特徵看起來都不重要,即使原始類別特徵實際上非常重要。
特徵相關性的影響:當兩個特徵高度相關時,模型往往會將大部分重要性賦予其中一個特徵,使另一個特徵看起來不那麼重要。這會影響我們對模型的解釋。
在實務應用中,我總是將特徵重要性視為一種起點,而非終點。它提供了初步的特徵評估,但需要結合領域知識和其他分析方法來全面理解模型。
隨機森林中的特徵選擇技術
特徵選擇是提高模型效能、降低過擬合風險和增強可解釋性的關鍵步驟。在實際專案中,我發現隨機森林本身就提供了一種強大的特徵選擇機制。
根據重要性的特徵選擇方法
以下是如何在隨機森林中進行特徵選擇的實用方法:
CODE_BLOCK_87
這段程式實作了一個簡潔的兩階段工作流程:
- 首先用所有特徵訓練一個隨機森林模型,並計算特徵重要性
- 然後只保留重要性超過閾值的特徵(這裡是0.3),建立一個更精簡的模型
__INLINE_CODE_123__類別常實用,它自動處理特徵選擇過程,讓我們可以專注於設定適當的閾值。__INLINE_CODE_44__引數利用所有可用的CPU核心加速計算,這在處理大型資料集時特別有價值。
特徵選擇的應用場景與注意事項
特徵選擇在以下情況特別有用:
- 降低模型複雜度和運算成本
- 減少過擬合風險,提高泛化能力
- 提高模型可解釋性,讓結果更容易被利益相關者接受
- 識別關鍵預測因子,指導後續資料收集
然而,使用這種方法時需要注意兩個重要的限制:
類別特徵分散效應:經過one-hot編碼的類別特徵會有重要性被稀釋的問題。例如,如果"城市"這個特徵被編碼為50個二元特徵,每個特徵的重要性可能都不高,即使整體而言"城市"是重要的預測因子。
相關特徵的重要性分配:當特徵間高度相關時,重要性往往會偏向其中一個特徵。例如,身高和體重通常高度相關,模型可能會將大部分重要性賦予身高,使體重看起來不重要,即使兩者實際上可能同樣重要。
針對這些限制,我通常會結合領域知識和其他特徵選擇方法(如遞迴特徵消除或根據統計檢驗的方法)來做出更全面的判斷。
處理不平衡類別問題
在實際應用中,不平衡類別問題非常普遍。例如,信用卡詐騙檢測中,欺詐交易可能只佔總交易的0.1%;醫療診斷中,罕見疾病的陽性樣本往往極少。如果不加以處理,這種不平衡會導致模型偏向多數類別而在少數類別表現不佳。
使用隨機森林處理不平衡資料
scikit-learn的隨機森林提供了內建的類別權重調整機制:
CODE_BLOCK_88
這個例子展示瞭如何處理不平衡類別問題:
- 首先人為建立不平衡資料集(移除部分觀察值)
- 將多類別題簡化為二元問題(類別0與非0)
- 使用__INLINE_CODE_125__引數自動調整類別權重
當設定__INLINE_CODE_125__時,scikit-learn會自動計算權重,使少數類別得更高的權重。權重計算公式為: CODE_BLOCK_89 其中wj是類別j的權重,n是總觀測數,nj是類別j中的觀測數,k是類別總數。
在本例中,有2個類別(k),110個觀測值(n),其中類別0有10個觀測值,類別1有100個觀測值。因此:
- 小類別的權重:110/(2×10) = 5.5
- 大類別的權重:110/(2×100) = 0.55
這種權重調整確保模型在訓練過程中更加關注少數類別的樣本。
不平衡類別處理的替代方法
除了類別權重調整外,處理不平衡類別問題的常用方法還包括:
- 上取樣(Upsampling):增加少數類別本,如SMOTE(合成少數類別取樣技術)
- 下取樣(Downsampling):減少多數類別本
- 整合方法:結合多個模型,如EasyEnsemble或BalanceCascade
- 調整決策閾值:在預測階段調整決策邊界,使模型更容易預測少數類別 在實踐中,我發現結合多種方法通常能獲得最佳效果,例如同時使用SMOTE和類別權重調整,再配合適當的評估指標(如F1分數或AUC)來評估模型表現。
控制決策樹大小:平衡複雜度與泛化能力
決策樹模型的一個常見問題是過擬合——模型可能會生長得過於複雜,完美擬合訓練資料但泛化能力差。控制樹的大小和結構是解決這個問題的關鍵。
決策樹引數調整技巧
scikit-learn提供了多種引數來控制決策樹的生長:
CODE_BLOCK_90
這段程式碼示了scikit-learn中控制決策樹結構的主要引數:
INLINE_CODE_127:樹的最大深度。如果設為None,則樹會生長到所有葉節點都純淨(即只包含一個類別的樣本)或無法再進一步分裂。設定一個整數值可以有效"修剪"樹的深度。
INLINE_CODE_128:分裂一個內部節點所需的最小樣本數。可以是整數(絕對數量)或浮點數(樣本比例)。
INLINE_CODE_129:一個葉節點必須包含的最小樣本數。同樣可以是整數或浮點數。
INLINE_CODE_130:最大葉節點數量,用於限制樹的複雜度。
INLINE_CODE_131:執行分裂所需的最小不純度減少量。只有當分裂能減少至少這麼多的不純度時,才會進行分裂。
在實務上,我最常調整的是__INLINE_CODE_127__和__INLINE_CODE_131__引數。較淺的樹(有時稱為"樹樁")是更簡單的模型,通常有較低的方差但較高的偏差。
樹大小控制的實用策略
根據我的經驗,控制決策樹大小的最佳實踐包括:
交叉驗證:使用網格搜尋和交叉驗證找到最佳的樹大小引數
視覺化不同深度的樹:觀察不同深度的樹結構和效能,找到最佳平衡點
預剪枝vs後剪枝:scikit-learn主要提供預剪枝(在構建過程中限制樹的生長),但有時後剪枝(先生長完整樹,再移除不重要的分支)也很有用
領域知識結合:利用領域知識設定合理的引數起點,例如在某些醫療應用中,可能需要限制樹的深度以確保模型的可解釋性
AdaBoost與整合模型的強大威力
近年來在處理各種複雜分類別迴歸問題時,我發現整合學習(Ensemble Learning)技術越來越受到關注。在這些技術中,AdaBoost(Adaptive Boosting)尤為特別。不同於傳統的單一模型訓練方式,AdaBoost透過一種獨特的迭代過程,逐步提升對困難觀測值的預測能力。
AdaBoost的核心工作原理
AdaBoost的精妙之處在於它如何處理訓練資料的權重。以下是它的運作流程:
- 首先對所有訓練樣本賦予相同權重
- 在資料上訓練一個「弱」模型
- 對每個觀測值進行處理:
- 如果弱模型正確預測了觀測值xi,則增加該觀測值的權重wi
- 如果弱模型錯誤預測了觀測值xi,則減少該觀測值的權重wi
- 訓練新的弱模型,賦予權重較高的觀測值更高的優先順序
- 重複步驟3和4,直到資料被完美預測或達到預設的弱模型數量
這個過程的最終結果是一個彙總模型,其中個別弱模型專注於那些較難預測的觀測值。在實際應用中,這種策略能夠顯著提升整體預測效能。
在Scikit-learn中實作AdaBoost
Scikit-learn提供了兩個主要的AdaBoost實作:INLINE_CODE_134__和__INLINE_CODE_135。在使用這些工具時,需要特別關注以下幾個關鍵引數:
CODE_BLOCK_91
這段程式碼展示瞭如何使用Scikit-learn建立AdaBoost分類別。我們首先建立了一個淺層決策樹(決策樹樁)作為弱學習器,然後將其傳入__INLINE_CODE_134__。這裡設定了100個弱學習器,並使用預設學習率1.0。決策樹樁(INLINE_CODE_137)是AdaBoost中最常用的弱學習器,因為它們簡單與計算快速。
關鍵引數詳解
使用AdaBoost時,需要理解並調整這些關鍵引數:
- base_estimator:用於訓練弱模型的學習演算法。預設使用決策樹,這也是最常見的選擇。
- n_estimators:迭代訓練的模型數量,即弱學習器的數量。
- learning_rate:每個模型對權重的貢獻程度,預設為1。降低學習率會使權重增減幅度變小,迫使模型訓練得更慢,但有時能獲得更好的效能。
- loss:僅用於__INLINE_CODE_135__,設定更新權重時使用的損失函式。預設為線性損失函式,也可以改為平方或指數損失。
在我的實踐中,通常會先以預設引數開始,然後根據交叉驗證結果調整__INLINE_CODE_139__和__INLINE_CODE_140__。特別是當資料量較小時,降低學習率並增加弱學習器的數量往往能改善模型表現。
隨機森林的Out-of-Bag誤差評估
在機器學習工作流程中,模型評估是一個關鍵環節。對於隨機森林(Random Forest)這類別成模型,我們有一種特殊的評估方法——Out-of-Bag(OOB)誤差,可以在不使用交叉驗證的情況下評估模型效能。
隨機森林的OOB評分計算
OOB評分是隨機森林的一個內建特性,利用了訓練過程中的自舉抽樣(Bootstrap Sampling)特性。以下是如何在Scikit-learn中實作OOB評分的計算:
CODE_BLOCK_92
這段程式碼展示瞭如何使用Scikit-learn的__INLINE_CODE_111__實作OOB評分計算。關鍵是設定__INLINE_CODE_142__引數,這會讓模型在訓練時自動計算OOB評分。訓練完成後,我們可以透過__INLINE_CODE_143__屬性取得評分結果。這個例子中,我們得到了約95.33%的OOB準確率,這表明模型有很好的泛化能力。引數__INLINE_CODE_44__讓演算法使用所有可用的CPU核心,大幅加速訓練過程,特別是當我們有許多樹(這裡是1000棵)時。
OOB評分的工作原理與價值
在隨機森林中,每棵決策樹都使用一個自舉樣本(即有放回抽樣的子集)進行訓練。這意味著對於每棵樹,都有一部分觀測值未被用於訓練——這些就是所謂的Out-of-Bag觀測值。
OOB評分的計算過程如下:
- 對於每個觀測值,找出所有未使用該觀測值進行訓練的樹
- 使用這些樹對該觀測值進行預測
- 比較預測結果與真實值
- 彙總所有觀測值的評分結果
OOB評分的優勢在於它不需要額外的驗證集或交叉驗證,就能提供模型泛化能力的可靠估計。這在計算資源有限或資料集較小的情況下特別有用。
在我的實際專案中,OOB評分常被用作隨機森林調參的快速反饋機制。例如,可以透過觀察不同__INLINE_CODE_139__值下的OOB評分變化,找出最佳的樹數量。
K近鄰演算法:簡單而強大的分類別
K近鄰(K-Nearest Neighbors,KNN)分類別是監督式學習中最簡單也是最常用的分類別之一。與大多數機器學習演算法不同,KNN被視為「懶惰學習器」(lazy learner),因為它不會在訓練階段建立明確的模型,而是在預測時才進行計算。
尋找觀測值的最近鄰
KNN的核心是找到觀測值的最近鄰。在Scikit-learn中,我們可以使用__INLINE_CODE_146__類別實作這一功能:
CODE_BLOCK_93
這段程式碼展示瞭如何找到一個觀測值的最近鄰。首先,我們標準化特徵,這在根據距離的演算法中非常重要,因為它確保所有特徵在相同的尺度上。然後,我們建立一個__INLINE_CODE_146__例項,設定尋找2個最近鄰,並使用標準化後的資料進行訓練。接著,我們定義一個新的觀測值__INLINE_CODE_148__,並使用__INLINE_CODE_149__方法找到其最近鄰。該方法回傳兩個陣列:INLINE_CODE_150(到每個最近鄰的距離)和__INLINE_CODE_151__(最近鄰在原始資料中的索引)。最後,我們使用這些索引從標準化資料中取得最近鄰的實際值。
距離度量方法
在KNN中,如何測量距離是一個關鍵問題。Scikit-learn提供了多種距離度量方法:
歐氏距離(Euclidean Distance): CODE_BLOCK_94
曼哈頓距離(Manhattan Distance): CODE_BLOCK_95
閔可夫斯基距離(Minkowski Distance)(預設):
CODE_BLOCK_96
其中,$x_i$ 和 $y_i$ 是我們計算距離的兩個觀測值的第 $i$ 個特徵。閔可夫斯基距離有一個超引數 $p$,當 $p=1$ 時等同於曼哈頓距離,當 $p=2$ 時等同於歐氏距離。在Scikit-learn中,預設 $p=2$。
我們可以使用__INLINE_CODE_152__引數設定距離度量方法:
CODE_BLOCK_97
建立鄰居圖譜
除了找到特定觀測值的最近鄰外,我們還可以使用__INLINE_CODE_153__建立一個矩陣,指示每個觀測值的最近鄰:
CODE_BLOCK_98
這段程式碼建立了一個鄰居圖譜,即一個矩陣,指示每個觀測值的最近鄰。__INLINE_CODE_153__方法回傳一個稀疏矩陣,我們使用__INLINE_CODE_155__將其轉換為密集矩陣。預設情況下,每個觀測值也會被視為自己的最近鄰,所以我們透過迴圈移除這些自參照(將對角線元素設為0)。最後,我們列印出第一個觀測值的兩個最近鄰,結果是一個包含大量0和少量1的陣列,其中1表示相應索引的觀測值是最近鄰。
標準化的重要性
在使用KNN或任何根據距離的演算法時,特徵標準化是一個關鍵步驟。這是因為距離度量方法會將所有特徵視為具有相同尺度,但如果一個特徵以百萬美元為單位,而另一個
K近鄰分類別:根據相似性的直觀分類別法
K近鄰(K-Nearest Neighbors,KNN)分類別機器學習中最直觀與易於理解的分類別法之一。這種演算法根據一個簡單的概念:相似的觀測值通常屬於相同的類別。當我實作複雜的深度學習模型時,常常會先用KNN建立基準模型,因為它簡單與效能通常不差。今天讓我們探討KNN分類別的實作方式。
建立K近鄰分類別
假設我們有一個未知類別的觀測值,我們希望根據其鄰居的類別來預測其所屬類別。只要資料集不是特別龐大,scikit-learn的__INLINE_CODE_156__是個理想選擇。
CODE_BLOCK_99
這段程式碼展示瞭如何使用scikit-learn建立一個K近鄰分類別:
- 首先載入鳶尾花資料集,這是一個包含三種鳶尾花類別的經典資料集
- 使用__INLINE_CODE_99__標準化特徵,這一步對KNN演算法至關重要,因為KNN依賴於距離計算
- 建立__INLINE_CODE_156__,設定__INLINE_CODE_159__表示考慮最近的5個鄰居,__INLINE_CODE_44__表示使用所有可用的CPU核心
- 使用__INLINE_CODE_161__方法訓練模型,傳入標準化的特徵和目標變數
- 建立兩個新的觀測值並預測它們的類別
KNN的工作原理與機率分析
在KNN中,給定一個未知類別的觀測值x_u,演算法首先識別k個最接近的觀測值(稱為x_u的鄰域),然後這k個觀測值根據它們的類別進行「投票」,得票最多的類別即為x_u的預測類別。
更正式地說,x_u屬於某個類別j的機率為:
CODE_BLOCK_100
其中,ν是x_u鄰域中的k個觀測值,y_i是第i個觀測值的類別,I是指示函式(如果條件為真則為1,否則為0)。
我們可以使用__INLINE_CODE_25__方法檢視這些機率值:
CODE_BLOCK_101
這段程式碼展示了KNN如何電腦率:
- 對於第一個觀測值,有60%的機率屬於類別1,40%的機率屬於類別2
- 對於第二個觀測值,有100%的機率屬於類別2
機率最高的類別成為預測類別。這就解釋了為什麼先前的__INLINE_CODE_163__方法回傳[1, 2]。
KNeighborsClassifier的重要引數
__INLINE_CODE_156__有幾個值得注意的引數:
- INLINE_CODE_152:設定距離度量方式(如歐氏距離、曼哈頓距離等)
- INLINE_CODE_63:決定使用多少CPU核心,因為KNN預測需要計算點到所有點的距離,所以強烈建議使用多核心
- INLINE_CODE_167:設定計算最近鄰的方法,預設情況下會自動選擇最佳演算法
- INLINE_CODE_168:預設為__INLINE_CODE_169__,表示鄰域中所有觀測值投票權重相等;設為__INLINE_CODE_170__時,較近的觀測值投票權重更大
在實際應用中,我發現權重設定為__INLINE_CODE_170__能在許多情況下提升模型效能,這很符合直覺—更相似的鄰居可能更能告訴我們關於觀測值類別的訊息。
最後,由於距離計算會將所有特徵視為等比例,所以在使用KNN前標準化特徵非常重要。
識別最佳鄰居數量
K的值對KNN分類別有重大影響。在機器學習中,我們試圖在偏差(bias)和方差(variance)之間取得平衡,而在KNN中,K值的選擇就明確體現了這一權衡。
讓我展示如何使用__INLINE_CODE_43__選擇最佳K值:
CODE_BLOCK_102
這段程式碼展示瞭如何尋找最佳K值:
- 建立一個包含標準化器和KNN分類別的管道
- 定義要搜尋的K值範圍(1到10)
- 使用__INLINE_CODE_43__進行5折交叉驗證,找出表現最佳的K值
- 最後輸出最佳K值
在KNN中,如果K=n(n為觀測值數量),則模型具有高偏差但低方差;如果K=1,則模型具有低偏差但高方差。最佳模型來自於找到能夠平衡這個偏差-方差權衡的K值。
在我的實踐中,通常會發現最佳K值在5到10之間,但這高度依賴於特定資料集的結構和噪音程度。如果資料集噪音較大,較大的K值通常會表現更好;相反,如果資料集乾淨與類別邊界明確,較小的K值可能更合適。
建立根據半徑的近鄰分類別
與KNN不同,根據半徑的近鄰分類別考慮的是在指定半徑內的所有觀測值。當資料分佈不均勻或需要處理異常值時,這種方法特別有用。
CODE_BLOCK_103
這段程式碼展示瞭如何使用__INLINE_CODE_174__:
- 載入並標準化鳶尾花資料集
- 建立一個半徑為0.5的分類別
- 訓練模型並預測一個新觀測值的類別
在根據半徑的分類別中,觀測值的類別由所有在給定半徑r內的觀測值的類別預測。這與KNN不同,KNN總是考慮固定數量的鄰居,不管它們有多遠。
__INLINE_CODE_174__有兩個重要引數:
- INLINE_CODE_176:決定哪些觀測值被視為鄰居的固定區域半徑
- INLINE_CODE_177:指定當沒有觀測值在半徑內時給予的標籤
我發現這種分類別在處理有明確密度區分的資料集時特別有效。例如,在異常檢測任務中,如果一個點周圍沒有其他點(即沒有觀測值在其半徑內),它很可能是異常值。
邏輯迴歸:強大的二元分類別
儘管名稱中有「迴歸」,邏輯迴歸實際上是一種廣泛使用的分類別術。讓我們看看如何使用scikit-learn訓練一個簡單的邏輯迴歸二元分類別。
CODE_BLOCK_104
這段程式碼展示瞭如何使用__INLINE_CODE_178__進行二元分類別
- 載入鳶尾花資料集的前100個樣本(只包含兩個類別)
- 標準化特徵
- 建立邏輯迴歸模型並訓練
- 使用訓練好的模型預測新觀測值的類別及相應機率
儘管名稱中有「迴歸」,邏輯迴歸實際上是一種廣泛使用的二元分類別(即目標向量只能有兩個值)。在邏輯迴歸中,線性模型(如β₀ + β₁x)被納入邏輯(或稱S型)函式 1/(1 + e^(-z)) 中,使得:
CODE_BLOCK_105
其中P(y_i = 1 | X)是第i個觀測值的目標值y_i為類別1的機率,X是訓練資料,β₀和β₁是待學習的引數,e是尤拉數。
邏輯函式的作用是將函式輸出值限制在0和1之間,使其可以被解釋為機率。如果P(y_i = 1 | X) > 0.5,則預測y_i為類別1,否則預測為類別0。
分類別選擇與應用場景
在實際應用中,選擇適合的分類別取決於多種因素。以下是我對這些分類別使用場景的觀察:
KNN適用場景
邏輯迴歸模型的預測能力
邏輯迴歸是機器學習中最基礎卻也最實用的分類別之一。在實際應用中,模型訓練完成後,我們最關心的就是它的預測能力。在使用 scikit-learn 時,邏輯迴歸模型提供了兩種主要的預測方法:直接分類別機率估計。
預測新觀測值的類別
當我們需要對新資料進行分類別,可以使用 predict()
方法:
# 建立新的觀測值
new_observation = [[.5, .5, .5, .5]]
# 預測類別
predicted_class = model.predict(new_observation)
# 輸出: array([1])
這段程式碼展示瞭如何使用已訓練的邏輯迴歸模型來預測新資料點的類別。新觀測值是一個包含四個特徵的向量,每個特徵值都設為 0.5。模型分析這些特徵後,預測該觀測值屬於類別 1。在二元分類別題中,這通常代表「正類別(如:郵件是垃圾郵件、病人有某種疾病等)。
取得類別預測機率
除了直接預測類別外,我們通常也需要了解預測的確定性程度,這時可以使用 predict_proba()
方法:
# 檢視預測機率
probability = model.predict_proba(new_observation)
# 輸出: array([[ 0.18823041, 0.81176959]])
這段程式碼揭示了模型對預測結果的信心程度。結果顯示這個觀測值有 18.8% 的機率屬於類別 0,有 81.2% 的機率屬於類別 1。這種機率資訊比簡單的類別預測更有價值,特別是在風險評估或需要設定不同決策閾值的場景中。
在醫療診斷等高風險應用中,我經常會關注這些機率值,而非僅依賴二元預測結果。例如,當模型預測患者有 60% 機率患某種疾病時,這種「不那麼確定」的結果可能需要進一步檢查,而不是直接做出診斷結論。
訓練多類別分類別
多類別分類別挑戰與解決方案
在實際應用中,我們經常需要處理超過兩個類別的分類別題。雖然邏輯迴歸本質上是二元分類別,但有兩種巧妙的擴充套件方法可以處理多類別問題。
# 載入必要的函式庫
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
# 載入鳶尾花資料集
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立一對多(one-vs-rest)邏輯迴歸模型
logistic_regression = LogisticRegression(random_state=0, multi_class="ovr")
# 訓練模型
model = logistic_regression.fit(features_standardized, target)
這段程式碼使用著名的鳶尾花資料集建立多類別分型別。首先使用 StandardScaler
對特徵進行標準化處理,這對邏輯迴歸特別重要,因為它能使不同尺度的特徵處於相同的影響力水平。然後建立一個 LogisticRegression
模型,並設定 multi_class="ovr"
,表示使用一對多策略處理多類別問題。
在處理多類別分類別,我發現標準化特徵是必不可少的步驟。曾經在一個產品分類別案中,忽略了這一步驟導致某些數值範圍較大的特徵主導了模型決策,產生了明顯偏差的結果。
一對多 vs 多項式邏輯迴歸
在 scikit-learn 中,邏輯迴歸支援兩種多類別分類別法:
一對多邏輯迴歸 (One-vs-Rest, OVR):
- 為每個類別單獨訓練一個二元分類別
- 每個分類別預測「是這個類別」或「不是這個類別」
- 假設各個分類別題相互獨立
多項式邏輯迴歸 (Multinomial Logistic Regression, MLR):
- 使用 softmax 函式替代標準邏輯函式
- 機率計算公式:P(y_i = k | X) = e^(βk•xi) / ∑(j=1 to K) e^(βj•xi)
- 其中 P(y_i = k | X) 表示第 i 個觀測值屬於類別 k 的機率,K 是類別總數
要使用多項式邏輯迴歸,只需將 multi_class
引數設為 “multinomial”:
# 建立多項式邏輯迴歸模型
multinomial_logistic = LogisticRegression(random_state=0, multi_class="multinomial")
# 訓練模型
multinomial_model = multinomial_logistic.fit(features_standardized, target)
這段程式碼展示瞭如何切換到多項式邏輯迴歸模型。多項式模型的一個實際優勢是它的預測機率通常更可靠(更好校準)。在需要精確機率估計的應用中,如風險評估或需要排名的推薦系統,多項式模型通常是更好的選擇。
在實務中,我建議同時嘗試這兩種方法並比較效果。在處理類別間有明顯相關性的問題時,多項式模型往往表現更佳;而當類別間較為獨立時,一對多方法可能更合適與計算效率更高。
透過正規化減少模型變異性
調整正規化強度引數
邏輯迴歸模型容易過度擬合複雜資料,導致高變異性。正規化是解決這一問題的有效方法。
# 載入必要的函式庫
from sklearn.linear_model import LogisticRegressionCV
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立具有交叉驗證的邏輯迴歸物件
logistic_regression = LogisticRegressionCV(
penalty='l2', Cs=10, random_state=0, n_jobs=-1)
# 訓練模型
model = logistic_regression.fit(features_standardized, target)
這段程式碼使用 LogisticRegressionCV
類別來自動調整正規化強度引數 C。引數 Cs=10
表示將測試 10 個不同的 C 值,這些值是從對數尺度的範圍中自動生成的。n_jobs=-1
設定使用所有可用的 CPU 核心進行平行計算,加速交叉驗證過程。penalty='l2'
指定使用 L2 正規化。
在實際專案中,正規化引數的選擇往往對模型效能有決定性影響。我在處理一個客戶流失預測模型時,發現合適的正規化設定將模型的泛化能力提高了近 15%,大幅減少了過度擬合現象。
正規化原理與實踐
正規化透過在損失函式中增加懲罰項來減少複雜模型的變異性。常見的正規化方法有 L1 和 L2 正規化:
L1 正規化 (Lasso):
- 懲罰項:α∑|β_j|
- 特點:促進特徵選擇,產生稀疏模型
- 適用場景:高維資料,希望自動進行特徵選擇
L2 正規化 (Ridge):
- 懲罰項:α∑(β_j)²
- 特點:平滑權重分佈,防止任何單一特徵權重過大
- 適用場景:處理多重共線性問題,一般預設選擇
在 scikit-learn 中,C 引數是正規化強度 α 的倒數:C = 1/α。較小的 C 值表示較強的正規化,較大的 C 值表示較弱的正規化。
在模型調整時,LogisticRegressionCV
可以自動尋找最佳的 C 值,但不能同時搜尋不同的正規化類別。如果需要比較 L1 和 L2 正規化效果,則需要使用 GridSearchCV
或 RandomizedSearchCV
等更通用的模型選擇工具。
在超大資料集上訓練分類別
使用隨機平均梯度最佳化
當資料量極大時,傳統最佳化法可能效率低下。隨機平均梯度 (SAG) 方法提供了高效的解決方案。
# 載入必要的函式庫
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
# 載入資料
iris = datasets.load_iris()
features = iris.data
target = iris.target
# 標準化特徵
scaler = StandardScaler()
features_standardized = scaler.fit_transform(features)
# 建立使用SAG最佳化的邏輯迴歸物件
logistic_regression = LogisticRegression(random_state=0, solver="sag")
# 訓練模型
model = logistic_regression.fit(features_standardized, target)
這段程式碼設定了邏輯迴歸模型使用 SAG 求解器(最佳化)。對於非常大的資料集,SAG 方法能夠比傳統方法快得多。引數 solver="sag"
指定使用隨機平均梯度方法進行模型訓練。特別注意的是,SAG 最佳化對特徵縮放非常敏感,因此在使用前必須進行特徵標準化。
在處理一個包含數百萬筆記錄的電子商務資料集時,我發現 SAG 最佳化將訓練時間從幾小時縮短到幾分鐘,同時保持了模型精確度。這種效率提升在需要頻繁更新模型的生產環境中尤為重要。
大資料分類別的最佳實踐
在處理超大資料集時,幾點關鍵考量:
- 特徵標準化:使用 SAG 最佳化前必須標準化特徵,否則可能導致收斂問題
- 最佳化選擇:scikit-learn 提供多種最佳化,包括:
- ’liblinear’:小型資料集的預設選擇
- ’newton-cg’:適用於中等規模多類別問題
- ’lbfgs’:類別 ’newton-cg’,但記憶體求較低
- ‘sag’:大型資料集的高效選擇
- ‘saga’:支援 L1 正規化的 SAG 變種
- 記憶體理:對於超大資料集,考慮使用部分擬合或增量學習方法
在實際應用中,最佳化的選擇應根據資料規模、特徵數量和可用計算資源來決定。對於真正的超大規模問題,可能還需要考慮分散式機器學習框架。