회귀 분석(regression analysis)은 입력 자료(독립 변수) $x$와 이에 대응하는 출력 자료(종속 변수) $y$간의 관계를 정량과 하기 위한 작업이다.
회귀 분석에는 결정론적 모형(Deterministic Model)과 확률적 모형(Probabilistic Model)이 있다.
결정론적 모형은 단순히 독립 변수 $x$에 대해 대응하는 종속 변수 $y$를 계산하는 함수를 만드는 과정이다.
$$ \hat{y} = f \left( x; \{ x_1, y_1, x_2, y_2, \cdots, x_N, y_N \} \right) = f (x; D) = f(x) $$여기에서 $ \{ x_1, y_1, x_2, y_2, \cdots, x_N, y_N \} $ 는 모형 계수 추정을 위한 과거 자료이다.
만약 함수가 선형 함수이면 선형 회귀 분석(linear regression analysis)이라고 한다.
$$ \hat{y} = w_0 + w_1 x_1 + w_2 x_2 + \cdots + w_D x_D $$일반적으로 회귀 분석에 앞서 다음과 같이 상수항을 독립 변수에 포함하는 작업이 필요할 수 있다. 이를 feature augmentation이라고 한다.
$$ x_i = \begin{bmatrix} x_{i1} \\ x_{i2} \\ \vdots \\ x_{iD} \end{bmatrix} \rightarrow x_{i,a} = \begin{bmatrix} 1 \\ x_{i1} \\ x_{i2} \\ \vdots \\ x_{iD} \end{bmatrix} $$augmentation을 하게 되면 모든 원소가 1인 벡터를 feature matrix 에 추가된다.
$$ X = \begin{bmatrix} x_{11} & x_{12} & \cdots & x_{1D} \\ x_{21} & x_{22} & \cdots & x_{2D} \\ \vdots & \vdots & \vdots & \vdots \\ x_{N1} & x_{N2} & \cdots & x_{ND} \\ \end{bmatrix} \rightarrow X_a = \begin{bmatrix} 1 & x_{11} & x_{12} & \cdots & x_{1D} \\ 1 & x_{21} & x_{22} & \cdots & x_{2D} \\ \vdots & \vdots & \vdots & \vdots & \vdots \\ 1 & x_{N1} & x_{N2} & \cdots & x_{ND} \\ \end{bmatrix} $$augmentation을 하면 가중치 벡터(weight vector)도 차원이 증가하여 전체 수식이 다음과 같이 단순화 된다.
$$ w_0 + w_1 x_1 + w_2 x_2 = \begin{bmatrix} 1 & x_1 & x_2 \end{bmatrix} \begin{bmatrix} w_0 \\ w_1 \\ w_2 \end{bmatrix} = x_a^T w $$
In [2]:
from sklearn.datasets import make_regression
bias = 100
X0, y, coef = make_regression(n_samples=100, n_features=1, bias=bias, noise=10, coef=True, random_state=1)
X = np.hstack([np.ones_like(X0), X0])
X[:5]
Out[2]:
OLS는 가장 기본적인 결정론적 회귀 방법으로 Residual Sum of Squares(RSS)를 최소화하는 가중치 벡터 값을 미분을 통해 구한다.
여기에서 그레디언트를 나타내는 다음 식을 Normal equation 이라고 한다.
$$ X^T y - X^TX w = 0 $$Normal equation 에서 잔차에 대한 다음 특성을 알 수 있다.
$$ X^T (y - X w ) = X^T e = 0 $$
In [3]:
y = y.reshape(len(y), 1)
w = np.dot(np.dot(np.linalg.inv(np.dot(X.T, X)), X.T), y)
print("bias:", bias)
print("coef:", coef)
print("w:\n", w)
In [4]:
w = np.linalg.lstsq(X, y)[0]
w
Out[4]:
In [5]:
xx = np.linspace(np.min(X0) - 1, np.max(X0) + 1, 1000)
XX = np.vstack([np.ones(xx.shape[0]), xx.T]).T
yy = np.dot(XX, w)
plt.scatter(X0, y)
plt.plot(xx, yy, 'r-')
plt.show()
sklearn 패키지를 사용하여 선형 회귀 분석을 하는 경우에는 linear_model 서브 패키지의 LinearRegression
클래스를 사용한다.
입력 인수
fit_intercept
: 불리언, 옵션normalize
: 불리언, 옵션속성
coef_
: 추정된 가중치 벡터intercept_
: 추정된 상수항
In [6]:
from sklearn.datasets import load_diabetes
diabetes = load_diabetes()
dfX_diabetes = pd.DataFrame(diabetes.data, columns=["X%d" % (i+1) for i in range(np.shape(diabetes.data)[1])])
dfy_diabetes = pd.DataFrame(diabetes.target, columns=["target"])
df_diabetes0 = pd.concat([dfX_diabetes, dfy_diabetes], axis=1)
df_diabetes0.tail()
Out[6]:
In [7]:
from sklearn.linear_model import LinearRegression
model_diabetes = LinearRegression().fit(diabetes.data, diabetes.target)
print(model_diabetes.coef_)
print(model_diabetes.intercept_)
In [8]:
predictions = model_diabetes.predict(diabetes.data)
plt.scatter(diabetes.target, predictions)
plt.xlabel("target")
plt.ylabel("prediction")
plt.show()
In [9]:
mean_abs_error = (np.abs(((diabetes.target - predictions)/diabetes.target)*100)).mean()
print("MAE: %.2f%%" % (mean_abs_error))
In [10]:
sk.metrics.median_absolute_error(diabetes.target, predictions)
Out[10]:
In [11]:
sk.metrics.mean_squared_error(diabetes.target, predictions)
Out[11]:
In [12]:
from sklearn.datasets import load_boston
boston = load_boston()
dfX_boston = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy_boston = pd.DataFrame(boston.target, columns=["MEDV"])
df_boston0 = pd.concat([dfX_boston, dfy_boston], axis=1)
df_boston0.tail()
Out[12]:
In [13]:
model_boston = LinearRegression().fit(boston.data, boston.target)
print(model_boston.coef_)
print(model_boston.intercept_)
In [14]:
predictions = model_boston.predict(boston.data)
plt.scatter(boston.target, predictions)
plt.xlabel("target")
plt.ylabel("prediction")
plt.show()
In [15]:
mean_abs_error = (np.abs(((boston.target - predictions)/boston.target)*100)).mean()
print("MAE: %.2f%%" % (mean_abs_error))
In [16]:
sk.metrics.median_absolute_error(boston.target, predictions)
Out[16]:
In [17]:
sk.metrics.mean_squared_error(boston.target, predictions)
Out[17]:
statsmodels 패키지에서는 OLS
클래스를 사용하여 선형 회귀 분석을 실시한다.
statsmodels.regression.linear_model.OLS(endog, exog=None)
endog
: 종속 변수. 1차원 배열exog
: 독립 변수, 2차원 배열. statsmodels 의 OLS
클래스는 자동으로 상수항을 만들어주지 않기 때문에 사용자가 add_constant
명령으로 상수항을 추가해야 한다.
모형 객체가 생성되면 fit
, predict
메서드를 사용하여 추정 및 예측을 실시한다.
예측 결과는 RegressionResults
클래스 객체로 출력되면 summary
메서드로 결과 보고서를 볼 수 있다.
In [18]:
df_diabetes = sm.add_constant(df_diabetes0)
df_diabetes.tail()
Out[18]:
In [19]:
model_diabetes2 = sm.OLS(df_diabetes.ix[:, -1], df_diabetes.ix[:, :-1])
result_diabetes2 = model_diabetes2.fit()
result_diabetes2
Out[19]:
In [20]:
print(result_diabetes2.summary())
In [21]:
df_boston = sm.add_constant(df_boston0)
model_boston2 = sm.OLS(df_boston.ix[:, -1], df_boston.ix[:, :-1])
result_boston2 = model_boston2.fit()
print(result_boston2.summary())
RegressionResults
클래스는 분석 결과를 다양한 속성에 저장해주므로 추후 사용자가 선택하여 활용할 수 있다.
In [22]:
dir(result_boston2)
Out[22]:
statsmodel는 다양한 회귀 분석 결과 플롯도 제공한다.
In [23]:
sm.graphics.plot_fit(result_boston2, "CRIM")
plt.show()