기본 콘텐츠로 건너뛰기

[Linear Algebra] 직교적 투영(Orthogonal Projection)

[data analysis] 다중회귀모델의 생성

회귀모델 생성

1개 이상의 설명변수들과 1개의 반응변수를 가진 선형모델 역시 statsmodels.api.OLS() 클래스와 sklearn.linear_model() 클래스를 적용하여 구축할 수 있습니다. 이 모델의 구축과정과 평가방법은 단순회귀분석(Simple regression)과 같습니다.

예 1)

코스피지수(kos), 코스탁지수(kq), kodex 레버리지(kl), kodex 인버스(ki), 그리고 원달러환율(WonDol)의 일일 종가들을 설명변수로 사용하여 삼성전자(sam)의 일일 종가를 추정하는 회귀모델을 구축해 봅니다. (이 자료에서 설명변수는 반응변수보다 1일 앞선 데이터 입니다.)

kos kq kl ki WonDol sam
Date
2023-01-10 2351.0 696.0 14440.0 4885.0 1239.0 60400.0
2023-01-11 2360.0 710.0 14525.0 4875.0 1240.0 60500.0
2023-01-12 2365.0 711.0 14580.0 4860.0 1242.0 60500.0

다음은 위 자료들을 호출하고 분석에 적합하게 조절하기 위한 코드들입니다.

import numpy as np 
import pandas as pd 
from sklearn import preprocessing
from scipy import stats
import matplotlib.pyplot as plt
import yfinance as yf
from sklearn.linear_model import LinearRegression
from statsmodels.regression.linear_model import OLS
from statsmodels.formula.api import ols
st=pd.Timestamp(2023,1, 10)
et=pd.Timestamp(2024, 5, 30)
code=["^KS11", "^KQ11", "122630.KS", "114800.KS","KRW=X","005930.KS"]
nme=["kos","kq","kl", "ki", "WonDol","sam" ]
da={}
for i, j in zip(nme,code):
    da[i]=yf.download(j,st, et)["Close"]
da2=pd.DataFrame(da.values(), index=da.keys()).T
da2=da2.ffill()
da2.head(3).round(0)

호출한 자료들의 시간들이 동일하지는 않습니다. 즉, WonDol을 제외한 자료는 거래가 중단되는 시간들이 존재합니다. 그러므로 이들 자료를 결합하는 과정에서 결측치가 존재합니다(결측치 조정 참조). 위 코드에서는 객체.ffill()를 적용하여 결측지 직전 값으로 대체하였습니다.

호출한 데이터들을 설명변수와 반응변수로 분리하고 마지막 행에 존재하는 자료들은 모델 생성에 참여하지 않은 설명변수로서 별도의 객체 final에 저장합니다.

ind=da2.values[:-1,:-1]
de=da2.values[1:,-1].reshape(-1,1)
final=da2.values[-1, :-1].reshape(1,-1)

각 변수들의 범위 즉, 스케일(규모)은 다양하므로 데이터 표준화를 실시합니다. 이것은 sklearn.preprocessing의 StandardScaler() 클래스를 적용합니다.

indScaler=preprocessing.StandardScaler().fit(ind)
deScaler=preprocessing.StandardScaler().fit(de)
indNor=indScaler.transform(ind)
finalNor=indScaler.transform(final)
deNor=deScaler.transform(de)
print(finalNor.round(3))
[[ 1.256 -0.133  1.488 -1.515  1.395]]

statsmodels.formula.api.ols() 클래스를 적용하여 회귀모델을 생성합니다. 이 모델의 세부적인 사항은 summay() 메서드로 확인할 수 있습니다. 이 메서드의 결과는 단순회귀분석에서 나타낸 것과 같이 3개의 표들로 구성됩니다. 이 표들은 이 메서드의 속성 tables로 별도로 나타낼 수 있습니다. 먼저 첫 번째 표를 나타내면 다음과 같습니다.

ols() 함수를 사용하기 위해서는 위의 indNor, deNor을 결합하여 DataFrame 구조로 생성하여야 합니다.

da3=pd.DataFrame(np.c_[indNor, deNor.reshape(-1,1)])
da3.columns=da2.columns
da3.head(3).round(2)
kos kq kl ki WonDol sam
0 -1.87 -3.01 -1.47 1.58 -2.36 -1.72
1 -1.79 -2.73 -1.42 1.53 -2.33 -1.72
2 -1.74 -2.71 -1.38 1.46 -2.29 -1.67
form='sam~kos+kq+kl+ki+WonDol'
reg=ols(form, data=da3).fit()
re=reg.summary()
re.tables[0]

위 코드의 결과는 표 1과 같습니다.

표 1 OLS Regression Results
Dep. Variable: sam R-squared: 0.863
Model: OLS Adj. R-squared: 0.861
Method: Least Squares F-statistic: 445.4
Date: Wed, 11 Sep 2024 Prob (F-statistic): 1.61e-150
Time: 09:52:12 Log-Likelihood: -154.10
No. Observations: 361 AIC: 320.2
Df Residuals: 355 BIC: 343.5
Df Model: 5
Covariance Type: nonrobust

표 1에서 나타낸 F 검정의 유의확률(p-value)은 매우 작은 값으로 모델의 모든 회귀계수가 0이 된다는 귀무가설을 기각할 수 있습니다. 즉, 이 모델은 설명변수들에 의한 반응변수의 설명이 가능함을 나타냅니다. 이 결과는 작지않은 결정계수(R2)에 의해 부연됩니다.

F 검정의 결과는 각각 유의확률과 검정통계량을 반환하는 모델.f_pvalue, 모델.fvalue 속성, 결정계수는 모델.squared 속성으로 확인할 수 있습니다.

fst, fp, r2=reg.fvalue,reg.f_pvalue, reg.rsquared
print('F통계량:%.3f, p-value:%.3f, R2:%.3f' %(fst, fp, r2))
F통계량:445.378, p-value:0.000, R2:0.863

F 검정 결과는 이 모델 전체에 대한 검정으로 각 설명변수가 반응변수에 영향 정도를 확인할 수 없습니다. 모델에의해 발생되는 오차에 대해 각 설명변수들의 영향정도는 anova 분석으로 확인할 수 있습니다.

anovaRe=sm.stats.anova_lm(reg)
np.around(anovaRe, 2)
df sum_sq mean_sq F PR(>F)
kos 1.0 217.12 217.12 1552.84 0.0
kq 1.0 4.62 4.62 33.04 0.0
kl 1.0 82.49 82.49 589.98 0.0
ki 1.0 5.45 5.45 38.99 0.0
WonDol 1.0 1.68 1.68 12.04 0.0
Residual 355.0 49.64 0.14 NaN NaN

위 결과는 잔차의 분산 대비 각 설명변수의 분산의 비를 통계량으로 하는 것으로 유의수준 0.05를 기준으로 모든 변수들의 효과가 없다는 귀무가설을 기각할 수 있습니다. 이 결과는 객체 re의 두번째 표는 회귀계수에 대한 t 검정 결과를 나타냅니다(회귀계수의 평가 참조).

re.tables[1]
coef std err t P>|t| [0.025 0.975]
Intercept 8.29e-16 0.020 4.21e-14 1.000 -0.039 0.039
kos -2.1508 0.144 -14.942 0.000 -2.434 -1.868
kq 0.3980 0.041 9.772 0.000 0.318 0.478
kl 0.9641 0.280 3.445 0.001 0.414 1.514
ki -1.7233 0.269 -6.416 0.000 -2.251 -1.195
WonDol 0.0810 0.023 3.470 0.001 0.035 0.127

위 결과는 anova 분석과 같은 결과를 보여줍니다. 편차항을 제외한 모든 계수의 신뢰구간은 0을 포함하지 않으므로 모델에 영향을 준다고 할 수 있습니다. 이 회귀계수의 신뢰구간은 위 표외에 모델.conf_int(alpha) 메소드로 확인할 수 있습니다.

reg.conf_int(0.05).round(3)
0 1
Intercept -0.039 0.039
kos -2.434 -1.868
kq 0.318 0.478
kl 0.414 1.514
ki -2.251 -1.195
WonDol 0.035 0.127

각각의 설명변수와 반응변수 sam에 대한 단순회귀모형으로 위 분석결과를 확인할 수 있습니다. 예를 들어 WonDol-sam의 단순회귀모형으로 이 설명변수의 효과여부를 판단해 봅니다.

reg_wd=ols("sam~WonDol", data=da3).fit()
pd.DataFrame([reg_wd.fvalue, reg_wd.f_pvalue], index=['f-statics', 'p-value']).round(3)
0
f-statics 113.455
p-value 0.000

위와 같이 각 설명변수에 대한 단순회귀분석의 결과는 sklearn.feature_selection.f_regression(설명변수, 반응변수) 함수를 사용하여 모든 변수에 대한 결과를 확인할 수 있습니다. 이 함수는 하나의 설명변수과 반응변수로 생성되는 단순회귀모델에 대한 F 검정 결과(통계량과 유의확률)를 반환합니다. 예를 들어 다음 결과의 첫번째 통계량과 유의확률은 y=b0 + b1x[:,0]의 모델에 대한 F 검정의 결과입니다.

from sklearn import feature_selection 
Ftest=feature_selection.f_regression(indNor, deNor.ravel())
f2=pd.DataFrame([Ftest[0], Ftest[1]], index=["f-value", "p-value"], columns=da2.columns[:-1])
np.around(f2, 1)
kos kq kl ki WonDol
f-value 541.7 105.1 975.8 994.2 113.5
p-value 0.0 0.0 0.0 0.0 0.0

위 결과는 F 통계량과 p-value로서 각 설명변수에 의한 단순회귀모델이 유효함을 의미합니다.

생성된 모델의 회귀계수는 모델.params 속성으로 확인할 수 있습니다. 또한 추정값은 모델.predict() 메소드로 확인할 수 있습니다.

reg.params.round(3)
Intercept    0.000
kos         -2.151
kq           0.398
kl           0.964
ki          -1.723
WonDol       0.081
dtype: float64

위 ols() 함수 대신에 sklearn.linear_model.LinearRegression() 클래스를 사용하여 회귀모델을 작성할 수 있습니다. 다음은 이 클래스를 적용한 결과입니다.

mod=LinearRegression().fit(indNor, deNor)
b0=mod.intercept_
b=mod.coef_
print(f"편차:{np.around(b0, 3)}, 계수: {np.around(b, 3)}")
편차:[-0.], 계수: [[-2.151  0.398  0.964 -1.723  0.081]]
r2=mod.score(indNor, deNor)
print(f"R2: {round(r2, 3)}")
R2: 0.863

그림 1은 생성한 모델을 통해 반응변수와 그에 대응하는 추정된 값들을 시각화한 것입니다.

그림 1. 중회귀모형에 의한 예측.
plt.figure(figsize=(4, 3))
plt.plot(deNor, c="g", ls="--", label="data")
plt.plot(mod.predict(indNor), c="b", label="regression")
plt.legend(loc="best", frameon=False)
plt.show()

이 블로그의 인기 게시물

유사변환과 대각화

내용 유사변환 유사행렬의 특성 대각화(Diagonalization) 유사변환(Similarity transformation) 유사변환 n×n 차원의 정방 행렬 A, B 그리고 가역 행렬 P 사이에 식 1의 관계가 성립하면 행렬 A와 B는 유사하다고 하며 이 변환을 유사 변환 (similarity transformation)이라고 합니다. $$\begin{equation}\tag{1} A = PBP^{-1} \Leftrightarrow P^{-1}AP = B \end{equation}$$ 식 1의 유사 변환은 다음과 같이 고유값을 적용하여 특성 방정식 형태로 정리할 수 있습니다. $$\begin{align} B - \lambda I &= P^{-1}AP – \lambda P^{-1}P\\ &= P^{-1}(AP – \lambda P)\\ &= P^{-1}(A - \lambda I)P \end{align}$$ 위 식의 행렬식은 다음과 같이 정리됩니다. $$\begin{align} &\begin{aligned}\textsf{det}(B - \lambda I ) & = \textsf{det}(P^{-1}(AP – \lambda P))\\ &= \textsf{det}(P^{-1}) \textsf{det}((A – \lambda I)) \textsf{det}(P)\\ &= \textsf{det}(P^{-1}) \textsf{det}(P) \textsf{det}((A – \lambda I))\\ &= \textsf{det}(A – \lambda I)\end{aligned}\\ &\begin{aligned}\because \; \textsf{det}(P^{-1}) \textsf{det}(P) &= \textsf{det}(P^{-1}P)\\ &= \t

[matplotlib] 히스토그램(Histogram)

히스토그램(Histogram) 히스토그램은 확률분포의 그래픽적인 표현이며 막대그래프의 종류입니다. 이 그래프가 확률분포와 관계가 있으므로 통계적 요소를 나타내기 위해 많이 사용됩니다. plt.hist(X, bins=10)함수를 사용합니다. x=np.random.randn(1000) plt.hist(x, 10) plt.show() 위 그래프의 y축은 각 구간에 해당하는 갯수이다. 빈도수 대신 확률밀도를 나타내기 위해서는 위 함수의 매개변수 normed=True로 조정하여 나타낼 수 있다. 또한 매개변수 bins의 인수를 숫자로 전달할 수 있지만 리스트 객체로 지정할 수 있다. 막대그래프의 경우와 마찬가지로 각 막대의 폭은 매개변수 width에 의해 조정된다. y=np.linspace(min(x)-1, max(x)+1, 10) y array([-4.48810153, -3.54351935, -2.59893717, -1.65435499, -0.70977282, 0.23480936, 1.17939154, 2.12397372, 3.0685559 , 4.01313807]) plt.hist(x, y, normed=True) plt.show()

R 미분과 적분

내용 expression 미분 2차 미분 mosaic를 사용한 미분 적분 미분과 적분 R에서의 미분과 적분 함수는 expression()함수에 의해 생성된 표현식을 대상으로 합니다. expression expression(문자, 또는 식) 이 표현식의 평가는 eval() 함수에 의해 실행됩니다. > ex1<-expression(1+0:9) > ex1 expression(1 + 0:9) > eval(ex1) [1] 1 2 3 4 5 6 7 8 9 10 > ex2<-expression(u, 2, u+0:9) > ex2 expression(u, 2, u + 0:9) > ex2[1] expression(u) > ex2[2] expression(2) > ex2[3] expression(u + 0:9) > u<-0.9 > eval(ex2[3]) [1] 0.9 1.9 2.9 3.9 4.9 5.9 6.9 7.9 8.9 9.9 미분 D(표현식, 미분 변수) 함수로 미분을 실행합니다. 이 함수의 표현식은 expression() 함수로 생성된 객체이며 미분 변수는 다음 식의 분모의 변수를 의미합니다. $$\frac{d}{d \text{변수}}\text{표현식}$$ 이 함수는 어떤 함수의 미분의 결과를 표현식으로 반환합니다. > D(expression(2*x^3), "x") 2 * (3 * x^2) > eq<-expression(log(x)) > eq expression(log(x)) > D(eq, "x") 1/x > eq2<-expression(a/(1+b*exp(-d*x))); eq2 expression(a/(1 + b * exp(-d * x))) > D(eq2, "x") a * (b * (exp(-d * x) * d))/(1 + b