Xác thực chéo lồng nhau và chọn mô hình hồi quy tốt nhất - đây có phải là quy trình SKLearn đúng không?


8

Nếu tôi hiểu chính xác, lồng nhau-CV có thể giúp tôi đánh giá mô hình và quy trình điều chỉnh siêu tham số nào là tốt nhất. Vòng lặp bên trong ( GridSearchCV) tìm ra các siêu đường kính tốt nhất và vòng lặp outter ( cross_val_score) đánh giá thuật toán điều chỉnh siêu tham số. Sau đó, tôi chọn kết hợp điều chỉnh / mô hình nào từ vòng lặp bên ngoài để giảm thiểu mse(tôi đang xem phân loại hồi quy) cho thử nghiệm mô hình cuối cùng của mình.

Tôi đã đọc các câu hỏi / câu trả lời về xác thực chéo lồng nhau, nhưng chưa thấy một ví dụ nào về một đường ống dẫn đầy đủ sử dụng điều này. Vì vậy, mã của tôi dưới đây (xin vui lòng bỏ qua các phạm vi siêu tham số thực tế - đây chỉ là ví dụ) và quá trình suy nghĩ có ý nghĩa?

from sklearn.cross_validation import cross_val_score, train_test_split
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import mean_squared_error
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
from sklearn.datasets import make_regression

# create some regression data
X, y = make_regression(n_samples=1000, n_features=10)
params = [{'C':[0.01,0.05,0.1,1]},{'n_estimators':[10,100,1000]}]

# setup models, variables
mean_score = []
models = [SVR(), RandomForestRegressor()]

# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.3)

# estimate performance of hyperparameter tuning and model algorithm pipeline
for idx, model in enumerate(models):
    clf = GridSearchCV(model, params[idx], scoring='mean_squared_error')

    # this performs a nested CV in SKLearn
    score = cross_val_score(clf, X_train, y_train, scoring='mean_squared_error')

    # get the mean MSE across each fold
    mean_score.append(np.mean(score))
    print('Model:', model, 'MSE:', mean_score[-1])

# estimate generalization performance of the best model selection technique
best_idx = mean_score.index(max(mean_score)) # because SKLearn flips MSE signs, max works OK here
best_model = models[best_idx]

clf_final = GridSearchCV(best_model, params[best_idx])
clf_final.fit(X_train, y_train)

y_pred = clf_final.predict(X_test)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))

print('Final Model': best_model, 'Final model RMSE:', rmse)

Câu trả lời:


8

Của bạn không phải là một ví dụ về xác nhận chéo lồng nhau.

Xác thực chéo lồng nhau rất hữu ích để tìm hiểu xem, một khu rừng ngẫu nhiên hoặc một SVM phù hợp hơn cho vấn đề của bạn. CV lồng nhau chỉ xuất ra một số điểm, nó không xuất ra một mô hình như trong mã của bạn.

Đây sẽ là một ví dụ về xác nhận chéo lồng nhau:

from sklearn.datasets import load_boston
from sklearn.cross_validation import KFold
from sklearn.metrics import mean_squared_error
from sklearn.grid_search import GridSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
import numpy as np

params = [{'C': [0.01, 0.05, 0.1, 1]}, {'n_estimators': [10, 100, 1000]}]
models = [SVR(), RandomForestRegressor()]

df = load_boston()
X = df['data']
y = df['target']

cv = [[] for _ in range(len(models))]
for tr, ts in KFold(len(X)):
    for i, (model, param) in enumerate(zip(models, params)):
        best_m = GridSearchCV(model, param)
        best_m.fit(X[tr], y[tr])
        s = mean_squared_error(y[ts], best_m.predict(X[ts]))
        cv[i].append(s)
print(np.mean(cv, 1))

Nhân tiện, một vài suy nghĩ:

  • Tôi thấy không có mục đích tìm kiếm lưới cho n_estimatorskhu rừng ngẫu nhiên của bạn. Rõ ràng, càng nhiều, càng tốt. Những thứ như max_depthlà loại chính quy mà bạn muốn tối ưu hóa. Lỗi cho CV lồng nhau RandomForestcao hơn nhiều do bạn không tối ưu hóa cho các siêu đường kính phù hợp, không nhất thiết vì đó là một mô hình tồi tệ hơn.
  • Bạn cũng có thể muốn thử cây tăng cường độ dốc.

Cảm ơn vì điều đó. Mục tiêu của tôi là làm chính xác những gì bạn nói - tìm ra thuật toán phân loại nào sẽ phù hợp nhất cho vấn đề của tôi. Tôi đoán rằng tôi đã nhầm lẫn về các tài liệu của SKLearn: scikit-learn.org/urdy/tutorial/statistic_inference/ Kẻ (dưới 'xác thực chéo')
BobbyJohnsonOG

Để kiểm tra hiệu suất của mô hình được chọn tốt nhất, tôi có thực hiện xác thực chéo cuối cùng trên toàn bộ tập dữ liệu không? Hoặc tôi nên chia dữ liệu của mình thành tàu / kiểm tra TRƯỚC CV lồng nhau, chạy CV lồng nhau trên tàu và sau đó phù hợp với mô hình tốt nhất trên dữ liệu tàu và kiểm tra thử nghiệm?
BobbyJohnsonOG

Xin lỗi vì những lời bình luận. Vì vậy, mô hình cuối cùng của tôi sẽ là:best_idx = np.where(np.mean(cv,1).min())[0]; final_m = GridSearchCV(models[best_idx], params[best_idx]); final_m.fit(X,y)
BobbyJohnsonOG

Xây dựng những gì bạn nói, đây là những gì tôi sẽ làm với các chức năng SKLearn tích hợp (cung cấp giống như câu trả lời của bạn):for model, param in zip(models, params): clf = GridSearchCV(model, param) my_score = cross_val_score(clf, X, y, scoring='mean_squared_error') my_scores.append(my_score)
BobbyJohnsonOG

7

Xác thực chéo lồng nhau ước tính lỗi tổng quát hóa của một mô hình, vì vậy đây là một cách tốt để chọn mô hình tốt nhất từ ​​danh sách các mô hình ứng cử viên và lưới tham số liên quan của chúng. Bài đăng gốc gần giống với thực hiện CV lồng nhau: thay vì thực hiện phân tách kiểm tra Train train đơn, thay vào đó, người ta nên sử dụng bộ chia xác thực chéo thứ hai. Đó là, một "tổ" một bộ tách xác thực chéo "bên trong" bên trong bộ chia xác thực chéo "bên ngoài".

Bộ chia xác thực chéo bên trong được sử dụng để chọn siêu đường kính. Bộ chia xác thực chéo bên ngoài tính trung bình lỗi kiểm tra trên nhiều lần phân tách kiểm tra của Train. Tính trung bình lỗi tổng quát hóa trên nhiều phân tách kiểm tra đào tạo cung cấp ước tính đáng tin cậy hơn về độ chính xác của mô hình trên dữ liệu chưa xem.

Tôi đã sửa đổi mã của bài đăng gốc để cập nhật nó lên phiên bản mới nhất sklearn(được sklearn.cross_validationthay thế bởi sklearn.model_selectionvà được 'mean_squared_error'thay thế bởi 'neg_mean_squared_error') và tôi đã sử dụng hai KFoldbộ tách xác thực chéo để chọn mô hình tốt nhất. Để tìm hiểu thêm về kiểm chứng chéo lồng nhau, xem sklearn's ví dụ về lồng nhau qua xác nhận .

from sklearn.model_selection import KFold, cross_val_score, GridSearchCV
from sklearn.datasets import make_regression
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
import numpy as np

# `outer_cv` creates 3 folds for estimating generalization error
outer_cv = KFold(3)

# when we train on a certain fold, we use a second cross-validation
# split in order to choose hyperparameters
inner_cv = KFold(3)

# create some regression data
X, y = make_regression(n_samples=1000, n_features=10)

# give shorthand names to models and use those as dictionary keys mapping
# to models and parameter grids for that model
models_and_parameters = {
    'svr': (SVR(),
            {'C': [0.01, 0.05, 0.1, 1]}),
    'rf': (RandomForestRegressor(),
           {'max_depth': [5, 10, 50, 100, 200, 500]})}

# we will collect the average of the scores on the 3 outer folds in this dictionary
# with keys given by the names of the models in `models_and_parameters`
average_scores_across_outer_folds_for_each_model = dict()

# find the model with the best generalization error
for name, (model, params) in models_and_parameters.items():
    # this object is a regressor that also happens to choose
    # its hyperparameters automatically using `inner_cv`
    regressor_that_optimizes_its_hyperparams = GridSearchCV(
        estimator=model, param_grid=params,
        cv=inner_cv, scoring='neg_mean_squared_error')

    # estimate generalization error on the 3-fold splits of the data
    scores_across_outer_folds = cross_val_score(
        regressor_that_optimizes_its_hyperparams,
        X, y, cv=outer_cv, scoring='neg_mean_squared_error')

    # get the mean MSE across each of outer_cv's 3 folds
    average_scores_across_outer_folds_for_each_model[name] = np.mean(scores_across_outer_folds)
    error_summary = 'Model: {name}\nMSE in the 3 outer folds: {scores}.\nAverage error: {avg}'
    print(error_summary.format(
        name=name, scores=scores_across_outer_folds,
        avg=np.mean(scores_across_outer_folds)))
    print()

print('Average score across the outer folds: ',
      average_scores_across_outer_folds_for_each_model)

many_stars = '\n' + '*' * 100 + '\n'
print(many_stars + 'Now we choose the best model and refit on the whole dataset' + many_stars)

best_model_name, best_model_avg_score = max(
    average_scores_across_outer_folds_for_each_model.items(),
    key=(lambda name_averagescore: name_averagescore[1]))

# get the best model and its associated parameter grid
best_model, best_model_params = models_and_parameters[best_model_name]

# now we refit this best model on the whole dataset so that we can start
# making predictions on other data, and now we have a reliable estimate of
# this model's generalization error and we are confident this is the best model
# among the ones we have tried
final_regressor = GridSearchCV(best_model, best_model_params, cv=inner_cv)
final_regressor.fit(X, y)

print('Best model: \n\t{}'.format(best_model), end='\n\n')
print('Estimation of its generalization error (negative mean squared error):\n\t{}'.format(
    best_model_avg_score), end='\n\n')
print('Best parameter choice for this model: \n\t{params}'
      '\n(according to cross-validation `{cv}` on the whole dataset).'.format(
      params=final_regressor.best_params_, cv=inner_cv))

Ở bình luận cuối cùng, bạn nói rằng bạn "... hoàn thiện mô hình tốt nhất này trên toàn bộ tập huấn luyện" nhưng bạn thực sự làm điều đó trên toàn bộ tập dữ liệu ( Xy). Theo tôi hiểu đây là điều đúng đắn, nhưng sau đó bình luận phải được sửa chữa. Bạn nghĩ sao?
Dror Atariah

Cảm ơn @DrorAtariah vì đã nắm bắt được điều đó. Bạn đúng. Tôi sửa nó rồi.
Charlie Brummitt

1

Bạn không cần

# this performs a nested CV in SKLearn
score = cross_val_score(clf, X_train, y_train, scoring='mean_squared_error')

GridSearchCVlàm điều này cho bạn. Để có được trực giác của quá trình tìm kiếm lưới, hãy thử sử dụng GridSearchCV(... , verbose=3)

Để trích xuất điểm cho mỗi lần, hãy xem ví dụ này trong tài liệu tìm hiểu scikit


Tôi nghĩ tìm kiếm lưới chỉ để tối ưu hóa các tham số siêu? Làm thế nào tôi có thể sử dụng gridsearch kết hợp với một cái gì đó khác để tìm ra thuật toán phân loại tốt nhất (ví dụ SVR so với RandomForest)?
BobbyJohnsonOG

Đúng. Đối với mỗi kết hợp siêu tham số, GridSearchCV sẽ tạo các nếp gấp và tính toán điểm số (có nghĩa là lỗi bình phương trong trường hợp của bạn) trên dữ liệu bên trái. Do đó, mỗi tổ hợp siêu tham số có điểm trung bình riêng. "Tối ưu hóa" chỉ là chọn kết hợp với điểm trung bình tốt nhất. Bạn có thể trích xuất các điểm trung bình đó và so sánh chúng trực tiếp cho các mô hình khác nhau.
lanenok
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.