
Для расчета коэффициента корреляции в PostgreSQL используется агрегатная функция corr
corr ( Y double precision, X double precision ) → double precision
Вычисляет коэффициент корреляции.
Однако, в ходе экспериментов была обнаружена интересная особенность функции corr - несовпадение результата с вычислениями в Excel.
Демонстрация для PostgreSQL версии 17
Тестовая таблица
CREATE TABLE test ( id integer , n1 double precision , n2 double precision , n3 double precision , n4 double precision ,n5 double precision );
Заполнение тестовой таблицы
INSERT INTO test ( id , n1 , n2 ,n3 , n4 ,n5 ) VALUES ( generate_series(1, 100),trunc(random()*100), 0.09 ,0.01 , 50 ,50.0 + ( random() / 100.0 ) );
Данные в тестовой таблице
SELECT * FROM test ; id | n1 | n2 | n3 | n4 | n5 -----+----+------+------+----+-------------------- 1 | 36 | 0.09 | 0.01 | 50 | 50.00621654293942 2 | 92 | 0.09 | 0.01 | 50 | 50.006497742852645 3 | 1 | 0.09 | 0.01 | 50 | 50.006280993837635 4 | 69 | 0.09 | 0.01 | 50 | 50.00841365225481 5 | 78 | 0.09 | 0.01 | 50 | 50.00154316058645 6 | 47 | 0.09 | 0.01 | 50 | 50.00738933579143 7 | 17 | 0.09 | 0.01 | 50 | 50.00603762461176 8 | 10 | 0.09 | 0.01 | 50 | 50.00758576917584 9 | 76 | 0.09 | 0.01 | 50 | 50.00134152728483 10 | 34 | 0.09 | 0.01 | 50 | 50.00645489433778 11 | 16 | 0.09 | 0.01 | 50 | 50.002059723234744 12 | 6 | 0.09 | 0.01 | 50 | 50.00966318353639 13 | 27 | 0.09 | 0.01 | 50 | 50.009460725903594 14 | 81 | 0.09 | 0.01 | 50 | 50.009483957949875 15 | 21 | 0.09 | 0.01 | 50 | 50.00821428161928 16 | 46 | 0.09 | 0.01 | 50 | 50.0033679016193 17 | 37 | 0.09 | 0.01 | 50 | 50.006204066803825 18 | 72 | 0.09 | 0.01 | 50 | 50.000081383021204 19 | 1 | 0.09 | 0.01 | 50 | 50.00456641068732 20 | 46 | 0.09 | 0.01 | 50 | 50.00244477619546 21 | 87 | 0.09 | 0.01 | 50 | 50.00176368771677 22 | 3 | 0.09 | 0.01 | 50 | 50.00569580845861 23 | 70 | 0.09 | 0.01 | 50 | 50.0095379964205 24 | 23 | 0.09 | 0.01 | 50 | 50.009802959442894 25 | 87 | 0.09 | 0.01 | 50 | 50.00569967390437 26 | 21 | 0.09 | 0.01 | 50 | 50.009189504439476 27 | 95 | 0.09 | 0.01 | 50 | 50.00900754265528 28 | 78 | 0.09 | 0.01 | 50 | 50.00238383410292 29 | 61 | 0.09 | 0.01 | 50 | 50.00084203208884 30 | 10 | 0.09 | 0.01 | 50 | 50.00435131919839 31 | 47 | 0.09 | 0.01 | 50 | 50.004035289654404 32 | 59 | 0.09 | 0.01 | 50 | 50.00445991601925 33 | 62 | 0.09 | 0.01 | 50 | 50.00878572611977 34 | 71 | 0.09 | 0.01 | 50 | 50.002757109856425 35 | 52 | 0.09 | 0.01 | 50 | 50.00611056006292 36 | 66 | 0.09 | 0.01 | 50 | 50.00697885620605 37 | 9 | 0.09 | 0.01 | 50 | 50.006011915628285 38 | 67 | 0.09 | 0.01 | 50 | 50.00859411134951 39 | 96 | 0.09 | 0.01 | 50 | 50.004438428438476 40 | 96 | 0.09 | 0.01 | 50 | 50.00204724660321 41 | 47 | 0.09 | 0.01 | 50 | 50.00637634321826 42 | 15 | 0.09 | 0.01 | 50 | 50.00976974510356 43 | 8 | 0.09 | 0.01 | 50 | 50.00624291944184 44 | 51 | 0.09 | 0.01 | 50 | 50.005173603996624 45 | 20 | 0.09 | 0.01 | 50 | 50.00210520583459 46 | 9 | 0.09 | 0.01 | 50 | 50.00363434421869 47 | 0 | 0.09 | 0.01 | 50 | 50.006149827589745 48 | 22 | 0.09 | 0.01 | 50 | 50.00378023237334 49 | 66 | 0.09 | 0.01 | 50 | 50.007290786978416 50 | 34 | 0.09 | 0.01 | 50 | 50.00056022030347 51 | 74 | 0.09 | 0.01 | 50 | 50.00638723914476 52 | 95 | 0.09 | 0.01 | 50 | 50.007043480245116 53 | 78 | 0.09 | 0.01 | 50 | 50.000835732376615 54 | 3 | 0.09 | 0.01 | 50 | 50.00492664579969 55 | 85 | 0.09 | 0.01 | 50 | 50.0055832735501 56 | 98 | 0.09 | 0.01 | 50 | 50.00069012074435 57 | 84 | 0.09 | 0.01 | 50 | 50.00311092699821 58 | 44 | 0.09 | 0.01 | 50 | 50.00211598464375 59 | 68 | 0.09 | 0.01 | 50 | 50.00980213460893 60 | 25 | 0.09 | 0.01 | 50 | 50.000213922580144 61 | 11 | 0.09 | 0.01 | 50 | 50.00491783229052 62 | 16 | 0.09 | 0.01 | 50 | 50.00385799142445 63 | 84 | 0.09 | 0.01 | 50 | 50.00315243952117 64 | 8 | 0.09 | 0.01 | 50 | 50.00256690991191 65 | 90 | 0.09 | 0.01 | 50 | 50.002797358413225 66 | 45 | 0.09 | 0.01 | 50 | 50.00457478193562 67 | 77 | 0.09 | 0.01 | 50 | 50.00018115160071 68 | 25 | 0.09 | 0.01 | 50 | 50.007349523094966 69 | 65 | 0.09 | 0.01 | 50 | 50.001488573852114 70 | 93 | 0.09 | 0.01 | 50 | 50.0075771417218 71 | 37 | 0.09 | 0.01 | 50 | 50.0066571961394 72 | 87 | 0.09 | 0.01 | 50 | 50.00480149092147 73 | 23 | 0.09 | 0.01 | 50 | 50.00569788662592 74 | 94 | 0.09 | 0.01 | 50 | 50.00415552203464 75 | 93 | 0.09 | 0.01 | 50 | 50.002042239062405 76 | 69 | 0.09 | 0.01 | 50 | 50.00659559667872 77 | 65 | 0.09 | 0.01 | 50 | 50.00858634168854 78 | 35 | 0.09 | 0.01 | 50 | 50.004245405616565 79 | 56 | 0.09 | 0.01 | 50 | 50.005895444411436 80 | 23 | 0.09 | 0.01 | 50 | 50.00710996591808 81 | 35 | 0.09 | 0.01 | 50 | 50.00655347804682 82 | 16 | 0.09 | 0.01 | 50 | 50.00649347589736 83 | 1 | 0.09 | 0.01 | 50 | 50.0028453545188 84 | 22 | 0.09 | 0.01 | 50 | 50.00516821142212 85 | 12 | 0.09 | 0.01 | 50 | 50.00156739277321 86 | 32 | 0.09 | 0.01 | 50 | 50.00520623376633 87 | 21 | 0.09 | 0.01 | 50 | 50.00239659550629 88 | 32 | 0.09 | 0.01 | 50 | 50.00663612351142 89 | 9 | 0.09 | 0.01 | 50 | 50.00020650827494 90 | 62 | 0.09 | 0.01 | 50 | 50.008316709037935 91 | 37 | 0.09 | 0.01 | 50 | 50.00328408974682 92 | 98 | 0.09 | 0.01 | 50 | 50.008635831213816 93 | 85 | 0.09 | 0.01 | 50 | 50.00747649345121 94 | 34 | 0.09 | 0.01 | 50 | 50.005888321085465 95 | 45 | 0.09 | 0.01 | 50 | 50.00259685294329 96 | 35 | 0.09 | 0.01 | 50 | 50.001741489475876 97 | 16 | 0.09 | 0.01 | 50 | 50.00261103814009 98 | 87 | 0.09 | 0.01 | 50 | 50.00848172675686 99 | 98 | 0.09 | 0.01 | 50 | 50.00741565325358 100 | 20 | 0.09 | 0.01 | 50 | 50.00501197001834 (100 rows)
Результаты расчета коэффициентов корреляции в PostgreSQL
Корреляция между столбцами n1-n2 (Разница между величинами ~3 порядка, одна величина - константа)
SELECT corr( n1 , n2 ) FROM test ;
corr
-----------------------
-0.009999684804104647
(1 row)
Корреляция между столбцами n1-n3 (Разница между величинами ~3 порядка, одна величина - константа)
SELECT corr( n1 , n3 ) FROM test ;
corr
-----------------------
-0.020890460418644157
(1 row)
Корреляция между столбцами n1-n4 (Cлучайная величина и константа одного порядка)
SELECT corr( n1 , n4 ) FROM test ;
corr
------
(1 row)
Корреляция между столбцами n1-n5 (Случайные величины одного порядка)
SELECT corr( n1 , n5 ) FROM test ;
corr
-----------------------
-0.008818762482844123
(1 row)
Результаты расчета коэффициентов корреляции в Excel - числовой тип , 15 символов после запятой
Корреляция между столбцами n1-n2 (Разница между величинами - ~3 порядка)


Корреляция между столбцами n1-n3 (Разница между величинами - ~3 порядка)


Корреляция между столбцами n1-n4 (Cлучайная величина и константа одного порядка)


Корреляция между столбцами n1-n5 (Случайные величины одного порядка)


Сравнение расчетов коэффициентов корреляции в PostgreSQL и Excel
Разница между величинами ~3 порядка
Нулевое значение корреляции - при расчете с помощью Excel.
Ненулевое значение - коэффициента корреляции при расчете с помощью PostgreSQL.
Cлучайная величина и константа одного порядка
Отсутствие корреляции при расчете с помощью Excel и PostgreSQL.
Случайные величины одного порядка
Разница в расчете коэффициента корреляции между значениями полученными с помощью Excel и PostgreSQL = 0,000000000002502
Дополнительная информация по расчету коэффициента корреляции для столбцов n1-n2 , n1-n3(Разница между величинами ~3 порядка, одна величина - константа)
В описанном сценарии (разница значений одной величины превышает 2-3 порядка, а вторая величина постоянна) коэффициент корреляции Пирсона будет неопределен (NaN - Not a Number) или, в некоторых реализациях, может быть возвращен как 0.
1.Суть коэффициента Пирсона: Он измеряет линейную связь между двумя изменяющимися величинами. Его формула основана на ковариации двух переменных, деленной на произведение их стандартных отклонений:
r = cov(X, Y) / (σ_X * σ_Y)
2.Проблема с постоянной величиной: Если одна из величин (допустим, Y) постоянна (все ее значения одинаковы), то:
Стандартное отклонение σ_Y = 0: Поскольку нет никакой вариации значений вокруг среднего.
Ковариация cov(X, Y) = 0: Ковариация измеряет, как совместно отклоняются величины от своих средних. Постоянная величина Y никогда не отклоняется от своего среднего (которое равно любому ее значению), поэтому cov(X, Y) всегда будет равна 0, независимо от того, как ведет себя X.
3.Деление на ноль: Формула коэффициента корреляции Пирсона превращается в:
r = 0 / (σ_X * 0) = 0 / 0
Деление на ноль (σ_Y = 0) математически не определено. Это основная причина, почему коэффициент не может быть рассчитан.
4. Почему неважен масштаб изменений X: Даже если значения X варьируются на 2, 3, 10 порядков (т.е., σ_X очень велико), это не спасает ситуацию. В числителе формулы ковариация все равно будет 0 (потому что Y не меняется), а в знаменателе σ_Y все равно будет 0. Результат 0 / 0 остается неопределенным.
5. Практическая интерпретация в статистических пакетах:
NaN (Not a Number): Большинство статистических программ (R, Python с библиотеками типа pandas, scipy, numpy) вернут NaN при попытке рассчитать корреляцию, если одна из переменных постоянна. Это корректное математическое представление неопределенности.
0: Некоторые очень простые реализации или скрипты могут вернуть 0, так как ковариация равна 0. Однако это технически неверно. Нулевая корреляция подразумевает отсутствие линейной связи между двумя изменяющимися величинами. Здесь же одна величина вообще не изменяется, поэтому говорить о связи ее изменений с изменениями другой величины бессмысленно. Состояние "постоянная величина" принципиально отличается от состояния "величина есть, но не коррелирует".
Итог:
Математически: Коэффициент корреляции Пирсона не определен (NaN), так как в его формуле происходит деление на ноль (стандартное отклонение постоянной величины равно 0).
Концептуально: Корреляция измеряет согласованность изменений двух величин. Если одна величина не изменяется, понятие "корреляция ее изменений с изменениями другой величины" лишено смысла.
На практике: Ожидайте результат NaN (или, реже и менее корректно, 0) при расчете в статистическом ПО.
Очень простой пример проблемы расчета коэффициента корреляции в PostgreSQL
WITH dataset AS ( SELECT x, 0.09 AS y FROM generate_series(0, 100) AS x) SELECT corr(x, y) FROM dataset;
Результат расчета коэффициента корреляции в PostgreSQL
$ psql psql (17.5) Type "help" for help. postgres=# WITH dataset AS ( postgres(# SELECT x, 0.09 AS y postgres(# FROM generate_series(0, 100) AS x postgres(# ) postgres-# SELECT corr(x, y) FROM dataset; corr -------------------- 0.9501367579819386 (1 row) postgres=#
