Сборка конвейера sklearn + вложенная перекрестная проверка для регрессии KNN

Я пытаюсь понять, как создать рабочий процесс для sklearn.neighbors.KNeighborsRegressor, который включает:

  • нормализовать особенности
  • выбор функций (лучшее подмножество из 20 числовых функций, без конкретного итога)
  • перекрестная проверка гиперпараметра K в диапазоне от 1 до 20
  • перекрестная проверка модели
  • использует RMSE в качестве метрики ошибок

В scikit-learn так много разных вариантов, что я немного ошеломлен, пытаясь решить, какие классы мне нужны.

Кроме sklearn.neighbors.KNeighborsRegressor, мне, кажется, нужно:

sklearn.pipeline.Pipeline  
sklearn.preprocessing.Normalizer
sklearn.model_selection.GridSearchCV
sklearn.model_selection.cross_val_score

sklearn.feature_selection.selectKBest
OR
sklearn.feature_selection.SelectFromModel

Не могли бы вы показать мне, как может выглядеть определение этого конвейера / рабочего процесса? Думаю должно быть примерно так:

import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import Normalizer
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.neighbors import KNeighborsRegressor
from sklearn.model_selection import cross_val_score, GridSearchCV

# build regression pipeline
pipeline = Pipeline([('normalize', Normalizer()),
                     ('kbest', SelectKBest(f_classif)),
                     ('regressor', KNeighborsRegressor())])

# try knn__n_neighbors from 1 to 20, and feature count from 1 to len(features)
parameters = {'kbest__k':  list(range(1, X.shape[1]+1)),
              'regressor__n_neighbors': list(range(1,21))}

# outer cross-validation on model, inner cross-validation on hyperparameters
scores = cross_val_score(GridSearchCV(pipeline, parameters, scoring="neg_mean_squared_error", cv=10), 
                         X, y, cv=10, scoring="neg_mean_squared_error", verbose=2)

rmses = np.abs(scores)**(1/2)
avg_rmse = np.mean(rmses)
print(avg_rmse)

Это не похоже на ошибку, но некоторые из моих проблем:

  • Правильно ли я выполнил вложенную перекрестную проверку, чтобы моя RMSE была беспристрастной?
  • Если я хочу, чтобы окончательная модель была выбрана в соответствии с наилучшей среднеквадратичной среднеквадратической среднеквадратической среднеквадратической среднеквадратической среднеквадратической ошибки, должен ли я использовать scoring="neg_mean_squared_error" как для cross_val_score, так и для GridSearchCV?
  • Является ли SelectKBest, f_classif лучшим вариантом для выбора функций для модели KNeighborsRegressor?
  • How can I see:
    • which subset of features was selected as best
    • который K был выбран как лучший

Любая помощь приветствуется!


person Austin    schedule 17.07.2017    source источник
comment
Кажется, ваш код в порядке. Также подход ко мне правильный. Получаете ли вы какую-нибудь ошибку или неожиданный результат?   -  person seralouk    schedule 17.07.2017
comment
Привет, спасибо за ваш комментарий. Я обновил свой пост, добавив немного дополнительной информации о том, что меня беспокоит.   -  person Austin    schedule 17.07.2017


Ответы (1)


Ваш код в порядке.

Что касается scoring="neg_mean_squared_error" для cross_val_score и GridSearchCV, я бы сделал то же самое, чтобы убедиться, что все работает нормально, но единственный способ проверить это - удалить один из двух и посмотреть, изменятся ли результаты.

SelectKBest - хороший подход, но вы также можете использовать SelectFromModel или даже другие методы, которые вы можете найти здесь < / а>

Наконец, чтобы получить лучшие параметры и оценки функций, я немного изменил ваш код следующим образом:

import ...


pipeline = Pipeline([('normalize', Normalizer()),
                     ('kbest', SelectKBest(f_classif)),
                     ('regressor', KNeighborsRegressor())])

# try knn__n_neighbors from 1 to 20, and feature count from 1 to len(features)
parameters = {'kbest__k':  list(range(1, X.shape[1]+1)),
              'regressor__n_neighbors': list(range(1,21))}

# changes here

grid = GridSearchCV(pipeline, parameters, cv=10, scoring="neg_mean_squared_error")

grid.fit(X, y)

# get the best parameters and the best estimator
print("the best estimator is \n {} ".format(grid.best_estimator_))
print("the best parameters are \n {}".format(grid.best_params_))

# get the features scores rounded in 2 decimals
pip_steps = grid.best_estimator_.named_steps['kbest']

features_scores = ['%.2f' % elem for elem in pip_steps.scores_ ]
print("the features scores are \n {}".format(features_scores))

feature_scores_pvalues = ['%.3f' % elem for elem in pip_steps.pvalues_]
print("the feature_pvalues is \n {} ".format(feature_scores_pvalues))

# create a tuple of feature names, scores and pvalues, name it "features_selected_tuple"

featurelist = ['age', 'weight']

features_selected_tuple=[(featurelist[i], features_scores[i], 
feature_scores_pvalues[i]) for i in pip_steps.get_support(indices=True)]

# Sort the tuple by score, in reverse order

features_selected_tuple = sorted(features_selected_tuple, key=lambda 
feature: float(feature[1]) , reverse=True)

# Print
print 'Selected Features, Scores, P-Values'
print features_selected_tuple

Результаты с использованием моих данных:

the best estimator is
Pipeline(steps=[('normalize', Normalizer(copy=True, norm='l2')), ('kbest', SelectKBest(k=2, score_func=<function f_classif at 0x0000000004ABC898>)), ('regressor', KNeighborsRegressor(algorithm='auto', leaf_size=30, metric='minkowski',
         metric_params=None, n_jobs=1, n_neighbors=18, p=2,
         weights='uniform'))])

the best parameters are
{'kbest__k': 2, 'regressor__n_neighbors': 18}

the features scores are
['8.98', '8.80']

the feature_pvalues is
['0.000', '0.000']

Selected Features, Scores, P-Values
[('correlation', '8.98', '0.000'), ('gene', '8.80', '0.000')]
person seralouk    schedule 17.07.2017
comment
Спасибо! Я вижу, что он показывает количество параметров, используемых для kbest__k, но есть ли способ узнать, какие столбцы использовались конкретно? SelectKBest пробует ли только первый столбец, затем первый и второй и т. Д., Или пробует каждую перестановку # функций в выбранном диапазоне? - person Austin; 17.07.2017
comment
@Jake Я отредактировал свой пост. Я добавил код для значений p и оценок функций. Я думаю, что это основано на перестановках, как вы сказали в своем комментарии - person seralouk; 17.07.2017
comment
@Jake Второе обновление моего ответа. теперь вы можете получить выбранные функции - person seralouk; 17.07.2017
comment
Спасибо, очень признателен! - person Austin; 17.07.2017
comment
@ Джейк рад, что я смог помочь - person seralouk; 17.07.2017
comment
Извините за этот поздний комментарий, но не могли бы вы объяснить, где он / она выполнил этап вложенной перекрестной проверки? Я не вижу этого в коде. Спасибо. - person Yan; 08.01.2020