Линейная регрессия, предположения и другие концепции

Линейная регрессия обычно рассматривается как линейный подход к моделированию отношений между двумя переменными, одна из которых независима, а другая зависима. Чаще всего при измерении взаимосвязи более чем одной переменной это называется множественной регрессией.

Когда дело доходит до науки о данных, линейная регрессия является одним из самых основных статистических методов для изучения.

Самый простой способ написать линейное уравнение:

𝛽0 — точка пересечения с осью Y, где 𝛽1 обозначает наклон линии. X - количество единиц, перемещенных по оси.

Эта формула суммирует линейную зависимость. Это может быть расширено или изменено на более «сложные» модели для лучшей подгонки. Эти модели включают квадратные уравнения или полиномиальные функции. Как специалист по данным, вы узнаете об этом вскоре после того, как линейная регрессия будет побеждена.

В контексте статистического обучения два типа данных, представленных здесь и далее, являются независимыми и зависимыми переменными.

Независимые переменные — это данные, которыми нельзя управлять. Независимыми переменными обычно являются переменные-предикторы, независимые переменные, признаки или входные переменные.

Зависимые переменные — это данные, которыми можно управлять напрямую, отсюда и взаимосвязь. Зависимые переменные обычно представляют собой «Y», переменные результата, целевые переменные или переменные отклика.

Независимые переменные приводят к изменению зависимой переменной (переменных).

Линейная регрессия — это статистическая модель, в которой ее можно рассматривать как способ, с помощью которого преобразование может помочь выразить прогноз или переменные результата. (зависимые переменные).

Чтобы создать модель линейной регрессии, она должна удовлетворять «допущению регрессии методом наименьших квадратов». Поскольку регрессионные модели учатся на своих параметрах, необходимо сделать определенные предположения. Они составляют объем регрессионного анализа и ДОЛЖНЫ быть соблюдены для создания регрессионной модели. Три предположения: линейность, нормальность и гомоскедастичность.

  1. Линейность. Он должен показывать линейную зависимость между переменной ответа и переменной результата. Термин «линейный» в этом контексте будет относиться к постоянному изменению Y на n-единичное изменение X.

Допущение о линейности важно, особенно при выполнении обычного сводного отчета по методу наименьших квадратов (OLS). (Эта концепция будет объяснена ниже).

Если нет линейной зависимости, то МНК не сможет отобразить какой-либо математический тренд.

Глядя на изображение, гораздо проще определить, есть ли выбросы. Это дополнительная мера, которую следует принимать всегда. Выбросы могут иметь огромное влияние на регрессионную модель.

2. Нормальность. Предположение о нормальности — это предположение, которое показывает, что остатки в модели следуют стандартному нормальному распределению. Предположение о нормальности является необходимым допущением.

Самый простой способ проверить предположение о нормальности — это использовать гистограммы. Ниже я кратко расскажу о графиках Q-Q, которые используются для проверки этого.

3. Гомоскедастичность. Не просто громкое слово, а способ показать, что зависимая изменчивость одинакова для независимых переменных. Это третье допущение, необходимое для построения модели линейной регрессии. Ниже важно видеть, что все точки «имеют одинаковый разброс». Здесь мы смотрим не на линию наилучшего соответствия, а на тренд точек данных и на то, как они находятся примерно на одинаковом расстоянии от линии.

В дополнение к допущениям, которые должны быть соблюдены, в линейной регрессии введено несколько концепций, которые чрезвычайно важны для практики и использования в качестве основы для более сложных моделей. Такими понятиями являются:

Коэффициент детерминации. R-квадрат, также известный как коэффициент детерминации, – это показатель, который используется для оценки точности соответствия в регрессионной модели. Это важно при оценке модели, потому что помогает уменьшить любую предвзятость. Прямая линия не описывает полностью отношения между своими переменными.

Базовая модель R-squared проста, но эффективна. Базовая модель прогнозирует значения на основе среднего значения наблюдаемых ответов на зависимые переменные вместо использования независимых переменных.

R-квадрат измеряется с точки зрения квадратов ошибок для линейной регрессии, а затем подгоняется для базовой модели.

Формула:

Где SS_RES — остаточная сумма квадратов ошибок. Это квадрат разницы между y и y (прогнозируемое значение y).

SS_TOT — это общая сумма квадратов ошибок. Это квадрат разницы между y и y bar (выборка y).

По сути, r-квадрат получается как «1 — доля дисперсии, не объясняемая моделью». Это означает, что мы хотим максимизировать показатель r-квадрата. Худшее значение равно 0.

Значения R-квадрата находятся в диапазоне от 0 до 1. Значения, близкие к 0, представляют плохое соответствие, а значения, близкие к 1, представляют «идеальное» соответствие.

Обычные наименьшие квадраты. Обыкновенные наименьшие квадраты – это автоматизированный метрический тест, созданный из пакета Python под названием statsmodels. Statsmodels, который предоставляет множество различных статистических моделей и проводит статистические тесты.

Обычные наименьшие квадраты (OLS) — хороший показатель, который также помогает тестировать линейную регрессию. Это метод, который помогает оценить параметры, неизвестные в регрессионной модели. Он уменьшает сумму квадратов расстояний между значениями, которые прогнозируются и наблюдаются с помощью рассчитанной оценки линейной регрессии.

OLS широко используется в сообществе специалистов по данным, особенно для регрессионных экспериментов. OLS также работает с ненормальными распределениями в контексте прогнозирования.

График Q-Q. График Q-Q – это визуализация, используемая в сравнении со стандартным нормальным распределением. Графики Q-Q проверяют предположение о нормальности. Это предположение позволяет визуально увидеть, отклоняются ли точки данных от красной линии. Этот тест оценивается путем получения условий ошибок (остатков) из модели, которая была запущена, а затем строится против нормального распределения. Если точки данных остаются близко к линии, можно предположить, что предположение о нормальности выполнено.

Графики Q-Q — еще один способ оценить регрессионную модель.

Интерпретация значимости и P-значения. Уровень значимости — это мера силы доказательств, которые должны присутствовать в данных выборки, прежде чем кто-либо отклонит нулевую гипотезу и сделает вывод о том, что влияние того, что проверяется, является статистически значимым. Это также обозначается как α или альфа. Уровень значимости — это вероятность отклонения нулевой гипотезы, если она верна. Стандартное значение α обычно равно 0,05, что указывает на 5%-й риск сказать, что разница существует, когда на самом деле ее нет.

Значение p, которое сравнивается с α, представляет собой вероятность, которая покажет, верна ли нулевая гипотеза для популяций. P-значения получены из выборочных данных и предполагают, что нулевая гипотеза верна. P-значения Lowe предлагают больше доказательств для отклонения нулевой гипотезы.

Значимость и p-значение — это другие способы анализа регрессионной модели. Значения значимости можно легко найти при проведении МНК.

Пример прохождения

Линейная регрессия — отличный инструмент для прогнозирования значений на основе других переменных.

Помимо приведенного выше ускоренного курса, я приведу пошаговый пример модели регрессии.

Я решил выбрать набор данных, основанный на прогнозировании цен на недвижимость. Эти данные были получены с https://www.kaggle.com/quantbruce/real-estate-price-prediction. Имеется 414 записей данных и восемь столбцов.

Этот набор данных относительно невелик и предназначен исключительно для практики применения и интерпретации.

8 столбцов:

  1. No
  2. Дата транзакции X1
  3. X2 возраст дома
  4. X3 расстояние до ближайшей станции метро
  5. X4 количество магазинов шаговой доступности
  6. X5 широта
  7. X6 долгота
  8. Y цена дома за единицу площади

Я начну это пошаговое руководство с импорта необходимых пакетов и данных. Оттуда я проведу некоторый исследовательский анализ данных. Затем я создам базовую модель, после чего внесу коррективы и смоделирую данные соответствующим образом. Затем я интерпретирую свои результаты.

#start by importing the necessary libraries
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
∞matplotlib inline
import seaborn as sns
from sklearn.model_selection import train_test_split
import statsmodels.api as sm
from sklearn.model_selection import train_test_split, KFold, cross_validate
from sklearn.linear_model import LinearRegression

Импортируйте данные и проверьте

data = pd.read_csv('../linearregression/Real Estate.csv')
print(data.shape)
print(data.keys())
data.head()

После запуска ячейки должен произойти вывод, подобный этому.

Данные, очистка и исследование

Я хотел бы удалить любые нулевые значения.

#remove null values
data = data.dropna()
print(data.shape)

Это уменьшило мои данные до (414, 8).

Теперь я хотел бы взглянуть на типы данных.

data.dtypes

Теперь я хочу проверить дубликаты. Это спорно, учитывая, что дом может быть продан более одного раза. Кроме того, цена при продаже дома может меняться в зависимости от множества факторов.

#checking for duplicates
data_duplicates = data.duplicated
data_duplicates.shape()

Вывод здесь тот же, дубликатов нет.

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

#I will create subplits of the features against the price to identify categorical variables
fig, axes = plt.subplots(nrows=1, ncols=6, figsize=(18,5))

for xcol, ax in zip(data[['X1 transaction date','X2 house age','X3 distance to the nearest MRT station','X4 number of convenience stores', 'X5 latitude', 'X6 longitude']], axes):
    data.plot(kind='scatter', x=xcol, y='Y house price of unit area', ax=ax, alpha=0.4, color='r')

#checking the distribution
print('Median House Age: ', data['X2 house age'].median())
print('Median Price Per Square Foot: $', data['Y house price of unit area'].median())

Средний возраст дома 16 лет.
Средняя цена за квадратный фут составляет 38,45 долларов США.

Давайте посмотрим, как распределяется цена за единицу площади. Я буду использовать гистограмму для этой визуализации.

fig, ax = plt.subplots(figsize=(12,8))

sns.kdeplot(data['Y house price of unit area'], shade=True, color='navy',alpha=0.8)
sns.despine()

plt.yticks([])
ax.tick_params(axis='both', which='major', labelsize=15)

ax.set_title('House Price Per Unit Area Distribution', fontsize=25, loc='center', weight='bold', pad=20)
ax.set_xlabel('Price ($)', fontsize=18, weight='bold')
ax.set_ylabel('Count', fontsize=18, weight='bold')

plt.xlim(0,200)

Теперь я хотел бы поближе познакомиться с переменными функций. Я сделаю это, проверив мультиколлинеарность.

#Multicollinearity 
data_multicollinearity = data.drop(['No'], axis = 1)

fig, ax = plt.subplots(figsize=(16,10))
sns.heatmap(data_multicollinearity.corr(), center=0, annot=True)

ax.set_title('Feature Correlation Matrix', fontsize=25, loc='center', weight='bold', pad =15)
ax.set_xlabel('Features', fontsize = 14, weight='bold')
ax.tick_params(axis='both', which='major', labelsize=13)

plt.autoscale()
plt.show()

Теперь я хочу сделать блок-диаграмму, показывающую дисперсию функции по мере ее увеличения (это связано с гетероскедастичностью, которую нам нужно остерегаться на более поздних этапах).

var = 'X4 number of convenience stores'
feature_var_data = pd.concat([data['Y house price of unit area'], data[var]], axis=1)

f, ax = plt.subplots(figsize=(14, 10))
fig = sns.boxplot(x=var, y = 'Y house price of unit area', data=feature_var_data, palette='dark')

ax.set_title('Feature Variance: ', fontsize=25, loc='center', weight='bold', pad=10)
ax.set_xlabel('X4 number of convenient stores', fontsize=14, weight='bold')
ax.set_ylabel('Y house price of unit area', fontsize=14, weight='bold')
ax.tick_params(axis='both', which='major', labelsize=13)

sns.despine()
fig.axis(ymin=0, ymax=120);

Моделирование данных

# X variables will contain our continuous and discrete features - we drop the dependent as well as non-predictors
X_base = data.drop(['Y house price of unit area'], axis = 1)

# Y variable is the dependent variable - what we want to predict
Y_base = data[['Y house price of unit area']]

Теперь о моем тестовом поезде. Я всегда буду делать сплит 80/20!

X_train_original, X_test_original, Y_train_original, Y_test_original = train_test_split(X_base, Y_base, test_size=.2, random_state=7)
X_train = X_train_original.copy()
X_test = X_test_original.copy()
Y_train = Y_train_original.copy()
Y_test = Y_test.copy()

print(X_train.shape)
print(X_test.shape)
print(Y_train.shape)
print(Y_test.shape)

(331, 7)

(83, 7)

(331, 1)

(83, 1)

Затем я добавлю константу для моего обычного метода наименьших квадратов и подогнал наклон и точку пересечения к моей модели.

#Statsmodels for Ordinary Least Square for the training set
#adding in a constant to fit both the slope and intercept
X_train_constant = sm.add_constant(X_train)
base_training_model = sm.OLS(Y_train, X_train_constant);
training_results = base_training_model.fit()

Обучающая модель вернула r-квадрат 0,585, это не идеальный показатель. Хорошо, что это не переобучение. Посмотрим, смогу ли я улучшить это.

Оценка и переопределение модели.

Основываясь на p-значениях в сводной таблице, я вижу наличие посторонних признаков. Я хочу выбрать только те функции, у которых p-значение меньше 0,05.

#discarding features with p-values less than .05
base_summary = training_results.summary()
base_p_table = base_summary.tables[1]
base_p_table = pd.DataFrame(base_p_table.data)
base_p_table.columns = base_p_table.iloc[0]
base_p_table = base_p_table.drop(0)
base_p_table = base_p_table.set_index(base_p_table.columns[0])

base_p_table['P>|t|'] = base_p_table['P>|t|'].astype(float)
x_cols = list(base_p_table[base_p_table['P>|t|'] < 0.05].index)
#x_cols.remove('const')
print(len(base_p_table), len(x_cols))
print(x_cols)

Теперь я переустановлю новое подмножество функций.

X_train = X_train[x_cols]
Y_train = Y_train[['Y house price of unit area']]
X_train_const = sm.add_constant(X_train)
base_training_model = sm.OLS(Y_train, X_train_const)
results1= base_training_model.fit()
print("Training Data R-Squared", round(results1.rsquared,3)) results1.summary()

Я проведу еще один тест мультиколлинеарности, но на этот раз я буду использовать коэффициент инфляции дисперсии.

from statsmodels.stats.outliers_influence import variance_inflation_factor
#Here I will perform a variance inflation factor test to identify features that display multicollinearity X = data[x_cols] vif = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])] list(zip(x_cols, vif))

x_cols.remove(‘X1 transaction date’) 
x_cols.remove(‘X5 latitude’)
x_cols

#refit with subset features
X_train = X_train[x_cols]
Y_train = Y_train[['Y house price of unit area']]
X_train_const = sm.add_constant(X_train)
base_training_model = sm.OLS(Y_train, X_train_const);
results2 = base_training_model.fit()
print("Training Data R-Squared:", round(results2.rsquared,3))
results2.summary()

Моя модель достигает r-квадрата 0,544, что еще больше снижает мою оценку точности, но я также удалил функции, которые сильно коррелируют с одним числом.

Сейчас я попробую построить восходящую модель.

#recall the original 80/20 split for train and test data X_train, X_test, Y_train, Y_test = train_test_split(X_base, Y_base, test_size=.2, random_state=42) print(X_train.shape) print(Y_train.shape)

(331, 7) (331, 1)

Select features that are known to predict house prices within a strong degree of accuracy and taking into account 
#multicollinearity
X_train = X_train[['X2 house age', 'X3 distance to the nearest MRT station', 'X4 number of convenience stores']]
Y_train = Y_train[['Y house price of unit area']]
X_test = X_test[['X2 house age', 'X3 distance to the nearest MRT station', 'X4 number of convenience stores']]
Y_test = Y_test[['Y house price of unit area']]
X_train_const = sm.add_constant(X_train)
base_training_model = sm.OLS(Y_train, X_train_const);
results3 = base_training_model.fit()
results3.summary()

Моя модель показала себя еще хуже, чем раньше. Это после удаления дополнительных переменных.

Теперь я собираюсь проверить предположения, упомянутые в начале этого поста.

#I now want to check for the normality assumption
import scipy.stats as stats
fig == sm.graphics.qqplot(results3.resid, dist=stats.norm, line='45', fit=True)

Здесь предположение о нормальности кажется верным, но похоже, что есть выбросы.

#I want to check for homoscedasticity
plt.scatter(results3.predict(X_train_const), results3.resid)
plt.plot(results3.predict(X_train_const), [0 for i in range(len(X_train_const))])
plt.show()

Здесь нарушается гомоскедастическое предположение.

Это показывает, что мои данные не имеют линейной зависимости.

Теперь я буду отбрасывать выбросы, чтобы посмотреть, поможет ли это.

df_outliers = pd.concat([X_train, Y_train], axis=1)

for i in range (80,100): 
    q = i/100
    print("{} percentile: {}".format(q, Y_train['Y house price of unit area'].quantile(q=q)))
    
Y_train['Y house price of unit area'].hist()
plt.show

#I will now drop everything past the 99 percentile 
original_total = len(df_outliers)
df_outlier_dropped = df_outliers[df_outliers['Y house price of unit area'] < 73.0] #subsetting to remove outliers
print("Percent removed:", (original_total - len(df_outlier_dropped))/original_total)
df_outlier_dropped['Y house price of unit area'].max()

X_train = df_outlier_dropped.drop(['Y house price of unit area'], axis=1)
Y_train = df_outlier_dropped['Y house price of unit area']

Процент удалено: 0,012084592145015106

#Now I will use my training data where I have dropped my outlier data and use it on my best performing model 
# this is the refined baseline model 
X_train = X_train[x_cols]
Y_train
X_train_const = sm.add_constant(X_train)
base_training_model = sm.OLS(Y_train, X_train_const);
results4 = base_training_model.fit()
print(round(results4.rsquared,3))
results4.summary()

Удаление выбросов помогло моей модели подскочить до 0,587, что намного лучше, чем мой первый результат r-квадрата!

Я еще раз проверю предположение о нормальности.

#I am going to check normality again to see if it has improved
fig = sm.graphics.qqplot(results4.resid, dist=stats.norm, line ='45', fit=True)

Нормальность на самом деле улучшилась за счет удаления выбросов.

Наконец, я запущу свои тестовые данные.

#standardize test data
for col in X_test_original: 
    X_test_original[col] = (X_test_original[col] - X_test_original[col].mean())/X_test_original[col].std()

X_test_original.head()

X_test = X_test_original[x_cols]
Y_test = Y_test_original
final_model_skl = LinearRegression(fit_intercept=True)

#Learning
final_model_skl.fit(X_train, Y_train)

#Evaluating performance
r2 = final_model_skl.score(X_test, Y_test)
r2 = r2.round(3)

print("R2 = {}".format(r2))

Я получаю r-квадрат 0,511.

Что нам могут рассказать данные:

Количество мини-маркетов на дом, а также широта и долгота, по-видимому, являются наиболее сильными определяющими факторами для цены дома на единицу площади.

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

Одна вещь, которую я бы сделал после этого урока, — это попробовал бы логистическую регрессию. Логистическая регрессия особенно хороша для категориальных переменных.

В реальных сценариях получение r-квадрата 0,587 или 0,511 неплохо. Чаще всего в реальных задачах, связанных с данными, очень редко можно получить высокие баллы.

Источники:

"Линейная регрессия"; Йельский онлайн-курс: LinReg; http://www.stat.yale.edu/Courses/1997-98/101/linreg.htm

"Линейная регрессия"; Куреши, А; https://github.com/anilaq/linearregression/blob/main/linear_regression.ipynb

Линейная V логистическая регрессия; Сурав; https://www.analyticsvidhya.com/blog/2020/12/beginners-take-how-logistic-regression-is-related-to-linear-regression/#:~:text=Linear%20Regression%20is%20used %20to,Logistic%20regression%20обеспечивает%20дискретный%20выход.

P-значение; Фрост, Джим; https://statisticsbyjim.com/glossary/p-value/