기본 콘텐츠로 건너뛰기

[math] 정적분의 특성

[data analysis] 단순회귀분석(Simple regression)

단순회귀분석(Simple regression)

전형적인 회귀 모형은 y = ax + b와 같은 형태이며 변수 x를 y로 선형변환하는 것으로 정의할 수 있습니다.

선형변환은 x의 변화 정도에 따라 y의 변화 정도가 같습니다.

x를 설명변수 또는 독립변수, y를 반응변수 또는 종속변수라고 하며 x는 1개 이상일 수 있으며 단변수일 경우를 단순회귀 모형이라고 합니다. 위 식과 같이 x를 y로 이동시키는 과정에서 가장 적합한 a와 b를 결정하는 것이 회귀분석의 목적이 됩니다.

예 1)

kospi 지수의 일일 주가 자료중 시가(Open)을 설명변수로 하여 종가(Close)를 추정하는 회귀모델을 작성합니다.

Open Close
0 2874.50 2944.45
1 2943.67 2990.57
2 2993.34 2968.21

다음 코드는 분석을 위한 자료를 호출하기 위한 것입니다.

st=pd.Timestamp(2021,1, 1)
et=pd.Timestamp(2024, 5, 10)
kos=fdr.DataReader('KS11',st, et)[["Open","Close"]]
kos.index=range(len(kos))
kos.head(3).round(2) 
Open Close
02201.212175.17
12192.582176.46
22154.972155.07

통계분석을 위해 다음의 이유로 자료의 표준화(Standardization)가 필요합니다.

  1. 데이터의 규모(scale) 축소
  2. 여러변수가 사용될 경우 변수간 발생되는 데이터의 규모를 일정하게 조정
  3. 반응변수의 표준화는 필수적이지 않습니다. 그러나 b와 동일한 이유로 실행됩니다.

반응변수를 포함한 모든 자료가 표준화된 상태에서 구축된 회귀모델에 의한 추정치는 최종적으로 원래의 스케일로 환원되어야 합니다. 이 경우 표준화 단계에서 산출된 평균과 표준편차의 통계량이 필요합니다. 파이썬의 sklearn.processing.StandardScale(x) 클래스는 이와 같은 조건들을 충족시킵니다. 이 클래스에 전달되는 인수 x는 2차원이어야 합니다.

X=kos.values[:,0].reshape(-1,1)
y=kos.values[:,1].reshape(-1,1)
from sklearn.preprocessing import StandardScaler 
#독립변수 정규화(표준화)
xScaler=StandardScaler().fit(X)
X_n=xScaler.transform(X)
print(X_n[:3].round(2))
[[0.56]
 [0.79]
 [0.96]]
#반응변수 정규화(표준화)
yScaler=StandardScaler().fit(y)
y_n=yScaler.transform(y)
print(y_n[:3].round(2))
[[0.8 ]
 [0.95]
 [0.88]]

이 자료에서 설명변수 Open(indNor)과 반응변수 Close(deNor)의 관계는 그림 1과 같습니다. 이 그림에서 회귀선은 아래 코드에서 계산한 회귀모형입니다.

그림 1. Close와 Open의 대응.
plt.figure(figsize=(4,2))
plt.scatter(X_n, y_n, label="Data")
plt.plot(X_n, 0.998*X_n, color="red", label="Regression line")
plt.legend(loc="best", frameon=False)
plt.xlabel("Open", weight="bold")
plt.ylabel('Close', weight="bold")
plt.show() 

그림 1에서 Open의 증가에 따라 Close의 증가는 명확해 보입니다. 회귀선(regression line)은 회귀분석에 의해 생성되는 모델이며 식 1과 같이 설정할 수 있습니다.

y = β0 + β1x + ε (식 1)
x: 설명변수
y: 반응변수
β0 : 편차
β1 : 회귀계수(가중치)
ε : 오차

식 1을 회귀모델(regression model)이라고 합니다. 회귀모델은 파이썬의 다양한 패키지에서 제공하는 클래스 또는 함수등을 적용하여 생성할 수 있습니다. 다음은 statsmodel.api.OLS()sklearn.linear_model.LinearRegression() 클래스를 적용한 결과입니다. 두 클래스 모두 설명변수와 반응변수 모두 numpy array객체로 전달하여야 합니다.

numpy array 객체는 벡터, 행렬등의 배열 구조의 데이터 생성, 조작등에 특화된 파이썬 대표적인 패키지 numpy의 array() 함수에 의해 생성됩니다.

위 LinearRegression()의 클래스는 전달하는 인수에 의해 편차항을 선택할 수 있지만 OLS() 클래스의 경우 식 2와 같이 설명변수 편차항을 인위적으로 첨가하여야 합니다. 설명변수에 편차항 즉, β0을 첨가하기 위해 add_constant() 함수를 적용합니다.

$$X=\begin{bmatrix}x_1\\x_2\\\vdots\\x_n\end{bmatrix} \Rightarrow X_0=\begin{bmatrix} 1& x_1\\1& x_2\\\vdots& \vdots\\1& x_n\end{bmatrix}$$ (식 2)
import statsmodels.api as sm
X_n0=sm.add_constant(X_n)
X_n0.shape, y_n.shape
((824, 2), (824, 1))

다음코드는 statsmodel.api.OLS() 클래스를 적용한 결과입니다. 이 클래스의 인스턴스 즉, 생성된 모델을 실제로 실행하기 위해 .fit() 메서드를 실행합니다. 또한 생성한 모델의 회귀계수는 .params 속성, 회귀 모델의 결정계수는 .rsuared 속성을 사용하여 나타냅니다.

statsmodels.formula.api.ols('반응변수 ~ 설명변수', data) 클래스도 OLS() 클래스와 같습니다. 그러나 ols()의 경우 설명변수에 편차항이 자동으로 생성되므로 .add_constant(설명변수) 메소드를 사용할 필요가 없습니다. 이 클래스에 편차항을 제거하기 위해서는 "반응변수 ~ 설명변수 -1"와 같이 작성합니다.

reg=sm.OLS(y_n, X_n0).fit()
print(f'회귀계수(b0, b1) :{np.around(reg.params,3)}\nR2:{np.around(reg.rsquared,3)}')
회귀계수(b0, b1) :[-0.     0.997]
R2:0.994

ols() 클래스를 적용하기 위해서는 각 변수의 변수이름이 존재하는 구조이어야 하므로 다음과 같이 표준화한 자료의 구조를 변환하여 사용합니다.

da=np.c_[X_n, y_n]
da1=pd.DataFrame(da, columns=["open", "close"])
da1.head(3).round(3)
open close
0 0.561 0.800
1 0.791 0.953
2 0.956 0.879
m=statsmodels.formula.api.ols("close ~ open", data=da1).fit()
print(f"회귀계수\n {m.params.round(3)}")
회귀계수
 Intercept   -0.000
open         0.997
dtype: float64
print("R2: %.3f" %m.rsquared)
R2: 0.994

회귀분석 결과의 요약은 .summay() 메서드로 확인할 수 있습니다. 이 결과는 회귀 모형, 회귀계수, 그리고 설명변수의 분포에 대한 표들로 구성되어 있습니다. 각 표에 수록되어 있는 결과들의 의미는 이어지는 절에서 소개할 것입니다.

reg.summary()

위 코드의 결과는 표 1과 같이 3개의 표로 반환됩니다. 첫번째 표는 모델의 주요통계량을 나타내고 회귀모델의 각 계수에 대한 분석결과는 두 번째 표에서 확인할 수 있습니다. 마지막 3번째 표는 모델의 전제 조건에 대한 분석 결과입니다.

표 1 OLS Regression Results
Dep. Variable: y R-squared: 0.994
Model: OLS Adj. R-squared: 0.994
Method: Least Squares F-statistic: 1.407e+05
Date: Tue, 04 Jun 2024 Prob (F-statistic): 0.00
Time: 18:42:07 Log-Likelihood: 952.04
No. Observations: 824 AIC: -1900.
Df Residuals: 822 BIC: -1891.
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const -1.691e-16 0.003 -6.36e-14 1.000 -0.005 0.005
x1 0.9971 0.003 375.137 0.000 0.992 1.002
Omnibus: 54.231 Durbin-Watson: 2.039
Prob(Omnibus): 0.000 Jarque-Bera (JB): 226.114
Skew: 0.016 Prob(JB): 7.94e-50
Kurtosis: 5.566 Cond. No. 1.00

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

생성된 모델인 reg를 사용하여 설명변수의 추정 결과는 .predict(설명변수) 메소드로 확인할 수 있습니다. 이 경우 전달하는 인수인 설명변수는 모델 구축시 사용된 변수와 같은 구조이어야 합니다. 모델 생성에 참여하지 않은 새로운 변수를 모델에 적용하기 위해 새로운 자료를 호출합니다.

trgDay=pd.Timestamp(2023, 5, 11)
newD=fdr.DataReader('KS11',trgDay, trgDay)[["Open","Close"]]
newD.round(2)
Open Close
Date
2023-05-11 2505.57 2491.0

위 자료의 Open은 새로운 설명변수가 되므로 표준화합니다. 또한 편차항을 첨가합니다.

x_new=newD.values[0,0].reshape(-1,1)
xN_new=xScaler.transform(x_new)
print(xN_new.round(2))
[[-0.66]]
xN_new0=np.c_[1, xN_new]
print(xN_new0.round(2))
[[ 1.   -0.66]]
pre=reg.predict(xN_new0)
print(pre.round(2))
[-0.66]

위 결과는 표준화된 값입니다. 이 값을 원 스케일로 환원하기 위해서는 다음과 같이 StandardScaler.inverse_transform() 메소드를 적용합니다.

pre_re=yScaler.inverse_transform(pre.reshape(-1,1))
print(pre_re.round(2))
[[2504.29]]

회귀모델은 sklearn 패키지의 liniear_model.linearRegression(fit_intercept=True) 클래스를 사용하여 구축할 수 있습니다. 이 클래스의 인수인 fit_intercept는 편차항의 존재를 의미하는 것으로서 기본값이 True이므로 편차항이 자동 생성됩니다. 이 클래스에 의해 자료에 모델을 적합시키기 위해 위에서 사용한 OLS 클래스와 같이 .fit(설명변수, 반응변수) 메서드를 사용합니다. 생성된 모델의 계수와 편차는 다음의 속성을 이용하여 나타낼 수 있습니다.

  • 모형클래스이름.coef_: model의 계수를 반환
  • 모형클래스이름.intercept_: model의 절편을 반환
  • 모델.score(설명변수, 반응변수): 결정계수(R2)을 반환
from sklearn.linear_model import LinearRegression
mod = LinearRegression()
mod.fit(X_n, y_n)
print(f'계수:{np.around(mod.coef_,3)}, \n편차 : {np.around(mod.intercept_,3)}\nR2:{np.around(mod.score(X_n, y_n),3)}')
계수:[[0.997]], 
편차 : [-0.]
R2:0.994

.predict() 메서드를 사용하여 예측값을 계산합니다.

pre=mod.predict(xN_new)
print(pre.round(2))
[[-0.66]]
pre_re=yScaler.inverse_transform(pre)
print(pre_re.round(2))
[[2504.29]]

댓글

이 블로그의 인기 게시물

[Linear Algebra] 유사변환(Similarity transformation)

유사변환(Similarity transformation) n×n 차원의 정방 행렬 A, B 그리고 가역 행렬 P 사이에 식 1의 관계가 성립하면 행렬 A와 B는 유사행렬(similarity matrix)이 되며 행렬 A를 가역행렬 P와 B로 분해하는 것을 유사 변환(similarity transformation) 이라고 합니다. $$\tag{1} A = PBP^{-1} \Leftrightarrow P^{-1}AP = B $$ 식 2는 식 1의 양변에 B의 고유값을 고려한 것입니다. \begin{align}\tag{식 2} B - \lambda I &= P^{-1}AP – \lambda P^{-1}P\\ &= P^{-1}(AP – \lambda P)\\ &= P^{-1}(A - \lambda I)P \end{align} 식 2의 행렬식은 식 3과 같이 정리됩니다. \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)\\ &= \textsf{det}(I)\end{aligned}\end{align} 유사행렬의 특성 유사행렬인 두 정방행렬 A와 B는 'A ~ B' 와 같

[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