피어슨 상관계수 - Pearson's product-moment correlation

개요

연속형 변수 2개의 상관 관계를 확인하기 위한 가장 기본적인 방법이다.

정확히 말해서 두개의 수치값들의 집합이 있을 때 이 두개의 수치값들은 각각의 순서쌍에 대해서 연결관계가 있다고 할 때 두 수치값이 서로 관련이 있는지를 확인하는 방법이다.

흔한 예로 있는 것이 고등학생 한 학급에 50명이 있다고 할 때 이 학생들의 수학과목의 성적과 물리과목의 성정이 관련이 있는지 확인하는 것이 있다. 즉 수학과목과 물리과목은 서로 수리적 또는 과학적 능력과 관련이 있어 두 과목은 서로 관련이 있을 것이라는 가설을 어느 정도 두고 있으며 실제로 그런지 확인한다.

피어슨의 상관계수는 그런 방법중에 가장 기본적인 방법이며 그 외에도 여러가지 상관방법이 있다.

피어슨 상관계수는 두 변수의 결합은 정규분포일 것이라는 가정이 포함되어 있으며 구조적으로 볼 때 이상치(outlier)에 매우 민감한 편이다.

주의할 것은 결과를 보고 상관관계가 인과관계와 관련이 있을 것이라는 확대해석을 하지 말아야하며 단순하게 두 변수가 연관성이 있다로만 결론을 내려야 한다는 것이다.

사용시 주의점

두 변량(변수, variable, variance)이 정규성(normality)을 따를 때 대해 최적화된 방법이므로 정규성 문제에서 자유롭지는 않다. 쉽게 예를 통해 말해보면 피어슨 상관계수는 두 변수가 정규분포여야 한다는 전제를 두지는 않지만 원래 피어슨 상관계수는 정규분포에서 가장 잘 작동하도록 설계되었다고 한다. 위의 예에서 수학성적과 물리성적은 모두 정규분포여야 더 정확한 결과를 얻을 수 있다.

변량이 정규분포가 아닌 경우에도 사용할 수는 있으나 결과값이 달라질 가능성이 커서 오해석을 할 수 있다.

편차의 곱들이 정규분포를 따르지 않으면 오해석을 만드는 이상치(outlier)에 예민한 문제가 있다.

인과관계를 증명하지 않으므로 결과를 인과관계로 확대해석하는 것을 항상 경계해야한다.

가설검정을 수행해서 반드시 p-value를 확인해야 한다. 하지만, 그 결과를 무조건 신뢰하지는 않아야 한다.

이상치(outlier)에 매우 민감하므로 데이터를 트랜스폼 하거나 다른 기술을 보조방법으로 확인해야 할 수 있다.

20개 이상의 데이터 포인트에 대해서 수행한다면 데이터가 정규분포를 따르게 만들거나 아웃라이어를 확실하게 처리해야함

후속 작업(인과 관계 증명)이 필요하면 regression test를 수행할 것 Intermittent 문제에서 매우 자유롭지 않음 결측치가 많거나 0이 많은 데이터에 대해서는 바로 사용하기 어려움 결측치를 채우고 0의 문제를 해결해 주어야 하는데 그렇게 하기 어렵다면 사용하지 않아야 함 쉽게 사용할 수 있으나 쉽게 해석하지는 말것 부연 설명 기본은 두 확률 변수(variable)가 서로 독립인지 아닌지를 확인하는 것인데 각각의 변수의 평균에서의 분산의 방향과 양을 서로 곱하고 합산하여(product) 적률(moment)로 독립성을 검정하는 것이다. 아웃라이어에 굉장히 예민하며 계산에 대한 최적(optimum)이 정규분포를 가정으로 되어 있어 결국 두 변수가 정규분포가 아닌 경우 또는 두 변수의 편차의 곱이 정규분포를 따르지 않으면 제대로 해석을 할 수 없다고 알려져 있다. 가장 기본이 되는 유사도 검정 방법이긴 하지만 여러가지 위험성 때문에 최근에는 많은 데이터 사이언티스트들은 직접 사용하는 것을 기피하는 경향이 강해지고 있다.

관련 기법

  • Data Transformation: 정규분포로 변환
  • 0값 또는 NULL값에 대한 보정
  • Outlier reduction or Influential reduction: outlier 제거 또는 무력화, 0값 보정 및 무력화
  • Bootstrapping: 편추정에 대한 방지
  • Cook’s distance: outlier 무력화

사용예

횡단면 데이터(cross-sectional) 또는 시계열 데이터(time-series)에 대해서 모두 사용할 수 있음 클릭과 컨버전과의 상관관계등을 구하는데 사용할 수 있다.

각 업종 카테고리들의 지표들(conversion, click, impression)의 상호연관관계

기타 모든 연속형 변수에 대해서 상호연관성이 있는지 확인 가능

참조 코드

비율 데이터와 양적 데이터에 대한 correlation의 반응 결과 시뮬레이션 ※ outlier의 존재 및 영향력에 따라 correlation의 결과가 크게 차이가 발생함을 확인

a <- rnorm(100, mean= 50, sd = 20)
b <- rnorm(100, mean= 2000, sd = 500)
c <- rnorm(100, mean= 120000, sd = 1500)
# 위의 세 변수는 정규분포에 의한 랜덤으로 서로 연관성이 없어야 함
 
paste(a, sep = "", collapse = ", ")
paste(b, sep = "", collapse = ", ")
paste(c, sep = "", collapse = ", ")
 
# 변수가 랜덤이므로 재현을 위해서 값을 기록해 둔다
# > paste(a, sep = "", collapse = ", ")
# [1] "43.5352862922437, 26.1142486253874, 83.0310075589865, 52.6120387834526, 79.0516784036759, 78.4067982054003, 49.062183315655, 33.9101133704574, 52.6453876117853, 22.5639577719374, 28.0566952588897, 58.3170898964112, 79.7531506969863, 16.4651442095427, 21.8266199445677, 84.7613164971811, 22.9314362586294, 57.2546573845694, 70.1072978856087, 69.5434626894672, 30.0281312105167, 51.331326846718, 37.7918517827927, 31.2858007434158, 16.1322596624448, 75.2985738809986, 12.5749486008556, 35.7921600656511, 64.806317406061, 62.977130791631, 47.3643715031428, 59.9356881188637, 21.6271869042728, 62.7203715153795, 65.4173808852516, 45.6678158936037, 65.4652627799009, 64.8256029810552, 59.5570284027551, 69.6764444112485, 58.5164575206365, 62.004266803614, 97.706433122476, 64.1470814021714, 41.8597076539052, 43.5156462394562, 14.5280461758878, 39.2917202512866, 80.7933545904295, 38.6129906668388, 40.3837831017038, 35.2616689131153, 34.003282142012, 68.7359333785656, 55.0633600450313, 54.1745798049531, 69.0118780703161, 53.4504373550242, 60.2301640760341, 9.7890658404699, 63.6178737287274, 29.5732275213378, 48.7588587666721, 40.5156753816904, 54.9906332676469, 32.4814706691121, 56.7982092746807, 55.1773169970468, 27.9953889016393, 35.4516456284645, 63.5454475487725, 75.9599618444786, 65.2507265886765, 33.9459834762341, 61.321763995156, 89.8059423687934, 84.6565172745663, 0.974251609395807, 35.1188518010291, 17.8961452288911, 84.213912723524, 33.9900156697055, 42.4386576418562, 59.4614633600509, 59.0355532878133, 51.9481361012289, 68.0797928653874, 72.1110911014688, 41.1499727814911, 75.2279481537229, 49.0997788926431, 63.3516617832293, 61.1487670634223, 27.6280479420989, 48.7997440672988, 82.448020715588, 65.9171002410758, 55.0521463374323, 68.8948953658392, 69.3871761692264"
# > paste(b, sep = "", collapse = ", ")
# [1] "1251.43332438274, 2342.37972353621, 2220.80372569032, 1895.67202861517, 2014.5484405777, 2376.00314439979, 2336.35697930541, 1654.00823520994, 1888.83098639829, 1181.60965560807, 1863.61920533526, 1481.15256643624, 1932.44372641792, 3055.92690257731, 1840.26793824745, 2208.60973931844, 1956.12542134589, 1631.76325719419, 2697.95727176067, 2429.20779820604, 2044.27327059926, 2371.31062184623, 2220.10184966659, 2139.39804535137, 1756.26740295561, 2259.86757217339, 1848.86774247112, 2463.81430642305, 2624.75885609224, 1778.54253932097, 1489.35179681014, 2891.55868135022, 1872.90871459947, 2399.44865358388, 2456.8524870807, 2741.75205825754, 3582.09350773464, 2900.74890621652, 2255.54297302259, 2667.33190357123, 1861.96324722154, 1884.02035899016, 3100.01143764508, 2022.4206226856, 2225.53778549019, 2635.82735842111, 1392.77415237051, 1305.97461470831, 1819.42159875603, 546.128677126583, 1457.97600776047, 2038.04094488796, 1652.43305615482, 1811.76409711056, 2611.6019475432, 2047.23886211447, 2202.41466500911, 1938.12732690756, 3018.09112950321, 2298.85390764845, 1371.98741043772, 1632.41914032878, 1512.07582044162, 2223.24185250764, 2823.81014669429, 1398.71033086321, 2440.25530481094, 1697.44725081322, 2529.9849209169, 1274.26673394536, 2538.96781338355, 2331.50749699991, 2531.01232864703, 2220.65705963555, 2436.36788346162, 2242.26168556345, 1684.61342059638, 2329.11879273551, 1794.99394056369, 1919.0816337302, 2063.6757595704, 3062.90035919268, 1754.96734557443, 1619.4821990434, 2726.76973077111, 2250.17607892164, 1864.44859264195, 2189.37654054184, 2512.62977050847, 1720.94990563809, 2088.27335020036, 2140.7877964509, 2210.3252937194, 1498.67647300586, 2900.34433448942, 2063.12406537933, 2567.97957458864, 1715.31375194128, 2962.83772029732, 2063.67912368279"
# > paste(c, sep = "", collapse = ", ")
# [1] "119251.740829297, 121454.749783168, 119322.863576464, 119625.053964249, 118777.133824213, 118886.263077579, 119452.106801154, 120852.422342105, 119878.777784741, 118744.994769308, 120485.993860488, 120900.993782886, 120029.694154418, 121873.759886909, 120103.095492903, 120464.566449077, 120413.950098949, 117675.521438293, 119369.593090079, 120240.848827266, 117719.926402129, 119937.608402987, 122204.395391432, 120046.437974128, 122030.752192869, 121758.319405922, 117695.944113387, 123573.943065106, 118291.406750377, 121223.526386357, 118517.552204085, 120807.901347187, 120621.001457778, 119475.47666331, 120242.292401057, 118921.238554979, 117521.086798667, 119578.721701939, 120911.304811968, 118703.778719702, 118788.362258785, 121556.481938474, 121028.947546723, 120985.485978974, 119249.785631828, 119058.080743588, 119660.567571029, 120534.219899411, 117111.884018716, 123267.794308878, 119786.970340605, 118413.811192198, 119009.253977222, 121819.638219391, 119700.137016435, 118591.023956261, 122084.292027088, 119312.936762931, 121054.04369525, 120441.609939599, 121026.397702518, 116540.245700406, 119952.566365456, 120310.313070646, 119499.52373053, 120397.564444098, 117148.951314992, 120480.029627339, 117264.617694825, 119973.696770688, 119083.964353884, 121199.805482649, 119799.284366371, 118761.546380338, 120774.208993894, 119938.635449809, 119953.469476303, 120705.658029756, 120433.900638267, 122404.092031616, 119370.262687362, 121592.496711847, 118925.505900191, 120272.407880099, 117654.657686838, 121295.025688249, 120741.271142659, 119270.308179925, 119029.993677834, 120957.591449431, 119201.571359284, 118571.767581187, 119661.859738992, 116945.538167552, 119312.891068774, 117398.409506805, 119068.847553957, 118553.244590584, 121318.583080948, 119410.618012882"
 
 
# 3번째 변수로 1번째, 2번째 변수를 나눠서 비율값으로 만든다.
# 분모가 같으므로 a와 b 그리고 a.rate와 b.rate는 상관계수가 거의 비슷해야 한다.
a.rate <- a/c
b.rate <- b/c
 
# plotting
par(mfrow=c(2, 1))
plot(a, b, pch=20)
plot(a.rate, b.rate, pch=20)
dev.off()
 
 
# install.packages("asbio")
library(asbio)
cor(a, b)  # correlation
cor(a.rate, b.rate)  # correlation with transformed variables
r.pb(a, b, beta = 0.2)  # percentage-bend correlation
r.pb(a.rate, b.rate, beta = 0.2)  # percentage-bend correlation with transformed variables
cor(a, b, method = "spearman")  # Spearman's correlation
 
# hypothesis test
cor.test(a, b)
cor.test(a.rate, b.rate)
cor.test(a, b, method = "spearman")  # hypothesis tset
 
# bootstrapping
library(boot)
cor.stat <- function(data, indices) {
  cor(data[indices, 1], data[indices, 2])
}
boot.output <- boot(data=cbind(a, b), cor.stat, R=100000)
(boot.output)
par(mfrow=c(1, 1))
hist(boot.output$t, nclass=32)
dev.off()
 
 
# responsibility test on outliers
# 정규분포에서의 랜덤으로 element가 10개인 변수 3개를 만들되 하나의 element는 outlier를 강제로 넣어준다.
# 첫번째 element에 outlier를 넣었으므로 outlier에 영향을 받는다면 상관계수가 매우 높게 나타날 것이다.
a1 <- c(100, rnorm(9, 5, 9))
b1 <- c(200, rnorm(9, 5, 9))
c1 <- c(500, rnorm(9, 50, 9))
paste(a1, sep = "", collapse = ", ")
# [1] "100, -17.8877517498719, 1.65010536316145, 10.8981253085614, -0.536608019252361, 0.368470776596632, 14.6682762969186, -10.6227685949784, 7.03189390859778, 14.9138302131459"
paste(b1, sep = "", collapse = ", ")
# [1] "200, -3.42021229405049, 0.877706007815157, -4.52919961063207, 19.5994542345915, 11.9415248662197, 10.7128587235155, 9.79371410533467, 22.8992163078861, -2.04341531240663"
paste(c1, sep = "", collapse = ", ")
# "200, -3.42021229405049, 0.877706007815157, -4.52919961063207, 19.5994542345915, 11.9415248662197, 10.7128587235155, 9.79371410533467, 22.8992163078861, -2.04341531240663"
 
cor(a1, b1)  # 상관계수가 클 것이다.
cor(a1/300, b1/300)  # 하나마나 한 짓이다.
cor(a1[2:10], b1[2:10]) # 상관계수가 낮을 것이다. outlier를 제거했으므로
cor(a1/c1, b1/c1)  # 상관계수가 작을 것이다. outlier를 무력화 했으므로
 
# 위의 결과를 각각 확인해 보면 비율인 경우 outlier의 영향을 줄이는 것을 볼 수 있지만 그렇지 않은 경우 outlier에 의해서 상관관계가 매우 높게 나타난다.
 
# Et cetera
cor(a1/b1, b1/b1)  # 하나마나한 것
cor(a1/(a1+b1), b1/(a1+b1))  # 하나마나한 것
 
# outlier checking with Cook's distance
library(MASS)
m1 <- lm(a ~ b)
plot(cooks.distance(m1))
# cook's distance로 outlier를 찾아낼 수 있다.
 
m1 <- lm(a1 ~ b1)
plot(cooks.distance(m1))

참고자료

https://ko.wikipedia.org/wiki/%EC%83%81%EA%B4%80%EB%B6%84%EC%84%9D