티스토리 뷰

파이썬으로 회귀 분석을 수행하는 방법은 3가지가 있습니다.


1. 회귀식을 직접 코드로 작성하기

2. sklearn 라이브러리 사용하기

3. statsmodels 라이브러리 사용하기


회귀식은 매우 단순한 편이기 때문에 직접 데이터의 패턴을 분석하는 코드로 짜는 것도 어렵지 않습니다만,

이미 만들어져 있는 라이브러리를 사용하는게 편리하며, 작성한 코드를 검증하는 시간도 줄어드는 이점이 있어

라이브러리를 사용하여 예측할 것을 권유드립니다.


본 글에서는 3. statsmodels 라이브러리를 사용하여 회귀분석을 수행해보도록 하겠습니다.


분석순서는 다음과 같습니다.


1. 라이브러리 호출 

2. 데이터 불러오기

3. 데이터 전처리

4. 상관 분석 수행

5. 회귀 분석 수행






1. 라이브러리 호출

사용할 라이브러리를 호출합니다.

사용할 라이브러리는 pandas와 statsmodel입니다.


import pandas as pd

import statsmodel.api as sm






2. 데이터 불러오기

패턴을 살펴볼 데이터를 불러옵니다.

이론편에서는 키와 몸무게와 같은 간단한 예제로 설명을 드렸습니다.

실습편에서는 좀더 라이브한 데이터를 다뤄볼까 합니다.

주식데이터를 가지고 회귀분석을 해보도록 하겠습니다.

주식데이터는 네이버 금융에 있는 정보를 활용하고 

이를 위해 블로그(https://blog.naver.com/zakk81/221110640599)에 있는 코드를 참고하였습니다.

크롤링 코드에 대한 설명이 필요하신 분은 위 주소를 클릭하시면 됩니다.


#크롤링을 위해 추가적으로 라이브러리 호출

import numpy as np from pandas import Series, DataFrame import requests from bs4 import BeautifulSoup


#크롤링 코드

corp_code = '005930' #네이버 금융에 있는 기업코드 for page in range(1, 13): url_tmp = 'http://finance.naver.com/item/sise_day.nhn?code=%s&page=%s' url = url_tmp % (corp_code, page) html = requests.get(url).text html = html.replace('\n', '') html = html.replace('\t', '') html = html.replace(',', '') html = html.replace('.', '-') soup = BeautifulSoup(html, 'lxml') span_data = soup.find_all('span') td_data = soup.find_all('td') tr_data = soup.find_all('tr') th_data = soup.find_all('th') if page == 1: columns_list = [] for i in range(len(th_data)): i_text = th_data[i].text columns_list.append(i_text) stock_price_all_array = np.array([columns_list]) rest_page = 0 stock_price_list = [] for i in range(1, len(span_data)): a = span_data[i].text stock_price_list.append(a) if page > 1 and stock_price_list[0] == stock_price_all_array[-10,0]: rest_page = (30 - page)*10 stock_price_array = np.zeros((rest_page,7)) stock_price_all_array = np.append(stock_price_all_array, stock_price_array, axis=0) break if i % 7 == 0: stock_price_array = np.array([stock_price_list]) stock_price_all_array = np.append(stock_price_all_array, stock_price_array, axis=0) stock_price_list = [] if rest_page: break elif len(span_data) < 70: rest_row = int((70 - len(span_data))/7+1) stock_price_array = np.zeros((rest_row, 7)) stock_price_all_array = np.append(stock_price_all_array, stock_price_array, axis=0) rest_page = (13 - page-1)*10 stock_price_array = np.zeros((rest_page,7)) stock_price_all_array = np.append(stock_price_all_array, stock_price_array, axis=0) break stock_price_all_array = np.delete(stock_price_all_array, 0, 0) stock_price_all_df = DataFrame(stock_price_all_array, columns=columns_list).set_index('날짜') stock_price_all_df = stock_price_all_df.reset_index()

stock_price_all_df.head()


크롤링 결과는 다음과 같습니다.








3. 데이터 전처리 

전처리에는 다음과 같은 내용이 포함됩니다.



3.1. 내가 예측하고자 하는 것이 무엇인지 명확히 하기

데이터만 보면 고가로 종가를 예측하기 저가로 종가를 예측하기 등등 할 수 있는 분석은 많습니다.

하지만, 의미없는 분석(당연한 결과가 나오는..)이 될 수 있으며 이는 시간 낭비로 이어질 뿐입니다.


주식에서 가장 관심있어할만한 부분은 아마 이전날들의 데이터를 활용하여 

다음날 주식가격이 오를 것인가 떨어질 것인가. 그리고 그 정도는 어느 정도인가가 될 것 입니다.

가능은 하지만 이 분석에 대해서는 더 많은 생각이 필요하므로

본 편에서는 하루 주식 가격의 변동이 거래량이 늘거나 주는데 영향을 미치는지를 확인해보는 것으로 하겠습니다.



3.2. 이상치가 있는지 확인하기

데이터에 이상치(outlier)가 있는지 확인합니다.

이상치란 다른 표본들과 다른 패턴을 가진 표본을 말합니다.

키와 몸무게를 예로 들어보면 키는 190cm이면서 몸무게가 40kg이라는 표본은 누가 봐도 이상한 수치이죠.

자료가 적은 상황에서 이러한 이상치는 평균에 큰 영향을 미치며 잘못된 예측 결과를 도출하게 만들기도 합니다.


이상치를 확인하는 방법은 눈대중으로 보는 방법, 통계적인 방법, 시각화하여 보는 방법도 있습니다.


위의 그림만 보더라도 11월 28일 거래량이 이상함을 알 수 있습니다.

그 이유는 크롤링한 시간이 11월 28일 오전 11시이며 

거래량은 그 이전에 발생한 내용에 대해서만 집계되어있기 때문입니다.


따라서 분석에서는 11월 28일 데이터를 제외시킨 후 분석을 하면 됩니다.



3.3 분석가능한 형태로 변환하기 

회귀 분석은 연속형 숫자 데이터가 입력으로 들어가고 출력 또한 연속형 숫자 데이터가 되어야합니다.

입출력 데이터를 모두 숫자형으로 변환해줍니다.

아울러 하루 내 주식가격의 변동폭에 대한 정보를 계산해줍니다.


#11월 28일 데이터 제외하기

stock_price_all_df=stock_price_all_df[1:].reset_index(drop=True)


#날짜컬럼을 제외한 나머지를 float로 변환하기

stock_price_all_df.iloc[:, 1:7]= stock_price_all_df.iloc[:, 1:7].astype(float) stock_price_all_df.head()

변환 결과는 다음과 같습니다.



주식 변동폭을 계산해줍니다.

stock_price_all_df["변동폭"] = stock_price_all_df["고가"] - stock_price_all_df["저가"]





4. 상관 분석 수행

상관 분석이란 두 변수간 얼마나 관련이 있는지를 수치로 표현해주는 것입니다.

키와 몸무게를 예로 들면 키가 +- 그리고 얼마나 변할 때 몸무게가 +- 얼마나 변하는지를 의미하며,

-1~1의 값을 갖습니다. 

-1에 가까울수록 키가 커지면 몸무게는 줄어든다는 의미가 됩니다.

+1에 가까울수록 키가 커지면 몸무게는 늘어난다라는 의미가 됩니다.

0은 키가 커지든 작아지든 몸무게는 키와는 관련없이 변하거나 변하지 않는다를 의미합니다.


회귀분석 이전에 상관 분석을 수행하는 이유는 시간 단축입니다.

두 변수간 관련도 없는데 굳이 a로 b를 예측할 필요는 없습니다.


#seaborn을 사용하여 상관분석 수행하기

import seaborn as sns Var_Corr = stock_price_all_df[["거래량","변동폭"]].corr() sns.heatmap(Var_Corr, annot=True)

0.49 정도의 상관이 있는 것으로 나타났습니다.

해석하면 변동폭이 증가할 때 거래량도 증가함을 의미합니다.

위의 결과가 통계적으로 유의미한지도 확인해보겠습니다.


#stat을 사용하여 통계적 유의미성 확인하기

import seaborn as sns Var_Corr = stock_price_all_df[["거래량","변동폭"]].corr() sns.heatmap(Var_Corr, annot=True)


결과는 다음과 같습니다.


상관계수가 랜덤으로(우연하게) 발생한 값일 확률이 p-value입니다.  

통계학적으로 0.05이하면 랜덤이 아닌 어떤 패턴이 존재한다를 의미하므로

0.000001이면 우연이 아니라 판단할 수 있습니다.


정리하면 거래량이 변동폭은 서로 관련이 있다. 

 거래량이 증가하면 변동폭도 증가한다. 

 그 관련성은 통계적으로도 유의미하다.







5. 회귀분석 수행

statsmodels를 사용하여 회귀분석을 수행합니다.


import statsmodels.api as sm x = stock_price_all_df["변동폭"] #키 생각하시면 됩니다. x = sm.add_constant(x) #상수 추가하고자 할 때 y = stock_price_all_df["거래량"]/100000 #몸무게 생각하시면 됩니다. x와 y의 척도 차이가 커서 줄이기 위해 /100000을 하였습니다. model = sm.OLS(y, x).fit() prediction = model.predict(x) model.summary()

위 코드에서 특이한 점은 x에 상수를 추가하는 부분 x = sm.add_constant(x) 입니다. 

이 부분은 절편(intertecpt) 혹은 상수(constant)라고 부르며 x가 0일 때 예측되는 y의 값입니다.

이해하기 쉽게 예를 들면 키를 가지고 몸무게를 예측할 때, 아무런 표본이 없다면 우리는 어떻게 예측을 할까요?

인간이라면 그래도 최소한 키가 100cm는 되지 않을까? 라는 추측을 하게 될 것입니다.

이 때의 100이 상수가 되며 식으로는 f(x) = ax + b(절편 즉 100)이 되는 것입니다.



회귀분석 결과는 다음과 같습니다.



R-squared : 아까 구한 상관계수의 제곱입니다.  

               변동폭이 거래량의 변화를 얼마나 설명하는가를 의미합니다.  1이면 거래량의 변화는 모두 변동폭에 의한 것입니다.

               하지만 그럴리는 없겠죠.


Adj-squared : 말그대로 수정된 r 제곱입니다. 위의 설명력이 과대추정되는 경우가 있어 모델의 설명량은 이 값으로 보는 경우가 많습니다.

0.238이면 약한 예측력을 가진 모델로 분류될 겁니다. 

쉽게 이해하고 싶으시다면 이 모델의 정확도는 약 24%의 정확도를 지닌다고 이해하시면 될 것 같습니다. 

(사실 정확도와는 다른 개념이라 이렇게 말하면 틀린 설명이긴 합니다)


const : 상수입니다. 변동폭이 0일 때 예측된는 거래량입니다. 위 숫자를 바꿔보니 5578000이 나오네요. 

    변동폭이 0일 때, 거래량은 5,578,000이다라고 이 모델은 예측하고 있습니다.


변동폭 : 이론편에서 말씀드린 w라고 할 수 있습니다. 변동폭이 1증가할 때 마다 거래량은 5538.0916 증가함을 의미합니다.



정리하면

이 회귀모델은 0.238의 설명력을 가지고 있다.

변동폭이 0일 때 하루 거래량은 5,578,000이다.

변동폭이 1증가할 때마다 거래량은 5538.0916 증가한다.


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함