Линейная регрессия: хорошие результаты для обучающих данных, ужасные для тестовых данных.

Я работаю с набором данных размером около 400 000 x 250. У меня проблема с моделью, которая дает очень хороший результат R ^ 2 при тестировании на обучающем наборе, но очень плохо при использовании на тестовом наборе. Поначалу это звучит как переоснащение. Но данные разбиваются на набор для обучения / тестирования случайным образом, а набор данных довольно большой, поэтому я чувствую, что должно быть что-то еще. Какие-либо предложения?

Разделение набора данных на обучающий набор и тестовый набор

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df.drop(['SalePrice'], 
axis=1), df.SalePrice, test_size = 0.3)

Оценщик линейной регрессии Склерна

from sklearn import linear_model
linReg = linear_model.LinearRegression()    # Create linear regression object
linReg.fit(X_train, y_train)                # Train the model using the training sets

# Predict from training set
y_train_linreg = linReg.predict(X_train)

# Predict from test set
y_pred_linreg = linReg.predict(X_test)

Расчет метрики

from sklearn import metrics
metrics.r2_score(y_train, y_train_linreg)
metrics.r2_score(y_test, y_pred_linreg)

Оценка R ^ 2 при тестировании на обучающей выборке: 0,64

Оценка R ^ 2 при тестировании на тестовой выборке: -10 ^ 23 (приблизительно)


person ViggoTW    schedule 11.06.2018    source источник
comment
Вы пытались применить какой-либо метод преобразования / предварительной обработки функций? например MinMaxScaler, а затем использовать перекрестную проверку для оценки производительности?   -  person Vivek Kumar    schedule 11.06.2018
comment
Это очень четкое и исчерпывающее руководство. Два дополнения 1) в пункте 3 Я бы также добавил масштабирование функций до нулевого среднего и единичной дисперсии (используя либо StandardScaler или RobustScaler. На линейные модели влияет разница в масштабе, если я правильно помню. 2) В последнем пункте я бы порекомендовал LightGBM / CatBoost или XGBoost вместо реализации sklean GBM, поскольку они есть намного быстрее   -  person seralouk    schedule 11.06.2018


Ответы (1)


Хотя я согласен с Михаем в том, что ваша проблема определенно выглядит как переоснащение, я не обязательно согласен с его ответом, что нейронная сеть решит вашу проблему; по крайней мере, не из коробки. Сами по себе нейронные сети переоснащаются больше, чем линейные модели. Вам нужно как-то позаботиться о своих данных, вряд ли какая-либо модель может сделать это за вас. Несколько вариантов, которые вы могли бы рассмотреть (извините, я не могу быть более точным, не глядя на набор данных):

  • Проще всего использовать регуляризацию. 400 тысяч строк - это много, но с 250 размерами вы можете переоборудовать практически все, что захотите. Поэтому попробуйте заменить LinearRegression на Ridge или Lasso (или Elastic Net или что-то еще). См. http://scikit-learn.org/stable/modules/linear_model.html (Преимущество лассо состоит в том, что вы отбрасываете особенности, см. следующий пункт)
  • Особенно, если вы хотите выйти за рамки линейных моделей (а вам, вероятно, следует), рекомендуется сначала уменьшить размер проблемы, поскольку я сказал, что 250 - это много. Попробуйте использовать некоторые методы выбора функций здесь: http://scikit-learn.org/stable/modules/feature_selection.html
  • Вероятно, самое главное, вы должны подумать об адаптации ваших входных данных. Самое первое, что я попробую, - это, если вы действительно пытаетесь предсказать цену, как предполагает ваш код, заменить ее логарифмом или log (1 + x). В противном случае линейная регрессия будет очень стараться уместить этот единственный объект, который был продан за 1 миллион долларов, игнорируя все, что ниже 1 тысячи долларов. Не менее важно проверить, есть ли у вас какие-либо нечисловые (категориальные) столбцы, и сохраняйте их только в том случае, если они вам нужны, на случай сокращения их до макрокатегорий: категориальный столбец с 1000 возможных значений увеличит размер вашей проблемы на 1000, что сделает это гарантированный переоснащение. Один столбец с уникальными категориальными данными для каждого входа (например, имя покупателя) приведет вас прямо к идеальной подгонке.
  • Вы пробовали перекрестную проверку (с использованием разных частей данных для обучения и тестирования несколько раз). Возможно, текущее распределение данных в обучении и тестировании не позволяет модели узнавать о данных в тесте (потому что подобных данных в обучении нет).
person Marco Spinaci    schedule 11.06.2018
comment
@MykhailoLisovyi большое спасибо за добавление деталей к моему ответу, действительно, упущение упоминания данных центрирования и масштабирования было большим упущением с моей стороны, так как они очень нужны! Также спасибо, что указали на лучшие реализации повышения, поскольку я знал только о XGBoost, эта часть ответа будет мне полезна :-) - person Mischa Lisovyi; 11.06.2018
comment
Для справки, есть несколько тестов, которые показывают, что на CPU LightGBM и CatBoost превосходят XGBoost (есть тесты, по которым XGBoost все еще быстрее на GPU, чем LightGBM, по крайней мере, но я не обучаю их на GPU, поэтому я не могу поделитесь личным опытом). И все три намного быстрее, чем реализация sklearn. Так что поиграться с этими пакетами очень полезно. - person Marco Spinaci; 11.06.2018
comment
Спасибо за подробный ответ. Я уже сделал масштабирование переменных функций. Однако переход на Ridge дал гораздо лучший результат, почти без разницы между данными обучения и данными теста :) - person Mischa Lisovyi; 11.06.2018
comment
После всего этого (очистка данных, уменьшение размерности одним из описанных выше методов или просто регрессией Лассо до тех пор, пока вы точно не доберетесь до значения менее 100, возможно, менее 20 - и помните, что это включает в себя любые категориальные данные!), Вам следует подумать об отсутствии -линейные методы для дальнейшего улучшения ваших результатов - но это бесполезно, пока ваша линейная модель не предоставит вам хотя бы некоторое умеренно положительное значение R ^ 2 на тестовых данных. sklearn предоставляет их множество: http://scikit-learn.org/stable/modules/kernel_ridge.html проще всего использовать в готовом виде (также выполняет регуляризацию), но он может быть слишком медленным для использования в вашем случае (сначала вы должны попробовать это и любое из следующих действий: на подмножестве ваших данных, скажем, 1000 строк, если вы выбрали только 10 или 20 функций и посмотрите, насколько это медленно). http://scikit-learn.org/stable/modules/svm.html#regression имеет много разных вариантов, но я думаю, что все, кроме линейной, будут слишком медленными. Придерживаясь линейных элементов, http://scikit-learn.org/stable/modules/sgd.html#regression, вероятно, самый быстрый, и именно так я бы обучил линейную модель на таком большом количестве образцов. Если действительно выйти за рамки линейности, самые простые методы, вероятно, будут включать какие-то деревья, либо напрямую http://scikit-learn.org/stable/modules/tree.html#regression (но это почти наверняка переоснащение) или, что лучше, с использованием какой-либо техники ансамбля (случайные леса http://scikit-learn.org/stable/modules/ensemble.html#forests-of-randomized-trees - это типичный алгоритм повышения градиента http://scikit-learn.org/stable/modules/ensemble.html#gradient-tree-boosting иногда работает лучше). Наконец, современные результаты действительно обычно получают с помощью нейронных сетей, см., Например, http://scikit-learn.org/stable/modules/neural_networks_supervised.html но для этих методов sklearn, как правило, не правильный ответ, и вам следует взглянуть на выделенные среды (TensorFlow, Caffe, PyTorch и т. д.) ) ... однако, если вы не знакомы с ними, это, конечно, не стоит усилий! - person ViggoTW; 11.06.2018