вторник, 18 октября 2022 г.

Статистика с Python в розничной торговле : регрессия

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

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


df=pd.read_excel("four_shops_06_08.xlsx",index_col="date", parse_dates=True)
df

dateshoprevvisititemchshiftsconvlchpricevisit_per_shift
02019-06-01Sh196957602066890.0893.02947.06384.444
12019-06-01Sh289212481663950.1574.25653.74149.600
....................................
3662019-08-31Sh32632221692940.1312.37938.14555.250
3672019-08-31Sh42357277612850.1012.17938.63955.400

368 rows × 11 columns


Обозначения :

  • shop - индекс магазина
  • rev - выручка
  • visit - количество посетителей
  • item - количество покупок
  • ch - количество чеков
  • shifts - количество смен продавцов
  • conv - конверсия = количество чеков / количество посетителей
  • lch - длина чека = количество покупок / количество чеков
  • price - средняя цена покупки = выручка / количество покупок
  • visit_per_shift - количество посетителей на смену

Диаграмма рассеяния и коэффициент корреляции

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

Пара  покупки & выручка, понятно, что связь положительна и линейна , т.к. выручка=покупки*цена, но так как цена по дням отличается, мы имеем не идеальную прямую линию, если провести линии регрессии отдельно по каждому магазину, будет видно, что угол наклон (средняя цена продажи) у магазинов будет отличаться.


fg = plt.figure(figsize=(12, 7), constrained_layout=True)
gs = fg.add_gridspec(2, 2)
fig_ax_1 = fg.add_subplot(gs[0, 0])
sns.histplot(df.item)
fig_ax_2 = fg.add_subplot(gs[0, 1])
sns.histplot(df.rev)
fig_ax_3 = fg.add_subplot(gs[1, :])
sns.scatterplot(x='item', y='rev',hue="shop",data=df)
corr, p = stats.pearsonr(df.item, df.rev)
fig_ax_3.title.set_text('Correlation = ' + "{:.2f}".format(corr)+' p='+ "{:.2f}".format(p))




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

fg = plt.figure(figsize=(12, 7), constrained_layout=True)
gs = fg.add_gridspec(2, 2)
fig_ax_1 = fg.add_subplot(gs[0, 0])
sns.histplot(df.visit)
fig_ax_2 = fg.add_subplot(gs[0, 1])
sns.histplot(df.rev)
fig_ax_3 = fg.add_subplot(gs[1, :])
sns.scatterplot(x='visit', y='rev',hue="shop",data=df)
corr, p = stats.pearsonr(df.visit, df.rev)
fig_ax_3.title.set_text('Correlation = ' + "{:.2f}".format(corr)+' p='+ "{:.2f}".format(p))



Пара посетители на смену & конверсия, интересная статистически значимая отрицательная зависимость, хотя и понятная, чем больше посетителей приходится на одного продавца, тем меньше у него возможности качественно обслужить покупателя.

fg = plt.figure(figsize=(12, 7), constrained_layout=True)
gs = fg.add_gridspec(2, 2)
fig_ax_1 = fg.add_subplot(gs[0, 0])
sns.histplot(df.visit_per_shift)
fig_ax_2 = fg.add_subplot(gs[0, 1])
sns.histplot(df.conv)
fig_ax_3 = fg.add_subplot(gs[1, :])
sns.scatterplot(x='visit_per_shift', y='conv',hue="shop",data=df)
corr, p = stats.pearsonr(df.visit_per_shift, df.conv)
fig_ax_3.title.set_text('Correlation = ' + "{:.2f}".format(corr)+' p='+ "{:.2f}".format(p))


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

fg = plt.figure(figsize=(12, 7), constrained_layout=True)
gs = fg.add_gridspec(2, 2)
fig_ax_1 = fg.add_subplot(gs[0, 0])
sns.histplot(df.visit_per_shift)
fig_ax_2 = fg.add_subplot(gs[0, 1])
sns.histplot(df.lch)
fig_ax_3 = fg.add_subplot(gs[1, :])
sns.scatterplot(x='visit_per_shift', y='lch',hue="shop",data=df)
corr, p = stats.pearsonr(df.visit_per_shift, df.lch)
fig_ax_3.title.set_text('Correlation = ' + "{:.2f}".format(corr)+' p='+ "{:.2f}".format(p))




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

fg = plt.figure(figsize=(12, 7), constrained_layout=True)
gs = fg.add_gridspec(2, 2)
fig_ax_1 = fg.add_subplot(gs[0, 0])
sns.histplot(df.visit)
fig_ax_2 = fg.add_subplot(gs[0, 1])
sns.histplot(df.price)
fig_ax_3 = fg.add_subplot(gs[1, :])
sns.scatterplot(x='visit', y='price',hue="shop",data=df)
corr, p = stats.pearsonr(df.visit, df.price)
fig_ax_3.title.set_text('Correlation = ' + "{:.2f}".format(corr)+' p='+ "{:.2f}".format(p))




Формула коэффициента корреляции
 
$$r=\frac{1}{n}\sum_{i=1}^{n}\frac{x_{i}-\bar{x}_{i}}{S_{x}}*\frac{y_{i}-\bar{y}_{i}}{S_{y}}$$

Эта формула представляется как сумма произведений  стандартизированных значений x и y, однако мне кажется более правильным рассмотреть другой ее вариант

$$r=\frac{1}{n}\sum_{i=1}^{n}\frac{\left ( x_{i}-\bar{x}_{i} \right )\left ( y_{i}-\bar{y}_{i} \right )}{S_{x}S_{y}}$$


Слагаемые в числителе выражают взаимодействие двух переменных и определяют знак корреляции. Если между переменными существует сильная положительная взаимосвязь (увеличение одной переменной при увеличении второй), каждое слагаемое будет положительным числом : когда точка характеризуется высоким значением x и y (выше среднего), произведение будет положительным, когда точка характеризуется низким значением (ниже среднего), произведение все равно будет положительным. Аналогично, если между переменными существует сильная отрицательная связь, все слагаемые будут отрицательными числами, что в результате даст отрицательное значение корреляции.

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

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

Некоторые положения, связанные с коэффициентом корреляции :

  • коэффициент корреляции полезен только для измерения линейной связи
  • большой коэффициент корреляции не является показателем причинно-следственная связь между двумя переменными
  • формула коэффициента корреляции симметрична относительно x и y, т.е. корреляция x с y - это тоже самое, что корреляция y с x, т.е., какая из двух переменных будет указана первой, значение не имеет, это утверждение справедливо для корреляции, но несправедливо для регрессии.

Корреляционная матрица


Корреляционная матрица (correlation matrix) : таблица, в которой строки и столбцы — это переменные, а значения ячеек —корреляции между этими переменными. Рассмотрим, как можно получить эту матрицу с помощью Python. 

Корреляционную матрицу можно получить с помощью метода DataFrame.corr

corr_mat = round(df.corr(),2)
corr_mat

revvisititemchshiftsconvlchpricevisit_per_shift
rev1.000.800.960.920.790.160.400.470.56
visit0.801.000.850.900.84-0.290.100.140.85
..............................
price0.470.140.250.220.260.280.191.00-0.03
visit_per_shift0.560.850.650.720.46-0.41-0.04-0.031.00

9 rows × 9 columns

Нагляднее будет представить ее в виде тепловой карты

plt.figure(figsize=(12, 7))
sns.heatmap(df.corr(),vmin=-0.3,vmax=0.6,center=0,annot=True,fmt='.2f',
mask=~np.tri(df.corr().shape[1], k=-1, dtype=bool),
linewidth=2,cbar=False)



Уравнение регрессии

Теперь, когда мы знаем, как рассчитывается относительная взаимосвязь между двумя переменными, мы можем разработать уравнение регрессии для прогнозирования или предсказания желаемой переменной. Ниже приведена формула простой линейной регрессии. «y» — это значение, которое мы пытаемся спрогнозировать, «b» — это наклон линии регрессии, «x» — это значение нашего независимого значения, а «a» представляет точку пересечения с осью y. Уравнение регрессии просто описывает взаимосвязь между зависимой переменной (y) и независимой переменной (x).

$$y=a+bx$$

Наклон  Наклон «b» равен коэффициенту корреляции, умноженному на отношение двух стандартных отклонений. 

Точка пересечения, или «а», представляет собой значение у (зависимой переменной), если значение х (независимая переменная) равно нулю, и поэтому иногда его просто называют «константой». Линейная регрессия пытается оценить линию, которая лучше всего соответствует данным (линия наилучшего соответствия), и уравнение этой линии приводит к уравнению регрессии. Коэффициенты уравнения регрессии находятся методом наименьших квадратов, задача которого минимизировать среднеквадратичную ошибку (mean squared error - MSE)

Подробное описание метрик качества регрессии можно посмотреть в статье "

Машинное обучение с Python в розничной торговле : метрики качества в задачах регрессии" от 20.03.22.


Регрессия является одним из методов машинного обучения, поэтому дальше мы будем рассматривать ее с этой точки зрения.  Существует несколько библиотек языка Python с надежными реализациями широкого диапазона алгоритмов машинного обучения. Одна из самых известных — Scikit-Learn, пакет, предоставляющий эффективные версии множества распространенных алгоритмов, включая регрессию. 

Краткий обзор основных положений, необходимых для работы с библиотекой : 

    Машинное обучение можно представить в виде набора моделей, реализующий определенный алгоритм 

    На вход модели поступают данные 

    Данные для МО представляют собой таблицы 

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

    Каждая строка данных относится к одному из измерений моделируемых объектов и количество строк равно количеству объектов в наборе (например в нашем примере - это дата или день, в котором мы рассматриваем определенный процес, в данном случае это торговый день). 

    Будем называть столбцы матрицы выборками (samples), а количество строк полагать равным n_samples Каждый столбец данных относится к конкретному количественному показателю, описывающему данную выборку. 

    Мы будем называть столбцы матрицы признаками (features), а количество столбцов полагать равным n_features. 

    Из устройства таблицы очевидно, что информацию можно рассматривать как двумерный числовой массив или матрицу, которую мы будем называть матрицей признаков (features matrix). 

    По традиции матрицу признаков часто хранят в переменной X. 

    Предполагается, что матрица признаков — двумерная, с формой [n_samples, n_features], и хранят ее чаще всего в массиве NumPy или объекте DataFrame библиотеки Pandas.


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

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

Помимо матрицы признаков x, обычно мы имеем дело с целевым массивом (массивом меток), который принято обозначать y. Целевой массив обычно одномерен, длиной n_samples. Его хранят в массиве NumPy или объекте Series библиотеки Pandas. Значения целевого массива могут быть непрерывными числовыми или дискретными классами/метками.

Отличительная черта целевого массива от остальных столбцов признаков в том, что он представляет собой величину, значения которой мы хотим предсказать на основе имеющихся данных. Говоря статистическим языком, это зависимая переменная (dependent variable). Например, для наших данных это может быть модель для предсказания конверсии на основе количества посетителей на смену. В этом случае столбец 'conv" рассматривается как целевой массив.

Для использования нашего набора данных в Scikit-Learn мы извлечем матрицу признаков и целевой массив из объекта DataFrame

Все алгоритмы машинного обучения в библиотеке Scikit-Learn реализуются через API статистического оценивания, предоставляющий единообразный интерфейс для широкого диапазона прикладных задач машинного обучения. 

Основы API статистического оценивания 

    1.Чаще всего использование API статистического оценивания библиотеки Scikit-Learn включает следующие шаги :

    2.Выбор класса модели с помощью импорта соответствующего класса оценивателя из библиотеки Scikit-Learn.

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

    4.Компоновка данных в матрицу признаков и целевой вектор в соответствии с описанным выше.

    5.Обучение модели на своих данных посредством вызова метода fit() экземпляра модели.

    6.Применение модели к новым данным: 
        в случае машинного обучения с учителем метки для неизвестных данных обычно предсказывают с помощью метода predict();
        в случае машинного обучения без учителя выполняется преобразование свойств данных или вывод их значений посредством методов transform() или predict(). 
        
Пройдемся по всем шагам этого алгоритма  для простой линейной регрессии

    1.Выбор класса модели. Каждый класс модели в библиотеке Scikit-Learn представлен соответствующим классом языка Python. Так, например, для расчета модели простой линейной регрессии можно импортировать класс линейной регрессии:

from sklearn.linear_model import LinearRegression

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

  • Хотим ли мы выполнить подбор сдвига прямой (то есть точки пересечения с осью координат)? 
  • Хотим ли мы нормализовать модель?
  • Хотим ли мы сделать модель более гибкой, выполнив предварительную обработку признаков?
  • Какая степень регуляризации должна быть у нашей модели?
  • Сколько компонент модели мы хотели бы использовать?

Это примеры тех важных решений, которые нам придется принять после выбора класса модели. Результаты этих решений часто называют гиперпараметрами, то есть параметрами, задаваемыми до обучения модели на данных. Выбор гиперпараметров в библиотеке Scikit-Learn осуществляется путем передачи значений при создании экземпляра модели. 

Создадим экземпляр класса LinearRegression и укажем с помощью гиперпараметра fit_intercept, что нам бы хотелось выполнить подбор точки пересечения с осью координат

regr = LinearRegression(fit_intercept=True)

    3. Формирование из данных матриц признаков и целевого вектора.  Наша целевая переменная y уже имеет нужный вид (массив длиной n_samples), но нам придется проделать небольшие манипуляции с данными x, чтобы сделать из них матрицу размера [n_samples, n_features]. В данном случае манипуляции сводятся просто к изменению формы одномерного массива:


X = x[:, np.newaxis]
X.shape

(92, 1)

#Обучение модели на наших данных.  Сделать это можно с помощью метода fit() 
модели:

regr.fit(X, y)


Команда fit() вызывает выполнение «под капотом» множества вычислений, 
в зависимости от модели, и сохранение результатов этих вычислений в атрибутах
 модели, доступных для просмотра пользователем. 
В библиотеке Scikit-Learn по традиции все параметры модели, полученные в процессе
 выполнения команды fit(), содержат в конце названия знак подчеркивания. 
Например, в данной линейной модели:

print(regr.coef_,regr.intercept_)

[-0.00023762] 0.10396857101918738

Эти два параметра представляют собой угловой коэффициент и точку пересечения

с осью координат для простой линейной аппроксимации наших данных. 

Для получения предсказанных моделью значений используется метод predict

y_lin_fit = regr.predict(X)

Визуализируем наш резульат

plt.figure(figsize=(10,6))
sns.scatterplot(x=X[:,0], y=y)
sns.lineplot(x=X[:,0], y=y_lin_fit)
plt.xlabel('visit_per_shift')
plt.ylabel('conv')
plt.title('simple linear regression cov ~ visit_per_shift')




Рассчитываем метрики качества модели

def MAPE(Y_actual,Y_Predicted):
    mape = np.mean(np.abs((Y_actual - Y_Predicted)/Y_actual))*100
    return mape

lin_mae = metrics.mean_absolute_error(y, y_lin_fit)
lin_mse = metrics.mean_squared_error(y, y_lin_fit)
lin_mape = MAPE(y, y_lin_fit)
lin_rmse = math.sqrt(lin_mse)
lin_r2 = metrics.r2_score(y, y_lin_fit)

# Выводим метрики
print('Decision Linear Regression Metrics:')
print(f'R^2 Score                  = {lin_r2:.3f}')
print(f'Mean Absolute Percentage Error    = {lin_mape:.2f}')
print(f'Mean Absolute Error        = {lin_mae:.2f}')
print(f'Mean Squared Error         = {lin_mse:.2f}')
print(f'Root Mean Squared Error    = {lin_rmse:.2f}')

Decision Linear Regression Metrics:
R^2 Score                  = 0.065
Mean Absolute Percentage Error    = 15.15
Mean Absolute Error        = 0.01
Mean Squared Error         = 0.00
Root Mean Squared Error    = 0.02

Глядя на график рассеяния можно предположить, что связь между нашими переменными нелинейная. В этом случае один из подходов предусматривает использование
полиномиальной регрессионной модели путем добавления полиномиальных членов

$$y=a+b_{1}x+b_{2}x^2+...+b_{d}x^d$$

Здесь d обозначает степень полинома. Для преобразования нашей модели используем
класс преобразователя PolynomialFeatures для добавления квадратичного (d=2) и 
кубичного (d=3) члена.

from sklearn.preprocessing import PolynomialFeatures

X_quad = PolynomialFeatures(degree=2).fit_transform(X)
regr = regr.fit(X_quad, y)
y_quad_fit = regr.predict(X_quad)
# Рассчитываем метрики качества
quad_mae = metrics.mean_absolute_error(y, y_quad_fit)
quad_mse = metrics.mean_squared_error(y, y_quad_fit)
quad_mape = MAPE(y, y_quad_fit)
quad_rmse = math.sqrt(quad_mse)
quad_r2 = metrics.r2_score(y, y_quad_fit)

# Выводим метрики
print('Decision Quadratic Regression Metrics:')
print(f'R^2 Score                  = {quad_r2:.3f}')
print(f'Mean Absolute Percentage Error    = {quad_mape:.2f}')
print(f'Mean Absolute Error        = {quad_mae:.2f}')
print(f'Mean Squared Error         = {quad_mse:.2f}')
print(f'Root Mean Squared Error    = {quad_rmse:.2f}')

Decision Quadratic Regression Metrics:
R^2 Score                  = 0.096
Mean Absolute Percentage Error    = 14.84
Mean Absolute Error        = 0.01
Mean Squared Error         = 0.00
Root Mean Squared Error    = 0.02

X_cub = PolynomialFeatures(degree=3).fit_transform(X)
regr = regr.fit(X_cub, y)
y_cub_fit = regr.predict(X_cub)
# Рассчитываем метрики качества
cub_mae = metrics.mean_absolute_error(y, y_cub_fit)
cub_mse = metrics.mean_squared_error(y, y_cub_fit)
cub_mape = MAPE(y, y_cub_fit)
cub_rmse = math.sqrt(cub_mse)
cub_r2 = metrics.r2_score(y, y_cub_fit)

# Выводим метрики
print('Decision Cubic Regression Metrics:')
print(f'R^2 Score                  = {cub_r2:.3f}')
print(f'Mean Absolute Percentage Error    = {cub_mape:.2f}')
print(f'Mean Absolute Error        = {cub_mae:.2f}')
print(f'Mean Squared Error         = {cub_mse:.2f}')
print(f'Root Mean Squared Error    = {cub_rmse:.2f}')

Decision Cubic Regression Metrics:
R^2 Score                  = 0.101
Mean Absolute Percentage Error    = 14.83
Mean Absolute Error        = 0.01
Mean Squared Error         = 0.00
Root Mean Squared Error    = 0.02

Не ограничимся этим, и используем експоненциальную и степенную модели

#Экспоненциальная модель y=ab^x

y_log=np.log(y)
regr = regr.fit(X, y_log)
y_exp_fit = regr.predict(X)
# Рассчитываем метрики качества
exp_mae = metrics.mean_absolute_error(y, np.exp(y_exp_fit))
exp_mse = metrics.mean_squared_error(y, np.exp(y_exp_fit))
exp_mape = MAPE(y, np.exp(y_exp_fit))
exp_rmse = math.sqrt(exp_mse)
exp_r2 = metrics.r2_score(y, np.exp(y_exp_fit))

# Выводим метрики
print('Decision Exp Regression Metrics:')
print(f'R^2 Score                  = {exp_r2:.3f}')
print(f'Mean Absolute Percentage Error    = {exp_mape:.2f}')
print(f'Mean Absolute Error        = {exp_mae:.2f}')
print(f'Mean Squared Error         = {exp_mse:.2f}')
print(f'Root Mean Squared Error    = {exp_rmse:.2f}')

Decision Exp Regression Metrics:
R^2 Score                  = 0.059
Mean Absolute Percentage Error    = 14.89
Mean Absolute Error        = 0.01
Mean Squared Error         = 0.00
Root Mean Squared Error    = 0.02

#Степенная модель y=ax^b

y_log=np.log(y)
X_log=np.log(X)
regr = regr.fit(X_log, y_log)
y_pow_fit = regr.predict(X_log)
# Рассчитываем метрики качества
pow_mae = metrics.mean_absolute_error(y, np.exp(y_pow_fit))
pow_mse = metrics.mean_squared_error(y, np.exp(y_pow_fit))
pow_mape = MAPE(y, np.exp(y_pow_fit))
pow_rmse = math.sqrt(pow_mse)
pow_r2 = metrics.r2_score(y, np.exp(y_pow_fit))

# Выводим метрики
print('Decision Power Regression Metrics:')
print(f'R^2 Score                  = {pow_r2:.3f}')
print(f'Mean Absolute Percentage Error    = {pow_mape:.2f}')
print(f'Mean Absolute Error        = {pow_mae:.2f}')
print(f'Mean Squared Error         = {pow_mse:.2f}')
print(f'Root Mean Squared Error    = {pow_rmse:.2f}')

Decision Power Regression Metrics:
R^2 Score                  = 0.070
Mean Absolute Percentage Error    = 14.88
Mean Absolute Error        = 0.01
Mean Squared Error         = 0.00
Root Mean Squared Error    = 0.02

Чтобы лучше представить, что у нас получилось, выведем графики

plt.figure(figsize=(10,6))
sns.scatterplot(x=X[:,0], y=y,label='training points', color='k')
sns.lineplot(x=X[:,0], y=y_lin_fit,label='line (d=1),
 $R^2={:.2f}$'.format(lin_r2),color = 'r')
sns.lineplot(x=X[:,0], y=y_quad_fit,label='quadratic (d=2), 
$R^2={:.2f}$'.format(quad_r2),color = 'b') 
sns.lineplot(x=X[:,0], y=y_cub_fit,label='cubic (d=3), 
$R^2={:.2f}$'.format(cub_r2),color = 'g') 
sns.lineplot(x=X[:,0], y=np.exp(y_exp_fit),label='exponent,
 $R^2={:.2f}$'.format(exp_r2),color='m')
sns.lineplot(x=X[:,0], y=np.exp(y_pow_fit),label='power,
 $R^2={:.2f}$'.format(pow_r2),color='c')
plt.xlabel("visit_per_shift", fontsize=14)
plt.ylabel("conv", fontsize=14)
plt.legend(loc='upper right')
plt.xlabel('visit_per_shift')
plt.ylabel('conv')
plt.title('simple linear and non-linear regression cov ~ visit_per_shift')


Также выведем остатки моделей

model_name=['line (a+b*x)','quadratic (a+b1*x+b2*x^2)',
'cubic (a+b1*x+b2*x^2+b3*x^3)','exponent (a*b^x)','power (a*x^b)',''] fig, axs = plt.subplots(3, 2, figsize=(12, 10), sharey=True) plt.subplots_adjust(hspace=0.5) axs[0,0].scatter(X[:,0], y - y_lin_fit,c='steelblue', marker='o', edgecolor='white',label='line') axs[0,1].scatter(X[:,0], y - y_quad_fit,c='g', marker='s', edgecolor='white',label='line') axs[1,0].scatter(X[:,0], y - y_cub_fit,c='r', marker='h', edgecolor='white',label='line') axs[1,1].scatter(X[:,0], y - np.exp(y_exp_fit),c='m', marker='H', edgecolor='white',label='line') axs[2,0].scatter(X[:,0], y - np.exp(y_pow_fit),c='b', marker='8', edgecolor='white',label='line') fig.delaxes(axs[2,1]) for i,ax in enumerate(axs.flat): ax.set(xlabel='visit_per_shift', ylabel='residual') ax.axhline (y = 0, color = 'b') ax.set_title("model "+model_name[i])




Разберем пример множественной линейной регрессии вида

$$y=a+b_{1}x_{1}+b_{2}x_{2}+...+b_{p}x_{p}$$

где p - количество объясняющих переменных. Разберем множественную регрессию на 
следующих  данных :

df = pd.read_excel("four_shops_visit_rev_06_08.xlsx",parse_dates=['date'])
df

dateSh1_visitSh2_visitSh3_visitSh4_visitSh1_revSh2_revSh3_revSh4_revtotal_visittotal_rev
02019-06-017602482033549695892128202582156524018
12019-06-027972102434237864382527414077167318507
....................................
902019-08-3037411118524043813739713125791010090
912019-08-31683224221277120491214726322357140529185

92 rows × 11 columns

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

df1=df[['Sh1_visit','Sh2_visit','Sh3_visit','Sh4_visit','total_rev']]
df1

Sh1_visitSh2_visitSh3_visitSh4_visittotal_rev
076024820335424018
179721024342318507
..................
9037411118524010090
9168322422127729185

92 rows × 5 columns


Выведем диаграммы рассеяния

fig, ax = plt.subplots(1,4,figsize=(14,6))
plt.subplots_adjust(wspace=0.5)
ax[0].scatter(df1.Sh1_visit,df.total_rev,color="g")
ax[1].scatter(df1.Sh2_visit,df.total_rev,color="r")
ax[2].scatter(df1.Sh3_visit,df.total_rev,color="b")
ax[3].scatter(df1.Sh4_visit,df.total_rev,color="m")
ax[0].set_xlabel("Sh1 visit")
ax[1].set_xlabel("Sh2 visit")
ax[2].set_xlabel("Sh3 visit")
ax[3].set_xlabel("Sh4 visit")
ax[0].set_ylabel("total rev");


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

выручку по показателям посетителей

X = df1.iloc[:, :-1].values
y= df1['total_rev'].values
regr = LinearRegression(fit_intercept=False)
regr.fit(X, y)
y_pred = regr.predict(X)
# Рассчитываем метрики качества
mae = metrics.mean_absolute_error(y, y_pred)
mse = metrics.mean_squared_error(y, y_pred)
mape = MAPE(y, y_pred)
rmse = math.sqrt(lin_mse)
r2 = metrics.r2_score(y, y_pred)


# Выводим метрики

print('Decision Linear Regression Metrics:')
print(f'R^2 Score                  = {r2:.3f}')
print(f'Mean Absolute Percentage Error    = {mape:.2f}')
print(f'Mean Absolute Error        = {mae:.2f}')
print(f'Mean Squared Error         = {mse:.2f}')
print(f'Root Mean Squared Error    = {rmse:.2f}')


Decision Linear Regression Metrics:
R^2 Score                  = 0.856
Mean Absolute Percentage Error    = 13.81
Mean Absolute Error        = 1722.79
Mean Squared Error         = 4997263.18
Root Mean Squared Error    = 17.67

Выведем графики остатков модели в координатах объясняющих переменных

col=df1.columns[:-1]
fig, axs = plt.subplots(2, 2, figsize=(12, 10), sharey=True)
axs[0,0].scatter(X[:,0], y - y_pred,c='steelblue',
                marker='o', edgecolor='white',label='line')
axs[0,1].scatter(X[:,1], y - y_pred,c='g',
                marker='s', edgecolor='white',label='line')
axs[1,0].scatter(X[:,2], y - y_pred,c='r',
                marker='h', edgecolor='white',label='line')
axs[1,1].scatter(X[:,3], y - y_pred,c='m',
                marker='H', edgecolor='white',label='line')
for i,ax in enumerate(axs.flat):
    ax.set(xlabel=col[i], ylabel='residual')
    ax.axhline (y = 0, color = 'b')















Комментариев нет:

Отправить комментарий