終于把機器學習中的交叉驗證搞懂了!!!
大家好,我是小寒
今天給大家分享機器學習中的一個關鍵概念,交叉驗證
交叉驗證是機器學習中用于評估模型泛化能力的一種方法,用于衡量模型在訓練集之外的新數(shù)據(jù)上的表現(xiàn)。
它的核心思想是將數(shù)據(jù)集劃分為多個子集,模型在不同的子集上交替進行訓練和測試,從而減少模型在某一特定數(shù)據(jù)分割上的偏差。交叉驗證能夠有效地降低模型過擬合的風險,從而提高模型評估的穩(wěn)定性和可靠性。
交叉驗證的作用
- 提升模型穩(wěn)定性
通過在不同數(shù)據(jù)組合上測試模型,可以減少由于數(shù)據(jù)集單一劃分引起的偏差。 - 防止過擬合
在多個驗證集上驗證模型,可以有效評估模型在新數(shù)據(jù)上的表現(xiàn),從而降低過擬合的風險。 - 更客觀的評估
交叉驗證提供了一種系統(tǒng)性、可重復的方法,使模型評估更為準確和客觀。
交叉驗證的工作流程
- 數(shù)據(jù)劃分
將數(shù)據(jù)集隨機劃分為多個子集(通常稱為“折”)。 - 循環(huán)訓練和驗證
在每次循環(huán)中,選擇一個子集作為驗證集,剩下的子集作為訓練集,用訓練集訓練模型,然后在驗證集上測試模型的性能。 - 計算平均性能
每次驗證的結果都記錄下來,最后對這些結果求平均值,得到模型的總體性能評估。
常見的交叉驗證方法
1.K 折交叉驗證方法
K 折交叉驗證將數(shù)據(jù)集分成 K 個不重疊的子集(折),每次將其中一個子集(折)作為測試集,其余 K-1 個折作為訓練集。
重復這個過程 K 次,每次用不同的折作為測試集,最終將 K 次測試的結果平均,以得到模型的總體性能。
圖片
優(yōu)點
- 每個數(shù)據(jù)點都能作為測試集的一部分,且每個折都被用于訓練和測試。
- 適合數(shù)據(jù)量較小的情況。
缺點
- 計算開銷較大,特別是當 K 較大時。
- 對于時間序列等具有時間依賴性的數(shù)據(jù),不適用。
from sklearn.model_selection import KFold, cross_val_score
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
# 加載數(shù)據(jù)
data = load_iris()
X, y = data.data, data.target
# 設置K折交叉驗證
kf = KFold(n_splits=5)
model = RandomForestClassifier()
# 使用交叉驗證評分
scores = cross_val_score(model, X, y, cv=kf)
print("K-Fold Cross-Validation Scores:", scores)
print("Mean Score:", scores.mean())
2.留一交叉驗證
留一交叉驗證是 K 折交叉驗證的極端形式,其中 K 等于樣本總數(shù) N。
每次選取一個樣本作為測試集,其余 N-1 個樣本作為訓練集,重復該過程 N 次,最后計算平均誤差。
圖片
優(yōu)點
- 使用了幾乎所有的數(shù)據(jù)進行訓練,模型訓練效果較好。
- 適合數(shù)據(jù)集極小的情況。
缺點
- 計算成本高,特別是當數(shù)據(jù)量很大時。
- 當數(shù)據(jù)包含噪聲時,結果容易受到單個異常值的影響。
from sklearn.model_selection import LeaveOneOut
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
# 加載數(shù)據(jù)
data = load_iris()
X, y = data.data, data.target
# 設置留一交叉驗證
loo = LeaveOneOut()
model = RandomForestClassifier()
# 使用交叉驗證評分
scores = cross_val_score(model, X, y, cv=loo)
print("Leave-One-Out Cross-Validation Scores:", scores)
print("Mean Score:", scores.mean())
3.引導法
引導法通過有放回地從原始數(shù)據(jù)集中抽取樣本,生成多個子樣本(通常與原始數(shù)據(jù)集大小相同)。
每次從生成的樣本中訓練模型,未被抽中的樣本(稱為“包外樣本”)作為測試集。
重復該過程多次,并對多次測試結果進行平均。
圖片
優(yōu)點
- 包外樣本可以很好地代表未見數(shù)據(jù),從而提供較好的泛化誤差估計。
- 數(shù)據(jù)集中的每個樣本有可能在不同的抽樣中多次被使用,從而增加數(shù)據(jù)利用率。
缺點:
- 由于樣本是有放回地抽取,導致可能有一些樣本被過多地抽取,而有些樣本未被抽中。
- 計算復雜度較高。
import numpy as np
from sklearn.utils import resample
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
# 加載數(shù)據(jù)
data = load_iris()
X, y = data.data, data.target
# 設置引導驗證
n_iterations = 100 # 100次引導采樣
model = RandomForestClassifier()
bootstrapped_scores = []
for _ in range(n_iterations):
# 使用引導法抽樣
X_train, y_train = resample(X, y, replace=True, n_samples=len(y))
X_test = np.array([x for x in X if x.tolist() not in X_train.tolist()])
y_test = np.array([y[i] for i, x in enumerate(X) if x.tolist() not in X_train.tolist()])
# 訓練模型并計算準確率
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
score = accuracy_score(y_test, y_pred)
bootstrapped_scores.append(score)
print("Bootstrap Validation Scores:", bootstrapped_scores)
print("Mean Score:", np.mean(bootstrapped_scores))
4.嵌套交叉驗證
嵌套交叉驗證主要用于模型選擇和超參數(shù)優(yōu)化。
外層交叉驗證用于評估模型的性能,內層交叉驗證用于選擇模型的最佳超參數(shù)。
具體來說,外層將數(shù)據(jù)分成多個折,每個折作為驗證集,剩余部分作為訓練集;而在每個外層折的訓練集中,又使用內層交叉驗證進行超參數(shù)搜索。
優(yōu)點
- 有效防止數(shù)據(jù)泄漏,是超參數(shù)調優(yōu)的標準方法。
- 提供可靠的模型評估結果,適合用于復雜模型的選擇。
缺點
- 計算成本非常高,特別是數(shù)據(jù)集較大或超參數(shù)網(wǎng)格較大時。
from sklearn.model_selection import GridSearchCV, cross_val_score, KFold
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
# 加載數(shù)據(jù)
data = load_iris()
X, y = data.data, data.target
# 設置參數(shù)網(wǎng)格
param_grid = {
'n_estimators': [10, 50, 100],
'max_depth': [3, 5, None]
}
# 設置嵌套交叉驗證
outer_cv = KFold(n_splits=5)
inner_cv = KFold(n_splits=3)
# 設置網(wǎng)格搜索和嵌套交叉驗證
model = RandomForestClassifier()
grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=inner_cv)
nested_scores = cross_val_score(grid_search, X, y, cv=outer_cv)
print("Nested Cross-Validation Scores:", nested_scores)
print("Mean Score:", nested_scores.mean())
5.分層交叉驗證
分層交叉驗證是一種特殊的交叉驗證方法,特別適用于分類任務。
在分層交叉驗證中,每個折內的類別分布與整個數(shù)據(jù)集的類別分布相同,從而在不同折中保持相對一致的標簽分布,避免模型評估因為類別失衡而產生偏差。
圖片
優(yōu)點
- 對于類別不均衡的數(shù)據(jù)特別有效,能夠提供更準確的評估。
- 避免因隨機劃分導致某些折中類別分布嚴重偏斜。
缺點
- 僅適用于分類任務,不適用于回歸或時間序列任務。
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
# 加載數(shù)據(jù)集
data = load_iris()
X, y = data.data, data.target
# 使用分層交叉驗證
skf = StratifiedKFold(n_splits=5)
model = RandomForestClassifier()
# 計算交叉驗證分數(shù)
scores = cross_val_score(model, X, y, cv=skf)
print("Stratified Cross-Validation Scores:", scores)
print("Mean Score:", scores.mean())
6.時間序列交叉驗證
時間序列交叉驗證是一種專門用于時間序列數(shù)據(jù)的模型評估方法。與傳統(tǒng)交叉驗證方法(如 K 折交叉驗證)不同,時間序列交叉驗證遵循時間的自然順序,從過去到未來逐步劃分數(shù)據(jù)。這種方法適用于時間序列預測任務,能夠避免將未來的數(shù)據(jù)泄漏到模型訓練過程中,從而保證模型的真實性能評估。
時間序列交叉驗證的常用方法
滾動預測法
在滾動預測法中,每次劃分訓練和測試集時,訓練集的大小保持不變,僅在時間上向前滾動。每次只使用最新的訓練集數(shù)據(jù)來預測未來的測試集數(shù)據(jù)。適合模擬模型實時滾動預測的情況。
圖片
優(yōu)缺點:
- 優(yōu)點:模擬真實的預測過程,能更好地反映模型在動態(tài)預測中的表現(xiàn)。
- 缺點:每次訓練數(shù)據(jù)有限,模型難以利用更多的歷史數(shù)據(jù),可能導致不穩(wěn)定性。
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
# 創(chuàng)建時間序列數(shù)據(jù)
X = np.arange(1, 101).reshape(-1, 1) # 1到100的時間序列
y = X.flatten() + np.random.normal(scale=5, size=X.shape[0]) # 添加噪聲
# 定義滾動窗口的大小
window_size = 20 # 每次訓練的窗口大小
# 初始化模型
model = LinearRegression()
# 存儲預測結果和誤差
predictions = []
errors = []
# 滾動窗口法進行預測
for i in range(len(X) - window_size - 1):
# 定義訓練集和測試集
X_train = X[i : i + window_size]
y_train = y[i : i + window_size]
X_test = X[i + window_size : i + window_size + 1]
y_test = y[i + window_size : i + window_size + 1]
# 訓練模型
model.fit(X_train, y_train)
# 進行預測
y_pred = model.predict(X_test)
# 記錄預測和誤差
predictions.append(y_pred[0])
mse = mean_squared_error(y_test, y_pred)
errors.append(mse)
print(f"Window {i+1}: Predicted = {y_pred[0]:.2f}, Actual = {y_test[0]:.2f}, MSE = {mse:.2f}")
# 計算平均誤差
average_mse = np.mean(errors)
print(f"\nAverage MSE over all windows: {average_mse:.2f}")
擴展窗口法
在擴展窗口法中,訓練集會隨著時間不斷擴大,即每次訓練時,訓練集包含更長時間段的數(shù)據(jù),而測試集仍為后續(xù)的一小部分數(shù)據(jù)。這種方法能讓模型在預測時利用更多歷史數(shù)據(jù)。
圖片
優(yōu)缺點
- 優(yōu)點:通過逐漸擴大訓練集,模型可以利用更多的歷史信息,提升預測穩(wěn)定性。
- 缺點:計算開銷較大,特別是在訓練集不斷增大時。
from sklearn.model_selection import TimeSeriesSplit
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
import numpy as np
# 創(chuàng)建時間序列數(shù)據(jù)
X = np.arange(1, 101).reshape(-1, 1)
y = X.flatten() + np.random.normal(scale=5, size=X.shape[0])
# 使用TimeSeriesSplit實現(xiàn)滾動預測法
tscv = TimeSeriesSplit(n_splits=5)
model = LinearRegression()
for train_index, test_index in tscv.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print("Test MSE:", mean_squared_error(y_test, y_pred)