簡體   English   中英

cross_val_score 和 cross_val_predict 的區別

[英]Difference between cross_val_score and cross_val_predict

我想使用交叉驗證來評估使用 scikitlearn 構建的回歸模型並感到困惑,我應該使用cross_val_scorecross_val_predict這兩個函數中的cross_val_score 一種選擇是:

cvs = DecisionTreeRegressor(max_depth = depth)
scores = cross_val_score(cvs, predictors, target, cv=cvfolds, scoring='r2')
print("R2-Score: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))

另一個,將 cv 預測與標准r2_score

cvp = DecisionTreeRegressor(max_depth = depth)
predictions = cross_val_predict(cvp, predictors, target, cv=cvfolds)
print ("CV R^2-Score: {}".format(r2_score(df[target], predictions_cv)))

我會假設這兩種方法都是有效的並給出相似的結果。 但這只是小 k 折的情況。 雖然 10 倍 cv 的 r^2 大致相同,但在使用“cross_vall_score”的第一個版本的情況下,對於更高的 k 值,它變得越來越低。 第二個版本幾乎不受折疊數變化的影響。

這種行為是否在意料之中,我是否對 SKLearn 中的簡歷缺乏一些了解?

cross_val_score返回測試折疊的分數,其中cross_val_predict返回測試折疊的預測 y 值。

對於cross_val_score() ,您使用的是輸出的平均值,這將受到折疊數的影響,因為它可能有一些可能具有高錯誤(不正確)的折疊。

cross_val_predict()為輸入中的每個元素返回當該元素在測試集中時為該元素獲得的預測。 [請注意,只有將所有元素分配給測試集一次的交叉驗證策略才能使用]。 所以增加折疊次數,只會增加測試元素的訓練數據,因此可能不會對其結果產生太大影響。

編輯(評論后)

請查看以下有關cross_val_predict如何工作的答案:

scikit-learn cross_val_predict 准確率分數是如何計算的?

我認為cross_val_predict會過擬合,因為隨着折疊次數的增加,更多的數據將用於訓練而更少的數據用於測試。 所以得到的標簽更依賴於訓練數據。 同樣如上所述,一個樣本的預測只進行一次,因此它可能更容易受到數據分裂的影響。 這就是為什么大多數地方或教程都推薦使用cross_val_score進行分析的原因。

所以這個問題也困擾着我,雖然其他人提出了很好的觀點,但他們並沒有回答 OP 問題的所有方面。

正確答案是:增加 k 的分數差異是由於選擇的度量 R2(決定系數)。 對於例如 MSE、MSLE 或 MAE,使用cross_val_scorecross_val_predict不會有任何區別。

參見R2定義

R^2 = 1 - (MSE(ground truth, prediction)/ MSE(ground truth, mean(ground truth) ))

粗體部分解釋了為什么隨着 k 的增加分數開始不同:我們擁有的分割越多,測試折疊中的樣本越少,測試折疊均值的方差越大。 相反,對於較小的 k,測試折疊的均值與完整的真實均值相差不大,因為樣本量仍然足夠大以具有較小的方差。

證明:

import numpy as np
from sklearn.metrics import mean_absolute_error as mae
from sklearn.metrics import mean_squared_log_error as msle, r2_score

predictions = np.random.rand(1000)*100
groundtruth = np.random.rand(1000)*20

def scores_for_increasing_k(score_func):
    skewed_score = score_func(groundtruth, predictions)
    print(f'skewed score (from cross_val_predict): {skewed_score}')
    for k in (2,4,5,10,20,50,100,200,250):
        fold_preds = np.split(predictions, k)
        fold_gtruth = np.split(groundtruth, k)
        correct_score = np.mean([score_func(g, p) for g,p in zip(fold_gtruth, fold_preds)])

        print(f'correct CV for k={k}: {correct_score}')

for name, score in [('MAE', mae), ('MSLE', msle), ('R2', r2_score)]:
    print(name)
    scores_for_increasing_k(score)
    print()

輸出將是:

MAE
skewed score (from cross_val_predict): 42.25333901481263
correct CV for k=2: 42.25333901481264
correct CV for k=4: 42.25333901481264
correct CV for k=5: 42.25333901481264
correct CV for k=10: 42.25333901481264
correct CV for k=20: 42.25333901481264
correct CV for k=50: 42.25333901481264
correct CV for k=100: 42.25333901481264
correct CV for k=200: 42.25333901481264
correct CV for k=250: 42.25333901481264

MSLE
skewed score (from cross_val_predict): 3.5252449697327175
correct CV for k=2: 3.525244969732718
correct CV for k=4: 3.525244969732718
correct CV for k=5: 3.525244969732718
correct CV for k=10: 3.525244969732718
correct CV for k=20: 3.525244969732718
correct CV for k=50: 3.5252449697327175
correct CV for k=100: 3.5252449697327175
correct CV for k=200: 3.5252449697327175
correct CV for k=250: 3.5252449697327175

R2
skewed score (from cross_val_predict): -74.5910282783694
correct CV for k=2: -74.63582817089443
correct CV for k=4: -74.73848598638291
correct CV for k=5: -75.06145142821893
correct CV for k=10: -75.38967601572112
correct CV for k=20: -77.20560102267272
correct CV for k=50: -81.28604960074824
correct CV for k=100: -95.1061197684949
correct CV for k=200: -144.90258384605787
correct CV for k=250: -210.13375041871123

當然,還有一個效果這里沒有展示,是別人提到的。 隨着 k 的增加,有更多的模型在更多樣本上訓練並在更少樣本上驗證,這會影響最終分數,但這不是由cross_val_scorecross_val_predict之間的選擇引起的。

我認為可以通過檢查它們的輸出來清楚區別。 考慮這個片段:

# Last column is the label
print(X.shape)  # (7040, 133)

clf = MLPClassifier()

scores = cross_val_score(clf, X[:,:-1], X[:,-1], cv=5)
print(scores.shape)  # (5,)

y_pred = cross_val_predict(clf, X[:,:-1], X[:,-1], cv=5)
print(y_pred.shape)  # (7040,)

注意形狀:為什么會這樣? scores.shape長度為 5,因為它是通過 5 次交叉驗證計算得出的分數(請參閱參數cv=5 )。 因此,每個折疊都會計算一個實際值。 該值是分類器的分數:

給定真實標簽和預測標簽,預測變量在特定折疊中有多少正確答案?

在這種情況下,輸入中給出的 y 標簽被使用兩次:從數據中學習和評估分類器的性能。

另一方面, y_pred.shape長度為 7040,這是數據集的形狀。 那是輸入數據集的長度。 這意味着每個值不是對多個值計算的分數,而是單個值:分類器的預測:

給定輸入數據及其標簽,分類器對特定折疊測試集中的特定示例的預測是什么?

請注意,您不知道使用了什么折疊:每個輸出都是根據某個折疊的測試數據計算的,但您無法分辨出哪個(至少從這個輸出中)。

在這種情況下,標簽只使用一次:用於訓練分類器。 您的工作是將這些輸出與真實輸出進行比較以計算分數。 如果你只是對它們求平均值,就像你所做的那樣,輸出不是一個分數,它只是平均預測。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM