leverage-outliar-cooks_distance_anova

1
import statsmodels.api as sm

레버리지 (leverage)

독립변수의 전체 데이터가 아닌 개별적인 데이터 표본 하나하나가 회귀분석 결과에 미치는 영향력은 레버리지 분석이나 아웃라이어 분석을 통해 알 수 있다.
레버리지(leverage)는 실제 종속변수값  𝑦 가 예측치(predicted target)  𝑦̂  에 미치는 영향을 나타낸 값이다. self-influence, self-sensitivity 라고도 한다.
1
2
3
4
5
6
7
8
from sklearn.datasets import load_boston

boston = load_boston()

dfx = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfx,dfy],axis=1)
df

CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 34.7
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 36.2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 22.4
502 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 20.6
503 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 23.9
504 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 22.0
505 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 11.9

506 rows × 14 columns

1
2
3
dfX = sm.add_constant(dfx)
df0 = pd.concat([dfX, dfy],axis=1)
df0

const CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 1.0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 1.0 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
2 1.0 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 34.7
3 1.0 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
4 1.0 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 36.2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 1.0 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 22.4
502 1.0 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 20.6
503 1.0 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 23.9
504 1.0 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 22.0
505 1.0 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 11.9

506 rows × 15 columns

statsmodels를 이용한 레버리지 계산
레버리지 값은 RegressionResults 클래스의 get_influence 메서드로 다음과 같이 구할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sklearn.datasets import make_regression

# 100개의 데이터 생성
X0, y, coef = make_regression(n_samples=100, n_features=1, noise=20,
coef=True, random_state=1)

# 레버리지가 높은 가상의 데이터를 추가
data_100 = (4, 300)
data_101 = (3, 150)
X0 = np.vstack([X0, np.array([data_100[:1], data_101[:1]])])
X = sm.add_constant(X0) #상수항 추가
y = np.hstack([y, [data_100[1], data_101[1]]])

plt.figure(figsize=(14,6))
plt.scatter(X0, y, s=30)
plt.xlabel("x")
plt.ylabel("y")
plt.title("가상의 회귀분석용 데이터")
plt.show()
output_6_0
1
2
3
model = sm.OLS(pd.DataFrame(y), pd.DataFrame(X))
result = model.fit()
print(result.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      0   R-squared:                       0.936
Model:                            OLS   Adj. R-squared:                  0.935
Method:                 Least Squares   F-statistic:                     1464.
Date:                Thu, 14 May 2020   Prob (F-statistic):           1.61e-61
Time:                        14:22:53   Log-Likelihood:                -452.71
No. Observations:                 102   AIC:                             909.4
Df Residuals:                     100   BIC:                             914.7
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
0              3.2565      2.065      1.577      0.118      -0.840       7.353
1             78.3379      2.048     38.260      0.000      74.276      82.400
==============================================================================
Omnibus:                       16.191   Durbin-Watson:                   1.885
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               36.807
Skew:                          -0.534   Prob(JB):                     1.02e-08
Kurtosis:                       5.742   Cond. No.                         1.14
==============================================================================

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


선형회귀 결과에서 get_influence 메서드를 호출하면 영향도 정보 객체를 구할 수 있고, 이 객체는 hat_matrix_diag 속성으로 레버리지 벡터의 값을 가지고도 있어
1
2
3
4
5
6
7
8
influence = result.get_influence()
hat = influence.hat_matrix_diag

plt.figure(figsize=(14,6))
plt. stem(hat)
plt.axhline(0.02, c = 'g', ls = '--') # c = color , ls = linestyle
plt.title('각 데이터의 레버리지 값')
plt.show()
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:5: UserWarning: In Matplotlib 3.3 individual lines on a stem plot will be added as a LineCollection instead of individual lines. This significantly improves the performance of a stem plot. To remove this warning and switch to the new behaviour, set the "use_line_collection" keyword argument to True.
  """
output_9_1
그래프를 그리는 코드에서 0.02의 값은 레버리지 평균값을 구하는 공식 독립변수의 갯수 / 데이터의 갯수 로 구하면 된다
1
![스크린샷 2020-05-14 오후 2 31 46](https://user-images.githubusercontent.com/59719711/81926278-b2215100-961c-11ea-9613-c5ba582d5de0.png)
1
2
3
4
5
6
7
8
9
plt.figure(figsize=(14,6))
ax = plt.subplot()
plt.scatter(X0, y,s=30)
sm.graphics.abline_plot(model_results=result, ax=ax)

idx = hat > 0.05
plt.scatter(X0[idx], y[idx], s=300, c="r", alpha=0.5)
plt.title("회귀분석 결과와 레버리지 포인트")
plt.show()
output_12_0
그래프를 토대로 해석을 하자면, 데이터가 혼자만 너무 작거나 너무 크게 단독으로 존재할수록 레버리지가 커짐을 알 수 있어. 이 말은 저런 데이터은 전체 회귀분석 결과값에 큰 영향을 미친다는 말이야

아웃라이어(outlier)

데이터와 동떨어진 값을 가지는 데이터, 즉 잔차가 큰 데이터를 아웃라이어(outlier)라고 하는데, 잔차의 크기는 독립 변수의 영향을 받으므로 아웃라이어를 찾으려면 이 영향을 제거한 표준화된 잔차를 계산해야 한다고 해. 무슨말인지 잘 모르겠지만 그래

statsmodels를 이용한 표준화 잔차 계산

잔차는 RegressionResult 객체의 resid 속성에 있다.
1
2
3
4
plt.figure(figsize=(14, 6))
plt.stem(result.resid)
plt.title("각 데이터의 잔차")
plt.show()
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:2: UserWarning: In Matplotlib 3.3 individual lines on a stem plot will be added as a LineCollection instead of individual lines. This significantly improves the performance of a stem plot. To remove this warning and switch to the new behaviour, set the "use_line_collection" keyword argument to True.
output_16_1
표준화 잔차는 resid_pearson 속성에 있고, 보통 표준화 잔차가 2~4보다 크면 아웃라이어로 보는게 일반적이야
1
2
3
4
5
6
plt.figure(figsize=(14,6))
plt. stem(result.resid_pearson)
plt.axhline(3, c='g', ls='--')
plt.axhline(-3, c='g', ls='--')
plt.title('각 데이터의 표준화 잔차')
plt.show()
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:2: UserWarning: In Matplotlib 3.3 individual lines on a stem plot will be added as a LineCollection instead of individual lines. This significantly improves the performance of a stem plot. To remove this warning and switch to the new behaviour, set the "use_line_collection" keyword argument to True.
output_18_1

Cook’s Distance

회귀 분석에는 레버리지 따로, 잔차의 크기가 큰 데이터가 아웃라이어가 되고 그것을 보는 따로따로의 기능도 있지만  이 두개를 동시에 보는 방법이 바로 Cook's Distance야. 아마도 Cook이라는 사람이 만들었을 가능성이..

넘어가자

동시에 보는 기준이라고 생각하면 되고, 둘중 하나만 커지더라도 이 Cook's distance 값은 커지게 돼

모든 데이터의 레버리지와 잔차를 동시에 보려면 plot_leverage_resid2 명령을 사용하는데, 이 명령은 x축으로 표준화 잔차의 제곱을 표시하고 y축으로 레버리지값을 표시한다. 

그리고 데이터 아이디가 표시된 데이터들이 레버리지가 큰 아웃라이어 야
1
2
3
4
5
6
plt.figure(figsize=(14,6))
sm.graphics.plot_leverage_resid2(result)
plt.show()

sm.graphics.influence_plot(result)
plt.show()
<Figure size 1008x432 with 0 Axes>
output_21_1 output_21_2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from statsmodels.graphics import utils

cooks_d2, pvals = influence.cooks_distance
K = influence.k_vars
fox_cr = 4 / (len(y) - K - 1)
idx = np.where(cooks_d2 > fox_cr)[0]

ax = plt.subplot()
plt.scatter(X0, y)
plt.scatter(X0[idx], y[idx], s=300, c="r", alpha=0.5)
utils.annotate_axes(range(len(idx)), idx,
list(zip(X0[idx], y[idx])), [(-20, 15)] * len(idx), size="small", ax=ax)
plt.title("Fox Recommendaion으로 선택한 아웃라이어")
plt.show()
output_22_0
보스턴 집값 예측 문제¶
보스턴 집값 문제에 아웃라이어를 적용해 보자. MEDV가 50인 데이터는 상식적으로 생각해도 이상한 데이터이므로 아웃라이어라고 판단할 수 있다. 나머지 데이터 중에서 폭스 추천공식을 사용하여 아웃라이어를 제외한 결과는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
boston = load_boston()

dfx = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfx,dfy],axis=1)
df

dfX = sm.add_constant(dfx)
df0 = pd.concat([dfX, dfy],axis=1)
df0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pred = result_boston.predict(dfX)

influence_boston = result_boston.get_influence()
cooks_d2, pvals = influence_boston.cooks_distance
K = influence.k_vars
fox_cr = 4 / (len(y) - K - 1)
idx = np.where(cooks_d2 > fox_cr)[0]

# MEDV = 50 제거
idx = np.hstack([idx, np.where(boston.target == 50)[0]])

ax = plt.subplot()
plt.scatter(dfy, pred)
plt.scatter(dfy.MEDV[idx], pred[idx], s=200, c="r", alpha=0.5)
utils.annotate_axes(range(len(idx)), idx,
list(zip(dfy.MEDV[idx], pred[idx])), [(-20, 15)] * len(idx), size="small", ax=ax)
plt.title("보스턴 집값 데이터에서 아웃라이어")
plt.show()
output_25_0
다음은 이렇게 아웃라이어를 제외한 후에 다시 회귀분석을 한 결과이다.
1
2
3
4
5
6
idx2 = list(set(range(len(dfX))).difference(idx))
dfX = dfX.iloc[idx2, :].reset_index(drop=True)
dfy = dfy.iloc[idx2, :].reset_index(drop=True)
model_boston2 = sm.OLS(dfy, dfX)
result_boston2 = model_boston2.fit()
print(result_boston2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.812
Model:                            OLS   Adj. R-squared:                  0.806
Method:                 Least Squares   F-statistic:                     156.1
Date:                Thu, 14 May 2020   Prob (F-statistic):          2.41e-161
Time:                        15:14:52   Log-Likelihood:                -1285.2
No. Observations:                 485   AIC:                             2598.
Df Residuals:                     471   BIC:                             2657.
Df Model:                          13                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         18.8999      4.107      4.602      0.000      10.830      26.969
CRIM          -0.0973      0.024     -4.025      0.000      -0.145      -0.050
ZN             0.0278      0.010      2.651      0.008       0.007       0.048
INDUS         -0.0274      0.046     -0.595      0.552      -0.118       0.063
CHAS           0.9228      0.697      1.324      0.186      -0.447       2.292
NOX           -9.4922      2.856     -3.323      0.001     -15.105      -3.879
RM             5.0921      0.371     13.735      0.000       4.364       5.821
AGE           -0.0305      0.010     -2.986      0.003      -0.051      -0.010
DIS           -1.0562      0.150     -7.057      0.000      -1.350      -0.762
RAD            0.1990      0.049      4.022      0.000       0.102       0.296
TAX           -0.0125      0.003     -4.511      0.000      -0.018      -0.007
PTRATIO       -0.7777      0.098     -7.955      0.000      -0.970      -0.586
B              0.0107      0.002      5.348      0.000       0.007       0.015
LSTAT         -0.2846      0.043     -6.639      0.000      -0.369      -0.200
==============================================================================
Omnibus:                       45.944   Durbin-Watson:                   1.184
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               65.791
Skew:                           0.679   Prob(JB):                     5.17e-15
Kurtosis:                       4.188   Cond. No.                     1.59e+04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.59e+04. This might indicate that there are
strong multicollinearity or other numerical problems.


R-squared 의 성능점수가 올라간 것을 볼 수 있어.

이렇게 어떤 특정 데이터를 가지고 회귀분석 모델링을 할 때에는 하기 전에 레버리지가 큰 데이터와 아웃라이어의 값을 이러한 절차에 의해 뽑아서 제거하고 모델링을 한다면 더욱 성능이 좋은 회귀분석 모델링을 할 수 있는거야

분산 분석

선형회귀분석의 결과가 얼마나 좋은지는 단순히 잔차제곱합(RSS: Residula Sum of Square)으로 평가할 수 없다. 변수의 단위 즉, 스케일이 달라지면 회귀분석과 상관없이 잔차제곱합도 달라지기 때문이야 ( ex.1km와 1000m)

분산 분석(ANOVA: Analysis of Variance)은 종속변수의 분산과 독립변수의 분산간의 관계를 사용하여 선형회귀분석의 성능을 평가하고자 하는 방법이다. 분산 분석은 서로 다른 두 개의 선형회귀분석의 성능 비교에 응용할 수 있으며 독립변수가 카테고리 변수인 경우 각 카테고리 값에 따른 영향을 정량적으로 분석하는데도 사용할 수 있게 돼

여러 수식들이 존재하지만 내가 이해를 못하겠고 결론은 다음과 같아.

모형 예측치의 움직임의 크기(분산,ESS)은 종속변수의 움직임의 크기(분산,TSS)보다 클 수 없어 그리고 모형의 성능이 좋을수록 모형 예측치의 움직임의 크기는 종속변수의 움직임의 크기와 비슷해진다는 점이야
F 검정을 사용한 변수 중요도 비교
F검정은 각 독립변수의 중요도를 비교하기 위해 사용할 수 있다. 방법은 전체 모형과 각 변수 하나만을 뺀 모형들의 성능을 비교하는 것인데, 이는 간접적으로 각 독립 변수의 영향력을 측정하는 것이라고 할 수 있다. 예를 들어 보스턴 집값 데이터에서 CRIM이란 변수를 뺀 모델과 전체 모델의 비교하는 검정을 하면 이 검정 결과는 CRIM변수의 중요도를 나타낸다.
1
2
3
4
5
6
model_full = sm.OLS.from_formula(
"MEDV ~ CRIM + ZN + INDUS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT + CHAS", data=df0)
model_reduced = sm.OLS.from_formula(
"MEDV ~ ZN + INDUS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT + CHAS", data=df0)

sm.stats.anova_lm(model_reduced.fit(), model_full.fit())
/opt/anaconda3/lib/python3.7/site-packages/scipy/stats/_distn_infrastructure.py:903: RuntimeWarning: invalid value encountered in greater
  return (a < x) & (x < b)
/opt/anaconda3/lib/python3.7/site-packages/scipy/stats/_distn_infrastructure.py:903: RuntimeWarning: invalid value encountered in less
  return (a < x) & (x < b)
/opt/anaconda3/lib/python3.7/site-packages/scipy/stats/_distn_infrastructure.py:1912: RuntimeWarning: invalid value encountered in less_equal
  cond2 = cond0 & (x <= _a)

df_resid ssr df_diff ss_diff F Pr(>F)
0 493.0 11322.004277 0.0 NaN NaN NaN
1 492.0 11078.784578 1.0 243.219699 10.801193 0.001087
anova_lm 명령에서는 typ 인수를 2로 지정하면 하나 하나의 변수를 뺀 축소 모형에서의 F 검정값을 한꺼번에 계산할 수 있다.
아노바 분석 - F검정
1
2
3
4
model = sm.OLS.from_formula(
"MEDV ~ CRIM + ZN + INDUS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT + CHAS", data=df0)
result = model.fit()
sm.stats.anova_lm(result, typ=2)

sum_sq df F PR(>F)
CRIM 243.219699 1.0 10.801193 1.086810e-03
ZN 257.492979 1.0 11.435058 7.781097e-04
INDUS 2.516668 1.0 0.111763 7.382881e-01
NOX 487.155674 1.0 21.634196 4.245644e-06
RM 1871.324082 1.0 83.104012 1.979441e-18
AGE 0.061834 1.0 0.002746 9.582293e-01
DIS 1232.412493 1.0 54.730457 6.013491e-13
RAD 479.153926 1.0 21.278844 5.070529e-06
TAX 242.257440 1.0 10.758460 1.111637e-03
PTRATIO 1194.233533 1.0 53.034960 1.308835e-12
B 270.634230 1.0 12.018651 5.728592e-04
LSTAT 2410.838689 1.0 107.063426 7.776912e-23
CHAS 218.970357 1.0 9.724299 1.925030e-03
Residual 11078.784578 492.0 NaN NaN
각각의 독립변수들의 전체와 비교했을 때 얼마만큼 중요도를 가지는데 정량적으로 나온 결과값이야. 여기서 주목해야할 부분은 PR>(>F)부분으로 summary에서도 나오는 p-value값을 디테일하게 풀어놓은 값이고 예를 들어 LSTAT, RM의 경우 10의 -23승, 10의 -18승으로 수치가 제일 낮은걸 알 수 있어. 그러면 이 2가지의 독립변수가 종속변수에 가장 큰 영향을 미쳤다고 해석하면 되는거야
표의 F값을 보고도 알 수 있지만 F값은 확률의 의미는 없기 때문에 단순 순위를 매기는거 라면 결정할 수 있지만 만약 귀무가설/대립가설을 accept 하냐 reject 하냐의 확률적 의미를 판단한다면 F값만으로는 불가능해
1
2


범주형을 사용한 비선형성
독립변수의 비선형성을 포착하는 또 다른 방법 중 하나는 강제로 범주형 값으로 만드는 것이다. 범주형 값이 되면서 독립변수의 오차가 생기지만 이로 인한 오차보다 비선형성으로 얻을 수 있는 이익이 클 수도 있다.

보스턴 집값 데이터에서 종속변수와 RM 변수의 관계는 선형에 가깝지만 방의 갯수가 아주 작아지거나 아주 커지면 선형모형에서 벗어난다.
1
2
3
plt.figure(figsize=(14,6))
sns.scatterplot(x="RM", y="MEDV", data=df0, s=60)
plt.show()
output_39_0
1
2
3
model_rm = sm.OLS.from_formula('MEDV ~ RM', data=df0)
result_rm = model_rm.fit()
print(result_rm.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.484
Model:                            OLS   Adj. R-squared:                  0.483
Method:                 Least Squares   F-statistic:                     471.8
Date:                Thu, 14 May 2020   Prob (F-statistic):           2.49e-74
Time:                        19:28:18   Log-Likelihood:                -1673.1
No. Observations:                 506   AIC:                             3350.
Df Residuals:                     504   BIC:                             3359.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept    -34.6706      2.650    -13.084      0.000     -39.877     -29.465
RM             9.1021      0.419     21.722      0.000       8.279       9.925
==============================================================================
Omnibus:                      102.585   Durbin-Watson:                   0.684
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              612.449
Skew:                           0.726   Prob(JB):                    1.02e-133
Kurtosis:                       8.190   Cond. No.                         58.4
==============================================================================

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


이렇게 RM 데이터 전체를 놓고 보면 종속변수 y와 아주 큰 상관관계가 있는것으로 보이지만 위에 그래프에서 봤듯이, 방의 갯수가 아주 적거나, 많으면 선형성을 보이지 않는 구간에 대해 조금 더 디테일하게 상관관게를 보고 싶다면 RM 데이터를 강제로 범주화 시켜 RM 데이터가 가지는 비선형성을 잡을 수 있다.
1
2
3
4
5
6
7
rooms = np.arange(3,10)
labels = [str(r) for r in rooms[:-1]]
df0['CAT_RM'] = np.round(df['RM'])

plt.figure(figsize=(14,6))
sns.barplot('CAT_RM', 'MEDV', data=df0)
plt.show()
output_42_0
이렇게 하면 RM 변수으로 인한 종속변수의 변화를 비선형 상수항으로 모형화 할 수 있다. 선형모형보다 성능이 향상된 것을 볼 수 있다.
1
2
3
model_rm2 = sm.OLS.from_formula("MEDV ~ C(np.round(RM))", data=df0)
result_rm2 = model_rm2.fit()
print(result_rm2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.537
Model:                            OLS   Adj. R-squared:                  0.532
Method:                 Least Squares   F-statistic:                     115.8
Date:                Thu, 14 May 2020   Prob (F-statistic):           3.57e-81
Time:                        19:33:48   Log-Likelihood:                -1645.6
No. Observations:                 506   AIC:                             3303.
Df Residuals:                     500   BIC:                             3329.
Df Model:                           5                                         
Covariance Type:            nonrobust                                         
==========================================================================================
                             coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------------------
Intercept                 17.0200      2.814      6.049      0.000      11.492      22.548
C(np.round(RM))[T.5.0]    -2.0741      2.998     -0.692      0.489      -7.964       3.816
C(np.round(RM))[T.6.0]     2.3460      2.836      0.827      0.409      -3.226       7.918
C(np.round(RM))[T.7.0]    11.0272      2.869      3.843      0.000       5.389      16.665
C(np.round(RM))[T.8.0]    28.5425      3.093      9.228      0.000      22.466      34.619
C(np.round(RM))[T.9.0]    23.6133      4.595      5.139      0.000      14.586      32.641
==============================================================================
Omnibus:                       81.744   Durbin-Watson:                   0.799
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              467.887
Skew:                           0.542   Prob(JB):                    2.51e-102
Kurtosis:                       7.584   Cond. No.                         31.1
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
시간 독립변수의 변형
독립변수가 시간인 경우에는 특정 시점에서 경과된 시간값으로 변형해야 한다. 일간 전기 사용량 데이터를 예로 들어 설명한다.
1
2
3
4
5
data = sm.datasets.get_rdataset("elecdaily", package="fpp2")

df_elec = data.data.drop(columns=["WorkDay", "Temperature"])
df_elec["Date"] = pd.date_range("2014-1-1", "2014-12-31")
df_elec.tail()

Demand Date
360 173.727990 2014-12-27
361 188.512817 2014-12-28
362 191.273009 2014-12-29
363 186.240144 2014-12-30
364 186.370181 2014-12-31
파이썬 datetime 자료형은 toordinal 명령으로 특정 시점으로부터 경과한 시간의 일단위 값을 구하거나 timestamp 메서드로 초단위 값을 구할 수 있다.
1
2
3
4
5
import datetime as dt

df_elec["Ordinal"] = df_elec.Date.map(dt.datetime.toordinal)
df_elec["Timestamp"] = df_elec.Date.map(dt.datetime.timestamp)
df_elec.tail()

Demand Date Ordinal Timestamp
360 173.727990 2014-12-27 735594 1.419606e+09
361 188.512817 2014-12-28 735595 1.419692e+09
362 191.273009 2014-12-29 735596 1.419779e+09
363 186.240144 2014-12-30 735597 1.419865e+09
364 186.370181 2014-12-31 735598 1.419952e+09
여기에서는 일단위 시간 값을 사용하여 회귀분석을 한다. 시간 값의 경우 크기가 크므로 반드시 스케일링을 해 주어야 한다.
1
2
3
model5 = sm.OLS.from_formula("Demand ~ scale(Ordinal)", data=df_elec)
result5 = model5.fit()
print(result5.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 Demand   R-squared:                       0.031
Model:                            OLS   Adj. R-squared:                  0.028
Method:                 Least Squares   F-statistic:                     11.58
Date:                Thu, 14 May 2020   Prob (F-statistic):           0.000739
Time:                        19:35:40   Log-Likelihood:                -1709.7
No. Observations:                 365   AIC:                             3423.
Df Residuals:                     363   BIC:                             3431.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==================================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------
Intercept        221.2775      1.374    160.997      0.000     218.575     223.980
scale(Ordinal)    -4.6779      1.374     -3.404      0.001      -7.381      -1.975
==============================================================================
Omnibus:                       43.105   Durbin-Watson:                   0.677
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               96.485
Skew:                           0.614   Prob(JB):                     1.12e-21
Kurtosis:                       5.199   Cond. No.                         1.00
==============================================================================

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


하지만 시간 독립변수는 이 외에더 다양한 특징들을 숨기고 있다. 예들 들어 연도, 월, 일, 요일 데이터를 별도의 독립변수로 분리하거나 한 달 내에서 몇번째 날짜인지 월의 시작 또는 끝인지를 나타내는 값은 모두 특징값이 될 수 있다. 판다스에서는 dt 특수 연산자를 사용하여 이러한 값을 구할 수 있다.
1
2
3
4
5
6
7
8
9
10
df_elec["Year"] = df_elec['Date'].dt.year
df_elec["Month"] = df_elec.Date.dt.month
df_elec["DayOfYear"] = df_elec.Date.dt.dayofyear
df_elec["DayOfMonth"] = df_elec.Date.dt.daysinmonth
df_elec["DayOfWeek"] = df_elec.Date.dt.dayofweek
df_elec["WeekOfYear"] = df_elec.Date.dt.weekofyear
df_elec["Weekday"] = df_elec.Date.dt.weekday
df_elec["IsMonthStart"] = df_elec.Date.dt.is_month_start
df_elec["IsMonthEnd"] = df_elec.Date.dt.is_month_end
df_elec.tail()

Demand Date Ordinal Timestamp Year Month DayOfYear DayOfMonth DayOfWeek WeekOfYear Weekday IsMonthStart IsMonthEnd
360 173.727990 2014-12-27 735594 1.419606e+09 2014 12 361 31 5 52 5 False False
361 188.512817 2014-12-28 735595 1.419692e+09 2014 12 362 31 6 52 6 False False
362 191.273009 2014-12-29 735596 1.419779e+09 2014 12 363 31 0 1 0 False False
363 186.240144 2014-12-30 735597 1.419865e+09 2014 12 364 31 1 1 1 False False
364 186.370181 2014-12-31 735598 1.419952e+09 2014 12 365 31 2 1 2 False True
이렇게 추가적인 특징값을 이용하여 구한 모형은 성능이 향상된다.
1
2
3
4
5
6
7
8
9
10
11
feature_names = df_elec.columns.tolist()
feature_names.remove("Demand")
feature_names.remove("Date")

formula = """
Demand ~ scale(Ordinal) + C(Month) + DayOfYear +
C(DayOfMonth) + C(DayOfWeek) + C(Weekday) + C(IsMonthStart) + C(IsMonthEnd)
"""
model6 = sm.OLS.from_formula(formula, data=df_elec)
result6 = model6.fit()
print(result6.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 Demand   R-squared:                       0.537
Model:                            OLS   Adj. R-squared:                  0.511
Method:                 Least Squares   F-statistic:                     19.98
Date:                Thu, 14 May 2020   Prob (F-statistic):           4.74e-46
Time:                        19:37:49   Log-Likelihood:                -1574.8
No. Observations:                 365   AIC:                             3192.
Df Residuals:                     344   BIC:                             3273.
Df Model:                          20                                         
Covariance Type:            nonrobust                                         
===========================================================================================
                              coef    std err          t      P>|t|      [0.025      0.975]
-------------------------------------------------------------------------------------------
Intercept                  58.6105      2.423     24.188      0.000      53.844      63.377
C(Month)[T.2]              14.5730      4.587      3.177      0.002       5.551      23.595
C(Month)[T.3]              -1.2369      8.663     -0.143      0.887     -18.276      15.802
C(Month)[T.4]             -29.1875     10.239     -2.851      0.005     -49.326      -9.049
C(Month)[T.5]              23.4037     15.493      1.511      0.132      -7.069      53.876
C(Month)[T.6]              11.3667      3.758      3.024      0.003       3.974      18.759
C(Month)[T.7]              64.8095     22.750      2.849      0.005      20.063     109.556
C(Month)[T.8]              66.5692     26.490      2.513      0.012      14.467     118.671
C(Month)[T.9]              22.7687      9.491      2.399      0.017       4.100      41.437
C(Month)[T.10]             59.0491     33.895      1.742      0.082      -7.619     125.717
C(Month)[T.11]             33.4276     16.778      1.992      0.047       0.427      66.429
C(Month)[T.12]             72.2523     41.334      1.748      0.081      -9.047     153.552
C(DayOfMonth)[T.30]        38.3755     13.530      2.836      0.005      11.763      64.988
C(DayOfMonth)[T.31]         5.6620      7.806      0.725      0.469      -9.691      21.015
C(DayOfWeek)[T.1]           3.4766      1.829      1.900      0.058      -0.121       7.075
C(DayOfWeek)[T.2]           1.5756      1.821      0.865      0.387      -2.006       5.157
C(DayOfWeek)[T.3]           2.8568      1.831      1.560      0.120      -0.745       6.459
C(DayOfWeek)[T.4]           0.8832      1.831      0.482      0.630      -2.719       4.485
C(DayOfWeek)[T.5]         -12.8982      1.831     -7.045      0.000     -16.499      -9.297
C(DayOfWeek)[T.6]         -16.4623      1.829     -8.999      0.000     -20.060     -12.864
C(Weekday)[T.1]             3.4766      1.829      1.900      0.058      -0.121       7.075
C(Weekday)[T.2]             1.5756      1.821      0.865      0.387      -2.006       5.157
C(Weekday)[T.3]             2.8568      1.831      1.560      0.120      -0.745       6.459
C(Weekday)[T.4]             0.8832      1.831      0.482      0.630      -2.719       4.485
C(Weekday)[T.5]           -12.8982      1.831     -7.045      0.000     -16.499      -9.297
C(Weekday)[T.6]           -16.4623      1.829     -8.999      0.000     -20.060     -12.864
C(IsMonthStart)[T.True]     1.2012      5.781      0.208      0.836     -10.169      12.571
C(IsMonthEnd)[T.True]       4.7608      5.781      0.824      0.411      -6.609      16.131
scale(Ordinal)           -101.7884      4.209    -24.182      0.000    -110.068     -93.509
DayOfYear                   0.6769      0.085      7.926      0.000       0.509       0.845
==============================================================================
Omnibus:                      150.460   Durbin-Watson:                   0.577
Prob(Omnibus):                  0.000   Jarque-Bera (JB):             1586.415
Skew:                           1.422   Prob(JB):                         0.00
Kurtosis:                      12.809   Cond. No.                     1.05e+18
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The smallest eigenvalue is 1.49e-29. This might indicate that there are
strong multicollinearity problems or that the design matrix is singular.
1
2


1
2


You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.