Как сделать подпись значений на графике и найти корреляцию между двумя графиками?

Коллеги, всем привет! Имею следующие данные:

import matplotlib.pyplot as plt

weather_data = {
'01.12': -4,
'02.12': -5,
'03.12': -5,
'04.12': -7,
'05.12': -10,
'06.12': -11,
'07.12': -11,
'08.12': -13,
'09.12': -13,
'10.12': -11,
'11.12': -6,
'12.12': -5,
'13.12': -7,
'14.12': -9,
'15.12': -8,
'16.12': -4,
'17.12': +2,
'18.12': +2,
'19.12': +4,
'20.12': +3,
'21.12': +1,
'22.12': +1,
'23.12': +1
}

value_clients = {
'01.12': 285,
'02.12': 496,
'03.12': 487,
'04.12': 254,
'05.12': 190,
'06.12': 236,
'07.12': 206,
'08.12': 267,
'09.12': 452,
'10.12': 384,
'11.12': 218,
'12.12': 252,
'13.12': 254,
'14.12': 265,
'15.12': 241,
'16.12': 425,
'17.12': 369,
'18.12': 256,
'19.12': 186,
'20.12': 255,
'21.12': 238,
'22.12': 277,
'23.12': 347
}

days = list(weather_data.keys())
temperatures = list(weather_data.values())
days = list(value_clients.keys())
value = list(value_clients.values())

# Создание графика
plt.figure(figsize=(15, 5))  # Указываем размер графика
plt.plot(days, temperatures, marker='o', linestyle='-', color='b')  # График температуры
plt.title('Температура в Твери по дням')  # Заголовок графика
plt.xlabel('День недели')  # Ось X
plt.ylabel('Температура, °C')  # Ось Y
plt.grid(True, which='both', linestyle='--', linewidth=0.5)  # Сетка
plt.tight_layout()  # Автоматическое распределение пространства
# Создание второго графика
plt.figure(figsize=(15, 5))  # Указываем размер графика
plt.plot(days, value, marker='o', linestyle='-', color='r')  #         График температуры
plt.title('Количество клиентов посетивших комплекс')  # Заголовок     графика
plt.xlabel('День месяца')  # Ось X
plt.ylabel('Количество человек')  # Ось Y
plt.grid(True, which='both', linestyle='-', linewidth=0.5)  # Сетка
plt.tight_layout()  # Автоматическое распределение пространства
# Отображение графика
plt.show()

Далее он отображает мне следующий графики:

введите сюда описание изображения

введите сюда описание изображения

Как мне добавить подписи значений на каждую точку графика? И ещё один вопрос, как мне найти корреляцию между двумя этими графиками?


Ответы (1 шт):

Автор решения: CrazyElf

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

import pandas as pd
from sklearn.linear_model import RidgeCV
from sklearn.metrics import mean_squared_error
import dateutil as du

df = pd.DataFrame({'day': days, 'temp': temperatures, 'clients': value})
df['day'] = pd.to_datetime(df.day + ".2023", dayfirst=True)
print(df.corr()['clients'])
df['weekend'] = (df.day.dt.dayofweek > 4).astype(int)
print(df.corr()['clients'])
X = df[['temp', 'weekend']]
y = df[['clients']]
lr = RidgeCV()
lr.fit(X, y)
print(lr.coef_)
y_pred = lr.predict(X)
df['predict'] = y_pred
print(f'RMSE: {mean_squared_error(y, y_pred)**0.5}')
df = df.set_index('day')
df[['clients', 'predict']].plot()

Вывод:

day       -0.218086
temp      -0.063177
clients    1.000000
Name: clients, dtype: float64

day       -0.218086
temp      -0.063177
clients    1.000000
weekend    0.909184
Name: clients, dtype: float64

[[ -1.08625212 176.72790901]]

RMSE: 37.60443795836316

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

введите сюда описание изображения

О том, как ещё можно эти результаты трактовать. Посмотрите на коэффициенты линейной регрессии. У температуры коэффициент примерно -1, т.е. на каждый градус повышения температуры количество клиентов уменьшается на 1. А вот у признака "выходной" коэффициент почти 177, т.е. выходной день сразу даёт +177 клиентов.

Среднеквадратичная ошибка RMSE нашей модели получилась примерно 38, т.е. грубо говоря данная модель ошибается "в среднем по больнице" где-то на 40 человек в день, что, наверное, довольно неплохо для такой простой модели. Но, если вернуться к корреляции с температурой, то при среднеквадратичной ошибке 40 изменение на 1 клиента в зависимости от температуры - это вообще ни о чём и может быть просто погрешностью измерения или модели. Это нужно иметь в виду.

P.S. Подписи можно добавить к соответствующим графикам примерно так:

for d,t in zip(days, temperatures):
    plt.text(d, t+0.2, t);
...
for d,t in zip(days, value):
    plt.text(d, t+0.2, t);

введите сюда описание изображения

введите сюда описание изображения

P.P.S. Если построить ту же линейную модель только по одному признаку, то получится:

  • На одной температуре RMSE=91, это гораздо хуже.
  • На одном признаке "выходной" RMSE=38, то есть практически без изменения, что с температурой, что без неё, что и было в общем понятно.

Вот график предсказания на одной только температуре. Это практически просто среднее значение числа посетителей.

введите сюда описание изображения

Более того, если взять константное предсказание на все дни - среднее значение посетителей в день за этот период (около 297 в день), то получим ту же самую метрику RMSE=91, что и с моделью на признаке "температура". Лишний раз убеждаемся, что температура практически ничего не даёт для предсказания посетителей.

→ Ссылка