(Серия ISLR на Python)
Эта статья является частью нашей серии ISLR, в которой мы постараемся охватить несколько примеров из упражнений из книги Введение в статистическое обучение и обсудить их подробно. Идеальной аудиторией для этих статей будет тот, кто начинает с регресса или хочет освежиться.
В этой статье в основном рассматривается использование диагностических графиков при анализе и улучшении моделей линейной регрессии.
Предположение. Читатель имеет базовые представления о Python и статистике.
Предложение: хотя само руководство является законченным, его можно лучше понять, прочитав вместе с Главой 3 ISLR → http://faculty.marshall.usc.edu/ Гарет-Джеймс
Ссылка на блокнот jupyter приведена в конце статьи.
Автоматический набор данных содержит информацию о 392 автомобилях. Наша цель будет заключаться в прогнозировании миль на галлон на основе лошадиных сил с использованием линейной регрессии и ее вариантов.
Файлы данных можно скачать с Git здесь.
Описание: Газовый пробег, лошадиные силы и другая информация для 392 автомобилей.
Использование: Авто - Автоматическая установка данных
Формат: фрейм данных с 392 наблюдениями по следующим 9 переменным.
- миль на галлон: миль на галлон.
- цилиндры: количество цилиндров от 4 до 8.
- объем: объем двигателя (куб. дюймы).
- лошадиные силы: мощность двигателя.
- вес: вес автомобиля (фунты).
- ускорение: время для разгона от 0 до 60 миль в час (сек.).
- год: модельный год (по модулю 100).
- origin: происхождение автомобиля (1. американское, 2. европейское, 3. японское).
- name: название автомобиля.
Исходные данные содержали 408 наблюдений, но 16 наблюдений с пропущенными значениями были удалены.
Источник-. Этот набор данных был взят из библиотеки StatLib, которая поддерживается в Университете Карнеги-Меллона. Набор данных использовался в Экспозиции Американской статистической ассоциации 1983 года.
Загрузка и очистка данных
Мы начинаем с загрузки данных в pandas DataFrame и анализа их с помощью функций .head () и .info ().
Использование головы для просмотра первых 5 строк набора данных.
auto_dataset = pd.read_csv(Auto.csv') auto_dataset.head()
auto_dataset.info()
Хотя значения мощности в первых пяти строках набора данных являются целыми числами, но типом данных для столбца является объект. Следовательно, мы принудительно преобразуем этот столбец в числовые значения, игнорируя любые значения, которые не могут быть преобразованы.
auto_dataset.horsepower = pd.to_numeric(auto_dataset.horsepower, errors='coerce') auto_dataset.info()
Теперь мы можем заметить, что столбец лошадиных сил представляет собой число с плавающей запятой с пятью пропущенными значениями, которые pandas не могут преобразовать.
Мы установим столбец name как индекс, а набор data_Set среза будет содержать только два интересующих столбца: mpg, и лошадиные силы для простоты использования.
required_df = auto_dataset[['mpg', 'horsepower']] required_df.describe()
Исследовательский анализ
Прежде чем непосредственно перейти к модели линейной регрессии, мы должны сначала построить график и наблюдать взаимосвязь между двумя переменными. Мы будем использовать regplot из библиотеки seaborn, что позволяет нам построить линию наилучшего соответствия на диаграмме рассеяния.
sns.regplot(x="horsepower", y="mpg", data=required_df, line_kws={'color':'red'}) plt.show()
Из приведенного выше графика видно, что линейная регрессия отражает суть отрицательной взаимосвязи между расходом топлива на галлон и мощностью в лошадиных силах. Однако есть некоторая выпуклость во взаимосвязи, которую линейная регрессия не может уловить. Мы обсудим это подробно при обсуждении диагностики на основе предположений линейной регрессии.
Основы линейной регрессии
В этом разделе мы кратко и интуитивно обсудим обычную регрессию методом наименьших квадратов, не углубляясь в математику.
OLS направлен на поиск наиболее подходящей линии, для которой сумма квадратов вертикального расстояния всех точек от линии минимальна.
Приведенное ниже уравнение показывает, как выглядят линейные отношения, и основные термины.
Линейная регрессия пытается предсказать указанное выше отношение, как показано ниже. В нашем уравнении линейной регрессии нет члена ошибки, поскольку этот член не моделируется. Линейная регрессия направлена на поиск объективных оценок параметров.
Примечание. Линия OLS всегда проходит через точку, обозначенную буквами X и Y.
Линейная регрессия в Python
Чтобы запустить линейную регрессию в Python, мы использовали пакет statsmodel. Когда у нас есть данные в DataFrame, требуется всего две строки кода для запуска и получения сводной информации о модели.
import statsmodels.formula.api as smf lin_model = smf.ols("mpg ~ horsepower", data=required_df).fit() lin_model.summary()
Сводка предоставляет исчерпывающую информацию о линейной регрессии. Отправной точкой является всегда смотреть на прогнозируемые параметры и их p-значение.
P-значения позволяют нам проверить значимость отдельных прогнозируемых параметров. P-значения почти равны нулю для обоих параметров, что говорит о том, что мы можем отклонить нулевую гипотезу о том, что либо параметр перехвата, либо параметр наклона равен нулю с высоким уровнем достоверности. В то же время Вероятность (F-статистика) проверяет значимость всей модели в целом. Опять же, близкое к нулю значение этой статистики предполагает, что мы можем отклонить нулевую гипотезу о том, что модель не фиксирует взаимосвязь между зависимыми и независимыми переменными с высоким доверительным интервалом.
Статистика R-квадрата показывает, какую дисперсию наша модель может уловить из общей дисперсии данных. Текущее значение предполагает, что мы можем уловить 60,5% общей дисперсии. Необъяснимая дисперсия может быть по двум причинам: 1) член ошибки - немоделируемая часть 2) Смещение модели - текущая модель слишком проста, чтобы уловить реальную взаимосвязь. В этом примере мы получаем значительный эффект от второго случая, поскольку мы пытаемся смоделировать выпуклые отношения с помощью линейной модели.
Последняя часть сводки под выделенным красным полем дает информацию об условиях ошибки. Тест Дарбина-Ватсона проверяет наличие автокорреляции, а тест Жарка-Бера - для проверки того, соответствуют ли члены ошибок нормальному распределению. Мы обсудим важность этого в следующем разделе.
Диагностические графики
Используя диагностические графики, мы проверяем, соответствует ли наша модель различным предположениям о линейной регрессии. Эти тесты предназначены для проверки правильности модели и предоставления информации о том, как улучшить модель, чтобы точно определить взаимосвязь между зависимыми и независимыми переменными.
Ниже приведен список предположений, которые мы будем проверять:
- Линейность: в остатках не должно быть никакой моделируемой информации.
- Эндогенность: остаток не должен быть связан с независимой переменной.
- Нормальность: остатки должны быть распределены нормально.
- Гомоскедастичность: разброс значений ошибок должен быть постоянным.
- Выбросы и высокое кредитное плечо. В наборе данных не должно быть сильной точки влияния, которая могла бы исказить нашу модель.
Для подробного понимания сделанных выше предположений обратитесь к теореме Гаусс-Марков.
Линейность. Остаточные значения не должны зависеть от прогнозируемых значений. На графике остаточных и подобранных значений не должно быть тенденции, а значения должны быть случайным образом распределены по оси абсцисс.
Любой узор на графике подразумевает некоторое количество моделируемой информации, не захваченной моделью.
В линейной модели уже вычислены как остаточные, так и аппроксимированные значения.
temp_data = pd.DataFrame(dict(fitted_values=lin_model.fittedvalues, residual=lin_model.resid)) graph = sns.lmplot(x='fitted_values', y='residual', data=temp_data, lowess=True, line_kws={'color':'red'}) plt.show()
Мы можем наблюдать выпуклый паттерн в остатке, который наша линейная модель не улавливает. Это согласуется с нашим первоначальным наблюдением, что соотношение между расходом топлива на галлон и мощностью в лошадиных силах имеет некоторую выпуклость.
Эндогенность. Эта проверка аналогична проверке на линейность. Это предполагает, что у нас не должно быть никакой связи между независимыми переменными (вместо подобранных значений) и остаточными членами.
temp_data = pd.DataFrame(dict(horsepower=required_df.horsepower, residual=lin_model.resid)) graph = sns.lmplot(x='horsepower', y='residual', data=temp_data, lowess=True, line_kws={'color':'red'}) plt.show()
Мы можем наблюдать такое же нарушение предположения, как линейность. Это означает, что предполагаемые параметры не могут быть объективной оценкой фактических параметров; следовательно, наша модель необъективна.
Нормальность. Допущение нормальности может привести к ошибкам в отношении точности модели, но оно сильно влияет на значения проверки гипотез. P-значения могут быть занижены или завышены, если остатки слишком сильно отклоняются от нормального распределения. Мы можем использовать QQ-Plot, чтобы проверить нормальность остатков.
sm.qqplot(lin_model.resid, dist=stats.t, fit=True, line='45', ax=ax[0]) sns.distplot(lin_model.get_influence().resid_studentized_internal) plt.show()
Остатки очень близки к нормальному распределению с небольшими отклонениями около хвоста. Левый хвост тоньше, чем у нормального распределения, а правый хвост немного толще, чем у нормального распределения.
Гомоскедастичность: если остаточные значения отражают гетероскедастичность, это означает, что линейная модель может дать больший вес нескольким точкам данных, чем другим точкам данных, при вычислении линии наилучшего соответствия.
Гетероскедастичность использует график «масштаб-расположение». Для гомоскедастичности линия тренда на этом графике должна быть горизонтальной.
Мы также можем наблюдать гетероскедастичность, глядя на остаточные графики выше. Опять же, воронкообразное распределение показывает гораздо больше отклонений в остатке вправо, чем в левой части графика.
qrt_std_residual = np.sqrt(np.abs(lin_model.get_influence().resid_studentized_internal)) temp_data = pd.DataFrame(dict(fitted_values=lin_model.fittedvalues, sqrt_std_residual=sqrt_std_residual)) graph = sns.lmplot(x='fitted_values', y='sqrt_std_residual', data=temp_data, lowess=True, line_kws={'color':'red'}) plt.show()
Линия тренда не плоская; следовательно, остатки по своей природе гетероскедастичны.
Выбросы и высокое кредитное плечо:. При линейной регрессии мы часто слишком много внимания уделяем выбросам. На самом деле точки с высоким кредитным плечом, которые также являются выбросами, намного опаснее, чем просто выбросы. Точки высокого кредитного плеча - это точки данных, которые находятся на крайнем значении независимых переменных (X).
Мы стремимся к тому, чтобы ни одна точка в наборе данных не оказала существенного влияния на нашу модель. Такие точки будут проблемой, если они являются исключительным случаем или неверны, поскольку это изменит модель в сторону от исходной взаимосвязи.
График влияния из модуля statsmodel.api или непосредственно при измерении расстояния Кука можно найти наиболее важные точки влияния.
sm.graphics.influence_plot(lin_model, alpha = 0.05, ax=ax, criterion="cooks") plt.show()
На приведенном выше графике ось Y представляет выбросы с точки зрения стандартного отклонения. Обычно считается, что точки ниже или выше трех стандартных отклонений являются выбросами. Ось X определяет горизонтальное плечо каждой точки, а размер пузыря - это влияние каждой точки на модель на основе меры Кука.
Эмпирическое правило состоит в том, что точки данных с расстоянием Кука больше 4 / (количество точек данных) являются точками данных, вызывающими озабоченность.
cooks_threshold = 4/len(X.index) df = influence_summary[influence_summary.cooks_d>cooks_threshold][['cooks_d']] df.style.bar(subset=['cooks_d'], color='Red')
Мы должны посмотреть на все эти точки данных, чтобы решить, верны ли они и должны ли они быть частью нашей модели или нет. Еще одна часто используемая матрица для поиска точек влияния - DFFITS.
Таким образом, мы рассмотрели все диагностические графики и наблюдали, как наша текущая модель не работает, исходя из предположений о линейной регрессии. В следующем разделе мы кратко рассмотрим, как можно интуитивно решить эти проблемы, чтобы уловить взаимосвязь между миль на галлон и лошадиными силами лучше.
Решение проблем с помощью диагностических графиков
Чтобы зафиксировать выпуклую взаимосвязь, которую мы наблюдали в невязках и подобранном графике, мы можем добавить полином второй степени и проверить, отражает ли он выпуклую взаимосвязь.
quad_model = smf.ols("mpg ~ horsepower + np.square(horsepower)", data=auto_dataset[['mpg','horsepower']].reset_index()).fit() quad_model.summary()
Из сводной статистики видно, что p-значение для квадратного члена близко к нулю, и, следовательно, его значимость. Мы также можем видеть, что точность нашей модели увеличилась, поскольку член R-квадрат теперь составляет ~ 68%, что на 8% выше, чем раньше.
Мы можем наблюдать, что линия тренда стала ближе к горизонтали. Однако мы все еще видим воронкообразную структуру в остатках с высокой дисперсией к правому концу, что указывает на наличие гетероскедастичности.
Чтобы разрешить сценарий, когда воронка открывается с правой стороны, мы можем преобразовать зависимую переменную с помощью вогнутой функции. Если воронка открывается слева, мы пытаемся преобразовать зависимую переменную с помощью выпуклой функции.
В текущем сценарии нам нужно преобразование вогнутой формы, и лучше всего начать с преобразования журнала.
log_quad_model = smf.ols("np.log(mpg) ~ horsepower + np.square(horsepower)", data=auto_dataset[['mpg','horsepower']].reset_index()).fit() log_quad_model.summary()
Приведенная выше сводная статистика регрессии показывает, что преобразование зависимой переменной увеличивает точность модели на ~ 4,5%.
Мы проигнорировали все точки влияния, превышающие пороговое значение для дистанции Кука, для простоты нашего обсуждения.
cooks_distance = influence_summary[influence_summary.cooks_d>4/len(X.index)][['cooks_d']] auto_dataset_removed_outliers = auto_dataset.drop(cooks_distance.index) log_quad_model = smf.ols("np.log(mpg) ~ horsepower + np.square(horsepower)", data=auto_dataset_removed_outliers[['mpg','horsepower']].reset_index()).fit() log_quad_model.summary()
После удаления важных точек точность модели увеличивается на ~ 4%, как показывает R-квадрат.
Диагностические графики на окончательной модели
Из приведенных выше диагностических графиков видно, что наша окончательная модель решает все проблемы с допущениями о линейной регрессии. В процессе решения этих проблем мы также изменили соотношение между миль на галлон и лошадиными силами.
ПРЕДЛАГАЕМАЯ НАЧАЛЬНАЯ МОДЕЛЬ
КОНЕЧНАЯ ПРОИЗВОДНАЯ МОДЕЛЬ
Заключительное примечание
В этой статье я попытался коснуться поверхности линейной регрессии. Однако линейная регрессия по-прежнему остается самым мощным инструментом, используемым в аналитике. Итак, прежде чем переходить к более модной модели, обязательно погрузитесь в линейную регрессию. Замечено, что следование структурированному подходу при анализе результата линейной регрессии может помочь выявить гораздо более сложные взаимосвязи, как показано выше.
Прокомментируйте или свяжитесь со мной в случае обратной связи или каких-либо конкретных тем, которые вы хотели бы, чтобы я затронул в следующих статьях.
Спасибо, что нашли время, чтобы прочитать эту статью, и удачного обучения.
- * Особая благодарность Нимешане за помощь в написании различных частей этой статьи. **
Ссылка на блокнот Jupyter: https://github.com/quantsbin/ISLRpybin/tree/main/islrpybin/notebooks/chapter3