April 15, 2022

Корреляция - когда применять можно, а когда опасно

Корреляция показывает линейную взаимосвязь между последовательностями значений. Однако ее следует применять не ко всем наборам чисел.

Напомним формулу коэффициента корреляции - Pxy = E(X-Ex)(Y-Ey) / (Sx*Sy), где Ex, Ey -  математические ожидания случайных величин X и Y, Sx и Sy - стандартные отклонения X и Y (подробнее о понятиях рассказывал здесь);

На практике данная формула превращается в сумму попарных произведений вида k*(x-x_ср)*(y-y_ср), где k некий положительный коэффициент. Каждый множитель входит в сумму со знаком "+", если оба значения одновременно выше своего среднего или ниже и "-", если один выше, а другой ниже. То есть корреляция положительна, когда величины склонны принимать большие и малые значения одновременно (максимум 1) и отрицательна, когда при больших значениях одной, другая стремится принимать меньшие значения (минимум -1).

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

import pandas as pd
import numpy as np
df = pd.DataFrame([['Иванов ИИ', '1987.01.22', 120], ['Федоров АК', '1965.12.20', 12], 
                   ['Арсентьева ВБ', '1977.03.12', 14],
                  ['Чувашов ВК', '1990.11.12', 123], ['Галанова ББ', '1955.04.04', 14]], 
                  columns=['fio', 'b_data', 'revenue'])
df['b_data'] = pd.to_datetime(df['b_data'], format='%Y.%m.%d')

df['mon'] = df['b_data'].dt.month
df['year']  = df['b_data'].dt.year
df

Посчитаем корреляцию между доходом и годом:

В противоположность между месяцем и доходом считать корреляцию неправильно, так как между месяцами упорядоченности нет (разве что в рамках одного года), например, месяц 1 в первой записи, который соответствовал году 1987 станет меньше, чем месяц 12 в 1965 году. Однако Pandas вам позволит посчитать корреляцию, так как в обоих столбцах значения числовые:

Для тех кто хочет заглянуть глубже в детали подсчета:

n = df['mon'].shape[0]
mu1 = df['mon'].mean()
mu2 = df['revenue'].mean()
std1 = np.sqrt(((1/(n-1))*(df['mon'] - mu1)**2).sum()) 
std2 = np.sqrt(((1/(n-1))*(df['revenue'] - mu2)**2).sum())

k =  ((1/(n-1))/(std1*std2))

k*((df['mon'] - mu1)*(df['revenue'] - mu2)).sum()

Смотрите на формулу как k*(сумму). Знаки сомножителей в сумме определяются так:

Для дохода большие значения соответствуют большим доходам (0 и 3), тогда как для месяца - нет (0 запись имеет самое малое значение, хотя дата - вторая самая большая в первоначальном массиве).