파이썬 상관계수 구하기, 방법과 의미는?!

2021. 11. 2. 10:33

상관 계수는 두 변수 사이의 직선 관계를 나타내는 지표이다. 산점도를 통해서 대략적인 관계를 파악할 수 있지만 객관성이 부족하다.
그래서 두 변수 사이의 관계를 수리적인 방법으로 표현하는 방법을 찾게 된다. 이러한 방법이 상관 계수를 구하는 것이다.

 

파이썬에서 상관계수를 구하는 방법은 여러가지가 있다. statsmodel의 corr함수를 이용해도 되고, 판다스 dataframe에서 corr함수를 이용할 수도 있다.


오늘은 파이썬에서 상관계수(correlation-coefficient)를 구하는 방법을 알아보고, 생산자물가지수와 소비자 물가지수의 상관 관계를 알아보도록 하겠다.

 

 

파이썬 상관계수

 

 

1. 상관계수(correlation)의 의미

상관계수는 -1과 1사이의 값으로, 절대값의 크기는 직선관계에 가까운 정도를 나타낸다. 양수일 때는 하나의 값이 증가할 때 다른 변수의 값도 증가하는 관계, 음수일 때는 하나의 값이 증가하면 다른 변수의 값은 감소하는 관계를 나타낸다.

상관계수는 모집단의 상관계수를 구하는 방법이 있고, 표본을 통해서 모집단을 추정하는 방법 2가지가 있다 .

 

모집단 상관계수

 

표본 상관계수 (sample correlation coefficient)

 

 

2.  scipy 패키지 이용하기

scipy 패키지는 여러가지 수학 알고리즘과 계산을 쉽게 할 수 있도록 도와주는 패키지이다. 여기서는 구할 수 있는 상관계수가 여러가지가 있다. 그 중에서도 가장 대표적인 피어슨 상관계수도 손 쉽게 구할 수 있다. 테스트를 하기 위해 상관관계가 아주 뚜렷한 임의의 넘파이 배열을 만들어 보았다.

import numpy as np

x = np.random.randint(0,100, 50)
y = x * 2

 

 

다음으로 아래와 같이 피어슨 상관계수를 구해 보았다.

from scipy import stats

stats.pearsonr(x, y)

[Out]: (1.0, 0.0)

 

 

앞에 값은 상관계수, 뒤에 값은 p-value이다. 예상한데로 양의 상관관계가 굉장히 높게 나온 것을 확인할 수 있었다.

 

 

3. 판다스 데이터프레임의 corr함수 이용하기

상관관계는 많이 사용하는 지표이기 때문에, 판다스 데이터프레임에서 직접 구할 수 있는 함수도 제공하고 있다.

판다스 데이터프레임 상관계수 구하기

 

 

구하는 방법도 pearson, kendall, spearman 3가지를 제공하고 있다. 사용방법은 어렵지 않다. 아래와 같이 그냥 corr()함수를 호출하면 된다.

import pandas as pd

df = pd.DataFrame({'x':x, 'y':y})
df.corr()

Out[1]: 
     x    y
x  1.0  1.0
y  1.0  1.0

 

 

그러면 위와 같이 상관관계 매트릭수가 출력된다.

 

 

4. 생산자 물가지수와 소비자 물가지수 간의 시차별 상관관계 구하기

아래와 같이 한국은행 API를 이용해서 데이터를 받은 후에, 시차별 상관계수를 구해 보았다.

# coding=utf-8
 
from urllib.request import urlopen
import pandas as pd
import matplotlib.pyplot as plt
 
 
import json
 
dif_month=1
 
def index_corr(produce_kr,consumer_kr,dif_month):
    num_del=produce_kr.index.max()-dif_month
    produce_kr_rel=produce_kr[produce_kr.index<=num_del]
 
    consumer_kr_rel = consumer_kr[consumer_kr.index >= dif_month]
    consumer_kr_rel=consumer_kr_rel.reset_index(drop=True)
 
    produce_kr_rel=produce_kr_rel.rename(columns={"DATA_VALUE":"produce_index"})
    consumer_kr_rel = consumer_kr_rel.rename(columns={"DATA_VALUE": "consume_index"})
 
    total=pd.concat([produce_kr_rel[["produce_index"]],consumer_kr_rel[["consume_index"]]],1)
 
    pd.scatter_matrix(total)
    print(str(dif_month)+"개월 상관계수:"+str(total.corr().iloc[0,1]))
 
    plt.figure()
    # plt.plot(produce_kr_rel.index,produce_kr_rel["produce_index"])
    # plt.plot(consumer_kr_rel.index, consumer_kr_rel["consume_index"])
 
    plt.scatter(total["produce_index"],consumer_kr_rel["consume_index"])
 
    return
 
if __name__ == "__main__":
    key =[자신의 인증키를 넣는다]
 
    # https://ecos.bok.or.kr/jsp/openapi/OpenApiController.jsp?t=guideServiceDtl&apiCode=OA-1040&menuGroup=MENU000004
    # 여기서 주소 만들면 쉽다.
    url="http://ecos.bok.or.kr/api/StatisticSearch/"+key+"/json/kr/1/1000/I02Y001/MM/201501/201805/?/?/?/"
    result = urlopen(url)
    html = result.read()
    data = json.loads(html)
    data=data["StatisticSearch"]["row"]
    produce = pd.DataFrame(data)
    produce_kr=produce[produce["ITEM_CODE1"]=="KOR"]
    # produce_kr=produce_kr.set_index("TIME")
    produce_kr["DATA_VALUE"]=produce_kr["DATA_VALUE"].astype("float")
 
    produce_kr["DATA_VALUE"].plot()
 
    produce_kr["TIME"] = produce_kr["TIME"].astype("int")
 
    # produce_kr["date"] = datetime.datetime(produce_kr["TIME"].str[0:4],produce_kr["TIME"].str[4:5])
    # produce_kr["date"] = produce_kr["TIME"].apply(lambda x: datetime.datetime.strptime(x, '%Y%m'))
 
    produce_kr["TIME"] = produce_kr["TIME"].astype("str")
    xlabel=produce_kr["TIME"]
    xlabel = xlabel.drop_duplicates()
 
    produce_kr=produce_kr.sort_values("TIME")
    produce_kr=produce_kr.reset_index(drop=True)
    produce_kr = produce_kr.reset_index()
 
    # plt.scatter(produce_kr["index"],produce_kr["DATA_VALUE"])
    # plt.xticks(produce_kr["index"], xlabel,rotation=70)
    #
    # plt.plot(produce_kr["index"],produce_kr["DATA_VALUE"])
    # plt.xticks(produce_kr["index"], xlabel,rotation=70)
 
 
    # 소비자 물가지수
    url="http://ecos.bok.or.kr/api/StatisticSearch/"+key+"/json/kr/1/1000/I02Y002/MM/201501/201805/?/?/?/"
    result = urlopen(url)
    html = result.read()
    data = json.loads(html)
    data=data["StatisticSearch"]["row"]
    consumer = pd.DataFrame(data)
    consumer_kr=consumer[consumer["ITEM_CODE1"]=="KOR"]
    # produoce_kr=produce_kr.set_index("TIME")
    consumer_kr["DATA_VALUE"]=consumer_kr["DATA_VALUE"].astype("float")
 
    consumer_kr=consumer_kr.sort_values("TIME")
    consumer_kr=consumer_kr.reset_index(drop=True)
    consumer_kr = consumer_kr.reset_index()
    #
    # plt.plot(cunsumer_kr["index"],cunsumer_kr["DATA_VALUE"])
 
    index_corr(produce_kr,consumer_kr,0)
    index_corr(produce_kr,consumer_kr,1)$
    index_corr(produce_kr,consumer_kr,2)
    index_corr(produce_kr,consumer_kr,3)
    index_corr(produce_kr,consumer_kr,4)
    index_corr(produce_kr,consumer_kr,5)
    index_corr(produce_kr,consumer_kr,6)
    index_corr(produce_kr,consumer_kr,7)
    index_corr(produce_kr,consumer_kr,8)
    index_corr(produce_kr,consumer_kr,9)
    index_corr(produce_kr,consumer_kr,10)

 

 

for문을 이용해서 약 1개월부터 10개월까지 시간 간격을 두고, 상관계수를 구해 보았다.

 

생산자물가지수와 소비자물가지수의 시차별 상관계수 값

 

 

2~3개월 간격의 시차를 두고 상관계수를 구하는 것이 가장 값이 높을 것이라는 예상했다. 하지만 예상과 달리 시차를 두지 않고 상관계수를 구하는 것이 가장 높았다. 즉 생산자물가지수와 소비자물가지수가 시차가 있다고 보기 어려웠다. 시기와 경제 상황에 따라 차이는 있을 것 같다.

 

 

이유는 알기 어렵지만 예전보다 유통의 단계가 급속도로 축소되고 있어서 그런 것은 아닐까 추측해본다. 마지막으로 생산자물가지수와 소비자물가지수를 시차없이 그린 sctter_matrix를 추가해본다.

 

scatter matrix

 

 

오늘은 이렇게 생산자물가지수와 소비자물가지수의 시차를 알아보기 위해 상관계수를 이용해보았다. 상관계수로는 두 지수의 시차를 확인하기는 어려웠다.

댓글()