Корреляционная матрица (correlation matrix) : таблица, в которой строки и столбцы — это переменные, а значения ячеек —корреляции между этими переменными. Рассмотрим, как можно получить эту матрицу с помощью Python.
Для примера используем следующий набор данных :
df = pd.read_excel("shop06.xlsx", index_col="date")
df.head()
wd | Plan | Rev | Visit | Conv | LCH | Price | |
---|---|---|---|---|---|---|---|
date | |||||||
2021-01-06 | 2 | 1200 | 1879 | 183 | 8.74 | 4.13 | 28 |
2021-02-06 | 3 | 1200 | 1431 | 187 | 9.09 | 3.24 | 26 |
2021-03-06 | 4 | 1200 | 547 | 219 | 5.48 | 2.33 | 26 |
2021-04-06 | 5 | 1200 | 1051 | 193 | 8.81 | 2.82 | 27 |
2021-05-06 | 6 | 2200 | 2247 | 309 | 8.09 | 3.20 | 28 |
Данные представляют собой дневные показатели работы розничного магазина одежды.Расшифруем показатели :
- date - дата
- wd - день недели 1-понедельник, 7-воскресенье.
- Plan- план в у.е.
- Rev - выручка в у.е.
- Visit - количество посетителей
- Conv - конверсия = количество чеков / количество посетителей
- LCH - длина чека = количество покупок / количество чеков
- Price - средняя цена покупки
Добавим еще одну колонку - выполнение плана
df['PlanPct']=df.apply(lambda r: round(r.Rev/r.Plan,2),axis=1)
df.head()
wd | Plan | Rev | Visit | Conv | LCH | Price | PlanPct | |
---|---|---|---|---|---|---|---|---|
date | ||||||||
2021-01-06 | 2 | 1200 | 1879 | 183 | 8.74 | 4.13 | 28 | 1.57 |
2021-02-06 | 3 | 1200 | 1431 | 187 | 9.09 | 3.24 | 26 | 1.19 |
2021-03-06 | 4 | 1200 | 547 | 219 | 5.48 | 2.33 | 26 | 0.46 |
2021-04-06 | 5 | 1200 | 1051 | 193 | 8.81 | 2.82 | 27 | 0.88 |
2021-05-06 | 6 | 2200 | 2247 | 309 | 8.09 | 3.20 | 28 | 1.02 |
Корреляционную матрицу можно получить с помощью метода DataFrame.corr
corr_mat = round(df.corr(),2)
corr_mat
wd | Plan | Rev | Visit | Conv | LCH | Price | PlanPct | |
---|---|---|---|---|---|---|---|---|
wd | 1.00 | 0.84 | 0.72 | 0.84 | -0.03 | -0.10 | 0.31 | 0.13 |
Plan | 0.84 | 1.00 | 0.73 | 0.89 | -0.09 | -0.07 | 0.16 | -0.02 |
Rev | 0.72 | 0.73 | 1.00 | 0.73 | 0.23 | 0.23 | 0.43 | 0.64 |
Visit | 0.84 | 0.89 | 0.73 | 1.00 | -0.33 | 0.00 | 0.16 | 0.09 |
Conv | -0.03 | -0.09 | 0.23 | -0.33 | 1.00 | -0.05 | 0.19 | 0.48 |
LCH | -0.10 | -0.07 | 0.23 | 0.00 | -0.05 | 1.00 | -0.26 | 0.44 |
Price | 0.31 | 0.16 | 0.43 | 0.16 | 0.19 | -0.26 | 1.00 | 0.41 |
PlanPct | 0.13 | -0.02 | 0.64 | 0.09 | 0.48 | 0.44 | 0.41 | 1.00 |
Чтобы можно было отобрать максимальные корреляции, уберем единицы с диагонали
for x in range(corr_mat.shape[0]): corr_mat.iloc[x,x] = 0.0 corr_mat
wd | Plan | Rev | Visit | Conv | LCH | Price | PlanPct | |
---|---|---|---|---|---|---|---|---|
wd | 0.00 | 0.84 | 0.72 | 0.84 | -0.03 | -0.10 | 0.31 | 0.13 |
Plan | 0.84 | 0.00 | 0.73 | 0.89 | -0.09 | -0.07 | 0.16 | -0.02 |
Rev | 0.72 | 0.73 | 0.00 | 0.73 | 0.23 | 0.23 | 0.43 | 0.64 |
Visit | 0.84 | 0.89 | 0.73 | 0.00 | -0.33 | 0.00 | 0.16 | 0.09 |
Conv | -0.03 | -0.09 | 0.23 | -0.33 | 0.00 | -0.05 | 0.19 | 0.48 |
LCH | -0.10 | -0.07 | 0.23 | 0.00 | -0.05 | 0.00 | -0.26 | 0.44 |
Price | 0.31 | 0.16 | 0.43 | 0.16 | 0.19 | -0.26 | 0.00 | 0.41 |
PlanPct | 0.13 | -0.02 | 0.64 | 0.09 | 0.48 | 0.44 | 0.41 | 0.00 |
А теперь выведем пары с максимальными корреляциями c их значениями
pc=corr_mat.abs().idxmax() cormax=corr_mat.loc[pc.index,pc.values] df_cor=pd.DataFrame({'colname ': pc,'cor': np.diagonal(cormax)}) df_cor.sort_values(by=['cor'])
colname cor Price Rev 0.43 LCH PlanPct 0.44 Conv PlanPct 0.48 PlanPct Rev 0.64 Rev Plan 0.73 wd Plan 0.84 Plan Visit 0.89 Visit Plan 0.89
Однако очень хотелось бы вывести не только значения корреляций,но и соответствующие им p-значения, чтобы понимать насколько значима корреляция.Сделаем это в несколько шаговС помощью метода corr() получаем корреляционную матрицуdf_cor=df.corr()
wd | Plan | Rev | Visit | Conv | LCH | Price | PlanPct | |
---|---|---|---|---|---|---|---|---|
wd | 1.00 | 0.84 | 0.72 | 0.84 | -0.03 | -0.10 | 0.31 | 0.13 |
Plan | 0.84 | 1.00 | 0.73 | 0.89 | -0.09 | -0.07 | 0.16 | -0.02 |
Rev | 0.72 | 0.73 | 1.00 | 0.73 | 0.23 | 0.23 | 0.43 | 0.64 |
Visit | 0.84 | 0.89 | 0.73 | 1.00 | -0.33 | 0.00 | 0.16 | 0.09 |
Conv | -0.03 | -0.09 | 0.23 | -0.33 | 1.00 | -0.05 | 0.19 | 0.48 |
LCH | -0.10 | -0.07 | 0.23 | 0.00 | -0.05 | 1.00 | -0.26 | 0.44 |
Price | 0.31 | 0.16 | 0.43 | 0.16 | 0.19 | -0.26 | 1.00 | 0.41 |
PlanPct | 0.13 | -0.02 | 0.64 | 0.09 | 0.48 | 0.44 | 0.41 | 1.00 |
С помощью функции nympy tril обнуляем значения выше диагоналиdf_cor=pd.DataFrame(np.tril(df_cor, k=-1),columns=df_cor.columns,
index=df_cor.columns)
wd | Plan | Rev | Visit | Conv | LCH | Price | PlanPct | |
---|---|---|---|---|---|---|---|---|
wd | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.0 |
Plan | 0.84 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.0 |
Rev | 0.72 | 0.73 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.0 |
Visit | 0.84 | 0.89 | 0.73 | 0.00 | 0.00 | 0.00 | 0.00 | 0.0 |
Conv | -0.03 | -0.09 | 0.23 | -0.33 | 0.00 | 0.00 | 0.00 | 0.0 |
LCH | -0.10 | -0.07 | 0.23 | 0.00 | -0.05 | 0.00 | 0.00 | 0.0 |
Price | 0.31 | 0.16 | 0.43 | 0.16 | 0.19 | -0.26 | 0.00 | 0.0 |
PlanPct | 0.13 | -0.02 | 0.64 | 0.09 | 0.48 | 0.44 | 0.41 | 0.0 |
Метод stack() поворачивает уровень меток столбцов, превращая его в индекс строк
помещаем столбцы в еще один уровень индекса строк
Результатом становится объект Series
df_cor=df_cor.stack()
wd wd 0.00 Plan 0.00 Rev 0.00 Visit 0.00 Conv 0.00 ... PlanPct Visit 0.09 Conv 0.48 LCH 0.44 Price 0.41 PlanPct 0.00 Length: 64, dtype: float64
Убираем нулевые значения
df_cor=df_cor[df_cor.abs()>0]
Plan wd 0.84 Rev wd 0.72 Plan 0.73 Visit wd 0.84 Plan 0.89 Rev 0.73 Conv wd -0.03 Plan -0.09 Rev 0.23 Visit -0.33 LCH wd -0.10 Plan -0.07 Rev 0.23 Conv -0.05 Price wd 0.31 Plan 0.16 Rev 0.43 Visit 0.16 Conv 0.19 LCH -0.26 PlanPct wd 0.13 Plan -0.02 Rev 0.64 Visit 0.09 Conv 0.48 LCH 0.44 Price 0.41 dtype: float64
Обозначаем столбец с корреляцией и сбрасываем индекс
df_cor=df_cor.rename("pearson")
df_cor=df_cor.reset_index()
level_0 | level_1 | pearson | |
---|---|---|---|
0 | Plan | wd | 0.84 |
1 | Rev | wd | 0.72 |
2 | Rev | Plan | 0.73 |
3 | Visit | wd | 0.84 |
4 | Visit | Plan | 0.89 |
5 | Visit | Rev | 0.73 |
6 | Conv | wd | -0.03 |
7 | Conv | Plan | -0.09 |
8 | Conv | Rev | 0.23 |
9 | Conv | Visit | -0.33 |
10 | LCH | wd | -0.10 |
11 | LCH | Plan | -0.07 |
12 | LCH | Rev | 0.23 |
13 | LCH | Conv | -0.05 |
14 | Price | wd | 0.31 |
15 | Price | Plan | 0.16 |
16 | Price | Rev | 0.43 |
17 | Price | Visit | 0.16 |
18 | Price | Conv | 0.19 |
19 | Price | LCH | -0.26 |
20 | PlanPct | wd | 0.13 |
21 | PlanPct | Plan | -0.02 |
22 | PlanPct | Rev | 0.64 |
23 | PlanPct | Visit | 0.09 |
24 | PlanPct | Conv | 0.48 |
25 | PlanPct | LCH | 0.44 |
26 | PlanPct | Price | 0.41 |
Добавляем колонку с p-значением
df_cor['p']=df_cor.apply(lambda r:
round(stats.pearsonr(df[r.level_0],df[r.level_1])[1],4),axis=1)
level_0 | level_1 | pearson | p | |
---|---|---|---|---|
0 | Plan | wd | 0.84 | 0.0000 |
1 | Rev | wd | 0.72 | 0.0000 |
2 | Rev | Plan | 0.73 | 0.0000 |
3 | Visit | wd | 0.84 | 0.0000 |
4 | Visit | Plan | 0.89 | 0.0000 |
5 | Visit | Rev | 0.73 | 0.0000 |
6 | Conv | wd | -0.03 | 0.8848 |
7 | Conv | Plan | -0.09 | 0.6231 |
8 | Conv | Rev | 0.23 | 0.2256 |
9 | Conv | Visit | -0.33 | 0.0756 |
10 | LCH | wd | -0.10 | 0.5979 |
11 | LCH | Plan | -0.07 | 0.7181 |
12 | LCH | Rev | 0.23 | 0.2167 |
13 | LCH | Conv | -0.05 | 0.7775 |
14 | Price | wd | 0.31 | 0.0973 |
15 | Price | Plan | 0.16 | 0.3897 |
16 | Price | Rev | 0.43 | 0.0175 |
17 | Price | Visit | 0.16 | 0.3941 |
18 | Price | Conv | 0.19 | 0.3096 |
19 | Price | LCH | -0.26 | 0.1587 |
20 | PlanPct | wd | 0.13 | 0.4793 |
21 | PlanPct | Plan | -0.02 | 0.9210 |
22 | PlanPct | Rev | 0.64 | 0.0001 |
23 | PlanPct | Visit | 0.09 | 0.6522 |
24 | PlanPct | Conv | 0.48 | 0.0068 |
25 | PlanPct | LCH | 0.44 | 0.0143 |
26 | PlanPct | Price | 0.41 | 0.0256 |
Убираем значения с p-уровнем значимости больше 0.05
df_cor=df_cor.query('p<=0.05')
level_0 | level_1 | pearson | p | |
---|---|---|---|---|
0 | Plan | wd | 0.843035 | 0.0000 |
1 | Rev | wd | 0.715471 | 0.0000 |
2 | Rev | Plan | 0.726003 | 0.0000 |
3 | Visit | wd | 0.835415 | 0.0000 |
4 | Visit | Plan | 0.890589 | 0.0000 |
5 | Visit | Rev | 0.732999 | 0.0000 |
11 | Price | Rev | 0.430656 | 0.0175 |
15 | PlanPct | Rev | 0.642399 | 0.0001 |
17 | PlanPct | Conv | 0.483507 | 0.0068 |
18 | PlanPct | LCH | 0.442528 | 0.0143 |
19 | PlanPct | Price | 0.406954 | 0.0256 |
Теперь можно прокомментировать полученные значения корреляции :
- План и выручка коррелируют с номером дня недели, чем ближе к выходным,
- тем больше план и выручка, так проявляется дневная сезонность
- Выручка с планом тоже понятно, дневная сезонность
- Посетители с днями недели - сезонность
- Посетители с планом и выручкой тоже логично, больше посетителей,
- больше выручка,
- но план как-то больше коррелирует с посетителями, чем выручка,
- значит план
- был рассчитан на более качественные показатели работы персонала
- Средняя цена и выручка тоже понятна
- Также логично то , что выполнение плана значимо коррелирует с выручкой,
- конверсией, длиной чека и ценой
Эту последовательность шагов поместим в функцию
def cor_mat_p_val(df):
df_cor=df.corr()
df_cor=pd.DataFrame(np.tril(df_cor, k=-1),columns=df_cor.columns,
index=df_cor.columns)
df_cor=df_cor.stack()
df_cor=df_cor[df_cor.abs()>0]
df_cor=df_cor.rename("pearson")
df_cor=df_cor.reset_index()
df_cor['p']=df_cor.apply(lambda r:
round(stats.pearsonr(df[r.level_0],df[r.level_1])[1],4),axis=1)
return df_cor.query('p<=0.05')
Выведем корреляционную матрицу в виде "тепловой карты"
sns.heatmap(corr_mat, annot=True, fmt='.2f', linewidths=2)
Уберем вывод верхней половины матрицы
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)
Комментариев нет:
Отправить комментарий