2021. 7. 4. 15:44 ㆍ개발 이야기/python
안녕하세요 해커의 개발일기 입니다.
오랫만에 글을 쓰게 되었는데요. 요즘은 경제학 공부에 빠져있는 관계로 .. 다른 것들이 아무것도 눈에 들어오지가 않았습니다 ㅜㅜ.. 죄책감에 이번주에는 꼭! 블로그 업데이트를 해야지! 라는 생각으로 TODO List에 적어놨던 주제를 꺼냈습니다.
오늘은 COVID-19 확산 지표와 교통 통계량 데이터를 이용해서 회귀분석을 하는 과정을 가시적으로 보여드리겠습니다.
요즘 핫한 키워드가 무엇이 있는지를 논하게 되면 단연코 데이터 분석 이야기를 안할 수가 없는데요. 데이터 분석을 통해 새로운 비지니스 모델을 찾기도 하고, 새로운 마케팅 방법을 찾기도 하는 등 기업 이익에 상당히 다양하게 일조를 할 수 있는 것이 데이터 분석이 아닌가 싶습니다. 하지만, 아쉽게도 데이터 분석을 함에 있어서 통계 지식이 없이 검색하면 나오는 알고리즘을 가지고 input, output만을 보게 된다면 정말 심각하게 엉뚱한 결과를 뽑아낼 수도 있기 때문에, 어느정도 통계학 지식을 쌓고 나서 데이터 분석 작업을 하는 것을 추천해드립니다.
오늘은 통계 기반의 데이터 분석 과정을 통해서 어떤 순서와 방법으로 다양한 데이터를 통해 의미있는 결과를 도출해 낼 수 있는지 알아보겠습니다.
먼저, 순서는
- COVID-19와 교통량 csv 데이터의 기술통계량 확인
- 상관계수 확인 및 다중공선성 문제 해결
- Ordinary Least Squares(최소제곱법) 회귀분석 결과 확인
데이터 분석에서 어쩌면 가장 중요할 수 있는 데이터 전처리 부분이 순서에는 빠져있는데요. 이유는 데이터 수집과 전처리는 어느 데이터를 사용하느냐에 따라 개발자의 역량에 따라, 데이터 분석자의 역량에 따라 상당히 수준차이도 생기고 의견도 갈리기 때문에 제외했습니다.
해당 블로그에서 사용한 데이터는 교통량 데이터와, COVID-19 데이터를 사용했으며, 출처는 아래와 같습니다.
- 교통량 데이터 : http://data.ex.co.kr
- COVID-19 현황 데이터 : https://github.com/jooeungen/coronaboard_kr
데이터를 위의 경로에서 수집하고 컴활 1급을 취득했던 기억을 더듬어 파워풀한 툴인 엑셀을 이용해서 데이터 전처리를 하고 하나의 시계열 데이터로 가공을 했으며, 확진자 수를 이용해 확진자 증감율 등을 뽑아내는 등의 파생 변수를 몇 가지 추가했습니다.
먼저, pandas를 이용해 1. COVID-19와 교통량 csv 데이터의 기술통계량을 확인해보겠습니다.
# pip install pandas
# pip install dataframe-image
import dataframe_image as dfi
import pandas as pd
def descriptive_statistics():
data = pd.read_csv('./rawdata/totally_raw_data_delete_expression.csv')
statistic_data = []
col = ["한글 변수명", "영문 변수명", "N", "평균", "표준편차", "최솟값", "최댓값"]
for key in data.keys():
if key == 'date':
continue
statistic_data.append([
hangul_mapper.get(key),
key,
data[key].__len__(),
round(data[key].mean(), 2),
round(data[key].std(), 2),
round(data[key].min(), 2),
round(data[key].max(), 2)])
statistic_df = pd.DataFrame(statistic_data, columns=col)
........
날짜를 뜻하는 date 변수를 제외한 모든 변수들의 평균 표준편차, 최대/소값을 뽑아주는 코드이며, 결과는 아래와 같습니다.
기술 통계량의 경우는 이런 값들을 가진 데이터가 있다를 보여주는 데이터 특성을 파악할 때 사용하는 것으로 필요에 따라 사분위, 분산 등을 추가로 넣을 수 있습니다.
다음은, 상관계수 확인 및 다중공선성 문제 해결 단계입니다. 상관계수는 독립변수들 간의 상관 관계의 정도를 수치적으로 나타는 계수이며 1 ~ -1 사이의 값을 가지며 1에 가까우면 양의 상관 관계로 변수가 증가함에 따라 함께 증가하는 상관관계를 뜻하며, -1에 가까우면 음의 상관 관계로 변수가 증가함에 다라 감소하는 음의 상관관계를 뜻합니다. 0에 가까울수록 상관된 정도가 적음을 의미합니다.
독립변수 중에 상관관계가 깊은 독립변수가 많은 경우 회귀 분석 결과의 정확도에 부정적인 영향을 미칠 수 있기 때문에 다중공선성 문제를 해결하고 회귀분석을 진행해야 조금 더 유의미한 결과를 도출할 수 있습니다.
날짜와 교통량 독립변수를 제외한 독립변수들의 상관계수를 도출해 보겠습니다.
# 피어슨 상관계수 히트맵
def calc_correlation(data):
# https://mindscale.kr/course/basic-stat-python/6/
# 차종별 교통량 제거, 날짜 제거
drop_unnecessary_data = data.drop(['sm_tp1_t',
'sm_tp2_t',
'sm_tp3_t',
'sm_tp4_t',
'sm_tp5_t',
'sm_tp6_t',
'date'], axis=1)
corr = drop_unnecessary_data.corr()
sns.heatmap(corr, cmap='viridis')
plt.savefig('image/9_상관계수_heatmap.png')
plt.close()
히트맵 형태로 출력해서 확인해본 결과입니다. 노란색에 가까울수록 양의 상관관계를 진항 파란색에 가까울 수록 음의 상관관계를 나타냅니다.
다음은 다중공선성 문제를 확인하기위해 VIF(Variance Inflation Factors) 분산팽창요인을 확인해보겠습니다.
def check_vif(data):
# https://nonmeyet.tistory.com/entry/Python-Pvalue-VIF-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0-Linear-regression
# 모든 독립변수
y, x = dmatrices("sm_tot_t ~" + features, data=data, return_type="dataframe")
# 보통 10이 넘으면 문제가 있다고 판단
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(x.values, i) for i in range(x.shape[1])]
vif["features"] = x.columns
dfi.export(vif.round(1), 'image/7_1_check_VIF.png')
vif.to_csv('image/7_1_check_VIF.scv')
# 다중공선성 제거 변수 테스트
y, x = dmatrices("sm_tot_t ~" + features_fixed, data=data, return_type="dataframe")
# 보통 10이 넘으면 문제가 있다고 판단
vif = pd.DataFrame()
vif["VIF Factor"] = [variance_inflation_factor(x.values, i) for i in range(x.shape[1])]
vif["features"] = x.columns
dfi.export(vif.round(1), 'image/7_2_check_VIF_fixed.png')
vif.to_csv('image/7_2_check_VIF_fixed.scv')
보통 수치가 10을 넘어가게되면 문제가 있다고 판단하여 해당 값과 연관된 독립변수를 제거해나갑니다. inf 값은 infinity(무한대)를 나타내는 것으로 관련 VIF Factor 문제가 있는 독립변수들을 제거해 보겠습니다.
Intercept를 제외한 독립변수들의 VIF Factor를 10 미만이 되도록 연관 독립변수를 제거했습니다. 분산팽창요인을 제거한 것과 제거하지 않은 독립변수들을 이용해 회귀 결과가 어떻게 달라지는지 확인해보겠습니다.
마지막으로, Ordinary Least Squares(최소제곱법) 회귀분석 결과 확인 과정을 보겠습니다.
def regression_analysis(data):
kind = ['tp1', 'tp2', 'tp3', 'tp4', 'tp5', 'tp6', 'tot']
for v in kind:
y, x = dmatrices("sm_" + v + "_t ~" + features, data=data, return_type="dataframe")
result = sm.OLS(y, x).fit()
plt.rc('figure', figsize=(9, 8))
plt.text(0.01, 0.05, str(result.summary2()), {'fontsize': 10},
fontproperties='monospace')
plt.axis('off')
plt.tight_layout()
plt.savefig('./image/10_회귀분석' + "_" + v + '.png')
plt.close()
y1, x1 = dmatrices("sm_" + v + "_t ~" + features_fixed, data=data, return_type="dataframe")
result1 = sm.OLS(y1, x1).fit()
plt.rc('figure', figsize=(9, 8))
plt.text(0.01, 0.05, str(result1.summary2()), {'fontsize': 10},
fontproperties='monospace')
plt.axis('off')
plt.tight_layout()
plt.savefig('./image/10_회귀분석' + "_" + v + '_다중공선성_제거.png')
plt.close()
다중공선성을 제거한 독립변수들을 이용한 회귀분석과, 다중공선성을 제거하지 않은 독립변수들을 이용한 회귀분석 결과를 비교해보겠습니다.
먼저, 다중공선성을 제거하지 않은 회귀분석 결과를 확인해보겠습니다. 신규 확진자를 나타내는 i_nw_confirm 독릭변수의 회귀계수를 보면 -값으로 신규확진자가 1명 늘면 교통량이 17851 감소한다는 결과를 확인할 수 있습니다. 마치, 언뜻 생각하기에는 옳바른 결과라고 생각할 수 있는 결과이지만, 실제 결과와는 상반되었습니다. 이어서 다중공선성을 제거한 결과를 확인할 후에 최종 결과를 도출해보겠습니다.
다중공선성 문제를 해결한 회귀결과 입니다. 신규확진자수 독립변수와 교통량의 관계가 양의 상관관계를 갖는 것을 확인할 수 있으며, 확진자가 1명 증가함에 따라 교통량이 3921대 증가한다는 것을 확인할 수 있습니다.
이 처럼, 다중공선성 문제를 해결하느냐, 아니냐에 따라 전혀 상반된 결과를 도출할 수가 있었습니다.
실제는 어땠을까요? 확진자가 증가함에 따라 사람 간의 접촉을 피하기 위해 출 퇴근시, 자차를 이용하는 사람의 수가 증가 했으며, 확진자가 늘어남에 따라 COVID-19 검사를 위해 이동 시 드라이브스루 검사소를 이용을 권고했기 때문에 오히려 교통량이 증가했던 것을 확인할 수 있었고, COVID-19 사태가 오래 지속될수록 오히려 상관 계수의 0에 가까워지는 것을 확인할 수가 있었습니다.
위와 같이, COVID-19 데이터와 교통량 데이터를 이용해 회귀분석을 하는 절차에 대해서 간략히 보여드렸으며, 통계 기반의 지식이 없다면 결과를 도출했어도 정상적으로 해석을 하지 못하는 결과가 생길 수 있기 때문에, 꼭 통계 기초를 공부하시는 것을 추천해드립니다.
다음으로는 다양한 회귀 모델을 손쉽게 테스트할 수 있는 LazyPredict에 대해 알아보도록 하겠습니다.
'개발 이야기 > python' 카테고리의 다른 글
OpenTelemetry Python Asyncio 지원 (0) | 2024.03.30 |
---|---|
# PYTHON PANDAS 특정 행 이하 제거 (1) | 2021.11.11 |
# anaconda 64bit 설치 후 32bit python 사용하기 (0) | 2020.09.02 |
비동기 B2C 서버 구축하기 - Gunicorn, Celery, rabbitMQ (7) | 2019.11.23 |
보안뉴스(boannews.com) 크롤러 텔레그램 연동 (0) | 2019.09.05 |