06_통계분석_1 (Linear Regression)

회귀분석

회귀 유형 : 회귀 계수의 선형/비선형 여부, 독립변수의 개수, 종속변수의 개수에 따라 나뉨

1) 독립변수의 수
단순회귀 : 독립변수와 종속변수가 각각 한개씩이면서 모두 수치형
다중회귀 : 1개의 수치형 종속변수와 2개 이상의 독립변수(수치형 또는 범주형)

2) 독립변수의 척도
일반회귀 : 등간, 비율척도
더미변수를 이용한 회귀 : 명목, 서열척도

3) 독립변수와 종속변수의 관계
선형회귀 : 선형
비선형회귀 : 비선형

선형 회귀 : 실제 값과 예측값의 차이, 즉 RSS(Residual Sum of Squares)를 최소화하는 직선형 회귀선을 최적화하는 방식

규제가 없는 일반 선형 회귀, 선형 회귀에 L1 규제를 추가한 라쏘(Lasso) 회귀, L2 규제를 추가한 릿지(Ridge) 회귀, L1/L2규제를 결합한 엘라스틱넷(ElasticNet) 회귀, 분류에 사용되는 선형 모델인 로지스틱 회귀(Logistic Regression)

전제조건(가정)

선형성(선형회귀에 한함) : 독립변수와 종속변수 간에는 선형관계가 존재
일부가 선형성을 만족하지 않는다면, 일단 선형 회귀모델을 만들고 변수 선택법으로 처리하거나, 다른 새로운 변수를 추가해보거나, 선형성을 만족하지 않는 변수를 제거하거나, 로그/지수/루트 등 변수 변환하는 방법으로 처리
등분산성 : 잔차들은 동일한 분산을 가짐, 분산이 같다는 것은 특정한 패턴 없이 고르게 분포했다는 의미
독립성(다중회귀에 해당) : 잔차들은 서로 독립(독립변수 x 간에 상관관계가 없이 독립성을 만족)
Stepwise를 사용해서 다중공선성을 일으키는 변수들을 제거하는 방법으로 처리
정규성 : 잔차가 정규분포를 따름. Shapiro-Wilk Test로 확인

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# print를 하지 않아도 행을 모두 보여줌
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

# Columns를 생략 없이 모두 보여줌
from IPython.display import display
pd.options.display.max_columns = None

[ sklearn package의 LinearRegression Class ]

[ statsmodels package의 formula.api Module ]

[ 회귀 평가 지표 ]



1. 단순회귀분석

# 예제 데이터셋
height = [170, 168, 177, 181 ,172, 171, 169, 175, 174, 178, 170, 167, 177, 182 ,173, 171, 170, 179, 175, 177, 186, 166, 183, 168]
weight = [70, 66, 73, 77, 74, 73, 69, 79, 77, 80, 74, 68, 71, 76, 78, 72, 68, 79, 77, 81, 84, 73, 78, 69]

body = pd.DataFrame(
    {'height': height,
    'weight': weight
    }
)
body.head(3)
height weight
0 170 70
1 168 66
2 177 73
plt.plot(body['weight'], body['height'], 'o')
plt.show()
[<matplotlib.lines.Line2D at 0x2a0371e55e0>]

png

1-1) LinearRegression

# 단순 선형 회귀 모델

import numpy as np
from sklearn.linear_model import LinearRegression

# X데이터를 넣을 때 .values.reshape(-1,1) 이유 : X는 2차원 array 형태여야 하기 때문, 차원증가
X = body['weight'].values.reshape(-1,1) #단순회귀일 때는 reshape 필수
y = body['height']

model = LinearRegression()
model.fit(X, y)

print('R2 : ', model.score(X, y))  # 1에 가까울수록 설명력이 높은데... 0.589

print('회귀계수 :',model.coef_)

print('절편 : ', model.intercept_)

# y = 107.86 + 0.89x
LinearRegression()



R2 :  0.5893075473608536
회귀계수 : [0.89042657]
절편 :  107.86242266362746
# 예측

# print(np.array([80, 70, 100]))
# print(new)
new = np.array([80, 70, 100]).reshape(-1,1) # predict할 때도 reshape 필수
model.predict(new)
array([179.09654836, 170.19228264, 196.90507978])
# 모델 시각화

plt.plot(X, y, 'o')
plt.plot(X,model.predict(X))
plt.show()
[<matplotlib.lines.Line2D at 0x1e22ea61e10>]






[<matplotlib.lines.Line2D at 0x1e22ea6b550>]

png

1-2) statsmodels - formula.api

# statsmodels package 사용
import statsmodels.formula.api as smf

# 단순회귀분석 실행하고 분석결과 출력
# 회귀분석을 지원하는 ols() 함수 : ols(formula='종속변수 ~ 독립변수', data=data1)
model_smf = smf.ols(formula='height ~ weight', data = body).fit()
model_smf.summary()

# 첫번째 테이블 : 수행된 회귀분석 결과의 일반적인 사항을 요약함
    # 종속변수(Dep.Variable), 분석모델(Model), Model의 계산방식(Method)
    # F-statistic : 해당 회귀모형의 적합도를 나타내는 통계량
    # F검정통계량의 유의 확률(Prob(F-statistic) : 1.20e-05로 유의확률이 0.01이하이므로 본 회귀모형은 유의미함
    # 모형의 결정계수(R-squared) 즉 설명력은 0.589 수준으로 나타남
    # 잔차의 자유도(Df Residuals)는 22, 모형의 매개변수 수(DF Model)는 1
    # AIC와 BIC는 복수개 모형의 적합도를 비교할 때 사용하는데 일반적으로 해당 통계량이 작을수록 더 좋은 모형이라고 판단함
      # (이 예제는 1개의 모형만 사용했으므로 해당사항 없음)
# 두번째 테이블 : 모형에 의해 추정된 회귀계수 테이블
    # 계수 추정치의 기본 표준오차(std err), t-value(t), 유의확률(P>|t|)
    # 95% 신뢰구간의 하한/상한값 제시
    # 분석결과 절편(intercept)과 독립변수인 weight는 모두 유의미하게 나타남(0.000???)
# 세번째 테이블 : 잔차의 분포를 평가하기 위한 몇가지 통계량을 보여줌
    # Omnibus : 잔차의 왜도와 첨도를 이용한 검정 통계량으로 0에 가까운 값이 나올수록 정규분포를 따른다고 판단
    # Prob(Omnibus) : Omnibus의 p-value임. 귀무가설로써 정규분포인지 평가함
    # Jarque-Bera(JB)/Prob(JB) : Omnibus와 유사하게 잔차의 왜도와 첨도를 이용해 정규성을 검정하는 통계량
    # 왜도(Skew), 첨도(Kurtosis)
    # Durbin-Watson : 회귀분석 시 잔차의 독립성을 검증할 때 사용하는 통계량. 보통 0~4 값이 출력되며 2에 가까울수록 독립적이라고 판단
    # Cond. No.(Condition Number) : 다중공선성을 평가할 수 있는 통계량. 30보다 작으면 다중공선성이 없다고 판단함
      # (이 예제는 하나의 독립변수만 사용했으므로 해당없음)    
OLS Regression Results
Dep. Variable: height R-squared: 0.589
Model: OLS Adj. R-squared: 0.571
Method: Least Squares F-statistic: 31.57
Date: Sat, 27 Nov 2021 Prob (F-statistic): 1.20e-05
Time: 21:14:49 Log-Likelihood: -63.655
No. Observations: 24 AIC: 131.3
Df Residuals: 22 BIC: 133.7
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept 107.8624 11.816 9.128 0.000 83.357 132.368
weight 0.8904 0.158 5.619 0.000 0.562 1.219
Omnibus: 0.796 Durbin-Watson: 2.201
Prob(Omnibus): 0.672 Jarque-Bera (JB): 0.829
Skew: 0.329 Prob(JB): 0.661
Kurtosis: 2.371 Cond. No. 1.20e+03



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



2. 다중회귀분석

# 예제 데이터셋

X = np.array([[1, 1], [1, 2], [2, 2], [2, 3]])

print('X :\n', X)

# y = ( ( x_0 * 1 ) + ( x_1 * 2 ) ) + 3
y = np.dot(X, np.array([1, 2])) + 3

print('\ny :\n', y)
X :
 [[1 1]
 [1 2]
 [2 2]
 [2 3]]

y :
 [ 6  8  9 11]

2-1) 교호작용을 고려하지 않을 때

import numpy as np
from sklearn.linear_model import LinearRegression

#model = LinearRegression()
#model.fit(X, y)
model = LinearRegression().fit(X, y)

print('R2 : ', model.score(X, y))
print('회귀계수 :',model.coef_)
print('절편 : ', model.intercept_)

# 예측
print(model.predict(np.array([[3, 5]]))) # 정수가 아니라 실수로 출력되네
R2 :  1.0
회귀계수 : [1. 2.]
절편 :  3.0000000000000018
[16.]

2-2) 교호작용을 고려할 때

# 맛보기(다항회귀에서 상세하게)
from sklearn.preprocessing import PolynomialFeatures

poly_d2 = PolynomialFeatures(degree=2, interaction_only=True)
# degree = 2 는 2차까지 만든다는 뜻, X3까지 있으면 degree=3도 가능할 듯
# interaction = True는 교호작용 변수만 만들고, 다항(제곱) 변수는 만들지 않겠다는 것
X_poly = poly_d2.fit_transform(X)

X_poly    # 1, X1, X2, X1*X2 순
array([[1., 1., 1., 1.],
       [1., 1., 2., 2.],
       [1., 2., 2., 4.],
       [1., 2., 3., 6.]])
import numpy as np
from sklearn.linear_model import LinearRegression

model = LinearRegression().fit(X_poly, y)

print('R2 : ', model.score(X_poly, y))
print('회귀계수 :',model.coef_)
print('절편 : ', model.intercept_)

# 예측
print(model.predict(np.array([[1, 3, 5, 15]])))
R2 :  1.0
회귀계수 : [ 0.00000000e+00  1.00000000e+00  2.00000000e+00 -1.55360188e-15]
절편 :  2.9999999999999964
[16.]

2-3) 다중회귀분석 예시 : 집값 예측

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from scipy import stats
from sklearn.datasets import load_boston
%matplotlib inline

# boston 데이터셋 로드
boston = load_boston()

boston
{'data': array([[6.3200e-03, 1.8000e+01, 2.3100e+00, ..., 1.5300e+01, 3.9690e+02,
         4.9800e+00],
        [2.7310e-02, 0.0000e+00, 7.0700e+00, ..., 1.7800e+01, 3.9690e+02,
         9.1400e+00],
        [2.7290e-02, 0.0000e+00, 7.0700e+00, ..., 1.7800e+01, 3.9283e+02,
         4.0300e+00],
        ...,
        [6.0760e-02, 0.0000e+00, 1.1930e+01, ..., 2.1000e+01, 3.9690e+02,
         5.6400e+00],
        [1.0959e-01, 0.0000e+00, 1.1930e+01, ..., 2.1000e+01, 3.9345e+02,
         6.4800e+00],
        [4.7410e-02, 0.0000e+00, 1.1930e+01, ..., 2.1000e+01, 3.9690e+02,
         7.8800e+00]]),
 'target': array([24. , 21.6, 34.7, 33.4, 36.2, 28.7, 22.9, 27.1, 16.5, 18.9, 15. ,
        18.9, 21.7, 20.4, 18.2, 19.9, 23.1, 17.5, 20.2, 18.2, 13.6, 19.6,
        15.2, 14.5, 15.6, 13.9, 16.6, 14.8, 18.4, 21. , 12.7, 14.5, 13.2,
        13.1, 13.5, 18.9, 20. , 21. , 24.7, 30.8, 34.9, 26.6, 25.3, 24.7,
        21.2, 19.3, 20. , 16.6, 14.4, 19.4, 19.7, 20.5, 25. , 23.4, 18.9,
        35.4, 24.7, 31.6, 23.3, 19.6, 18.7, 16. , 22.2, 25. , 33. , 23.5,
        19.4, 22. , 17.4, 20.9, 24.2, 21.7, 22.8, 23.4, 24.1, 21.4, 20. ,
        20.8, 21.2, 20.3, 28. , 23.9, 24.8, 22.9, 23.9, 26.6, 22.5, 22.2,
        23.6, 28.7, 22.6, 22. , 22.9, 25. , 20.6, 28.4, 21.4, 38.7, 43.8,
        33.2, 27.5, 26.5, 18.6, 19.3, 20.1, 19.5, 19.5, 20.4, 19.8, 19.4,
        21.7, 22.8, 18.8, 18.7, 18.5, 18.3, 21.2, 19.2, 20.4, 19.3, 22. ,
        20.3, 20.5, 17.3, 18.8, 21.4, 15.7, 16.2, 18. , 14.3, 19.2, 19.6,
        23. , 18.4, 15.6, 18.1, 17.4, 17.1, 13.3, 17.8, 14. , 14.4, 13.4,
        15.6, 11.8, 13.8, 15.6, 14.6, 17.8, 15.4, 21.5, 19.6, 15.3, 19.4,
        17. , 15.6, 13.1, 41.3, 24.3, 23.3, 27. , 50. , 50. , 50. , 22.7,
        25. , 50. , 23.8, 23.8, 22.3, 17.4, 19.1, 23.1, 23.6, 22.6, 29.4,
        23.2, 24.6, 29.9, 37.2, 39.8, 36.2, 37.9, 32.5, 26.4, 29.6, 50. ,
        32. , 29.8, 34.9, 37. , 30.5, 36.4, 31.1, 29.1, 50. , 33.3, 30.3,
        34.6, 34.9, 32.9, 24.1, 42.3, 48.5, 50. , 22.6, 24.4, 22.5, 24.4,
        20. , 21.7, 19.3, 22.4, 28.1, 23.7, 25. , 23.3, 28.7, 21.5, 23. ,
        26.7, 21.7, 27.5, 30.1, 44.8, 50. , 37.6, 31.6, 46.7, 31.5, 24.3,
        31.7, 41.7, 48.3, 29. , 24. , 25.1, 31.5, 23.7, 23.3, 22. , 20.1,
        22.2, 23.7, 17.6, 18.5, 24.3, 20.5, 24.5, 26.2, 24.4, 24.8, 29.6,
        42.8, 21.9, 20.9, 44. , 50. , 36. , 30.1, 33.8, 43.1, 48.8, 31. ,
        36.5, 22.8, 30.7, 50. , 43.5, 20.7, 21.1, 25.2, 24.4, 35.2, 32.4,
        32. , 33.2, 33.1, 29.1, 35.1, 45.4, 35.4, 46. , 50. , 32.2, 22. ,
        20.1, 23.2, 22.3, 24.8, 28.5, 37.3, 27.9, 23.9, 21.7, 28.6, 27.1,
        20.3, 22.5, 29. , 24.8, 22. , 26.4, 33.1, 36.1, 28.4, 33.4, 28.2,
        22.8, 20.3, 16.1, 22.1, 19.4, 21.6, 23.8, 16.2, 17.8, 19.8, 23.1,
        21. , 23.8, 23.1, 20.4, 18.5, 25. , 24.6, 23. , 22.2, 19.3, 22.6,
        19.8, 17.1, 19.4, 22.2, 20.7, 21.1, 19.5, 18.5, 20.6, 19. , 18.7,
        32.7, 16.5, 23.9, 31.2, 17.5, 17.2, 23.1, 24.5, 26.6, 22.9, 24.1,
        18.6, 30.1, 18.2, 20.6, 17.8, 21.7, 22.7, 22.6, 25. , 19.9, 20.8,
        16.8, 21.9, 27.5, 21.9, 23.1, 50. , 50. , 50. , 50. , 50. , 13.8,
        13.8, 15. , 13.9, 13.3, 13.1, 10.2, 10.4, 10.9, 11.3, 12.3,  8.8,
         7.2, 10.5,  7.4, 10.2, 11.5, 15.1, 23.2,  9.7, 13.8, 12.7, 13.1,
        12.5,  8.5,  5. ,  6.3,  5.6,  7.2, 12.1,  8.3,  8.5,  5. , 11.9,
        27.9, 17.2, 27.5, 15. , 17.2, 17.9, 16.3,  7. ,  7.2,  7.5, 10.4,
         8.8,  8.4, 16.7, 14.2, 20.8, 13.4, 11.7,  8.3, 10.2, 10.9, 11. ,
         9.5, 14.5, 14.1, 16.1, 14.3, 11.7, 13.4,  9.6,  8.7,  8.4, 12.8,
        10.5, 17.1, 18.4, 15.4, 10.8, 11.8, 14.9, 12.6, 14.1, 13. , 13.4,
        15.2, 16.1, 17.8, 14.9, 14.1, 12.7, 13.5, 14.9, 20. , 16.4, 17.7,
        19.5, 20.2, 21.4, 19.9, 19. , 19.1, 19.1, 20.1, 19.9, 19.6, 23.2,
        29.8, 13.8, 13.3, 16.7, 12. , 14.6, 21.4, 23. , 23.7, 25. , 21.8,
        20.6, 21.2, 19.1, 20.6, 15.2,  7. ,  8.1, 13.6, 20.1, 21.8, 24.5,
        23.1, 19.7, 18.3, 21.2, 17.5, 16.8, 22.4, 20.6, 23.9, 22. , 11.9]),
 'feature_names': array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
        'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7'),
 'DESCR': ".. _boston_dataset:\n\nBoston house prices dataset\n---------------------------\n\n**Data Set Characteristics:**  \n\n    :Number of Instances: 506 \n\n    :Number of Attributes: 13 numeric/categorical predictive. Median Value (attribute 14) is usually the target.\n\n    :Attribute Information (in order):\n        - CRIM     per capita crime rate by town\n        - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.\n        - INDUS    proportion of non-retail business acres per town\n        - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)\n        - NOX      nitric oxides concentration (parts per 10 million)\n        - RM       average number of rooms per dwelling\n        - AGE      proportion of owner-occupied units built prior to 1940\n        - DIS      weighted distances to five Boston employment centres\n        - RAD      index of accessibility to radial highways\n        - TAX      full-value property-tax rate per $10,000\n        - PTRATIO  pupil-teacher ratio by town\n        - B        1000(Bk - 0.63)^2 where Bk is the proportion of black people by town\n        - LSTAT    % lower status of the population\n        - MEDV     Median value of owner-occupied homes in $1000's\n\n    :Missing Attribute Values: None\n\n    :Creator: Harrison, D. and Rubinfeld, D.L.\n\nThis is a copy of UCI ML housing dataset.\nhttps://archive.ics.uci.edu/ml/machine-learning-databases/housing/\n\n\nThis dataset was taken from the StatLib library which is maintained at Carnegie Mellon University.\n\nThe Boston house-price data of Harrison, D. and Rubinfeld, D.L. 'Hedonic\nprices and the demand for clean air', J. Environ. Economics & Management,\nvol.5, 81-102, 1978.   Used in Belsley, Kuh & Welsch, 'Regression diagnostics\n...', Wiley, 1980.   N.B. Various transformations are used in the table on\npages 244-261 of the latter.\n\nThe Boston house-price data has been used in many machine learning papers that address regression\nproblems.   \n     \n.. topic:: References\n\n   - Belsley, Kuh & Welsch, 'Regression diagnostics: Identifying Influential Data and Sources of Collinearity', Wiley, 1980. 244-261.\n   - Quinlan,R. (1993). Combining Instance-Based and Model-Based Learning. In Proceedings on the Tenth International Conference of Machine Learning, 236-243, University of Massachusetts, Amherst. Morgan Kaufmann.\n",
 'filename': 'C:\\Users\\Administrator\\anaconda3\\lib\\site-packages\\sklearn\\datasets\\data\\boston_house_prices.csv'}
# boston 데이터셋 DataFrame 변환 
bostonDF = pd.DataFrame(boston.data , columns = boston.feature_names)
bostonDF.head()
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
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
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
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
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
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
# boston dataset의 target array는 주택 가격. 이를 PRICE 컬럼으로 DataFrame에 추가함. 
bostonDF['PRICE'] = boston.target

print('Boston 데이터셋 크기 :', bostonDF.shape, '\n')   # 506 rows, 14 cols
print('Boston 데이터셋 정보 :', bostonDF.info())        # Null 없음. 14 cols 모두 float type
bostonDF.head()
Boston 데이터셋 크기 : (506, 14) 

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 506 entries, 0 to 505
Data columns (total 14 columns):
 #   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  
 0   CRIM     506 non-null    float64
 1   ZN       506 non-null    float64
 2   INDUS    506 non-null    float64
 3   CHAS     506 non-null    float64
 4   NOX      506 non-null    float64
 5   RM       506 non-null    float64
 6   AGE      506 non-null    float64
 7   DIS      506 non-null    float64
 8   RAD      506 non-null    float64
 9   TAX      506 non-null    float64
 10  PTRATIO  506 non-null    float64
 11  B        506 non-null    float64
 12  LSTAT    506 non-null    float64
 13  PRICE    506 non-null    float64
dtypes: float64(14)
memory usage: 55.5 KB
Boston 데이터셋 정보 : None
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT PRICE
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
# 각 컬럼별로 PRICE(주택가격)에 미치는 영향도 조사
# 8개 col에 대해 값이 증가할 수록 PRICE가 어떻게 변하는지 확인

# matplotlib의 subplots() : 여러개의 그래프를 한번에 표현하기 위해 사용
# (ncols : 열 방향으로 위치할 그래프의 수, nrows : 행 방향으로 위치할 그래프의 수, 총 ncols*nrows개의 그래프를 그림)
# 아래는 2개의 행과 4개의 열을 가진 subplots를 이용. axs는 4x2개의 ax를 가짐
fig, axs = plt.subplots(figsize=(16,8) , ncols=4 , nrows=2)
lm_features = ['RM','ZN','INDUS','NOX','AGE','PTRATIO','LSTAT','RAD']
for i , feature in enumerate(lm_features):
    row = int(i/4)
    col = i%4
    # seaborn의 regplot을 이용해 산점도와 선형 회귀 직선을 함께 표현
    sns.regplot(x=feature , y='PRICE',data=bostonDF , ax=axs[row][col])
    
# RM과 LSTAT의 PRICE 영향도가 가장 두드러지게 나타남
# RM은 양 방향의 선형성이 가장 큼. 즉, 방의 크기가 클수록 가격이 증가하는 모습
# LSTAT은 음 방향의 선형성이 가장 큼. 즉, 하위 계층의 비율이 적을수록 가격이 증가하는 모습
<AxesSubplot:xlabel='RM', ylabel='PRICE'>






<AxesSubplot:xlabel='ZN', ylabel='PRICE'>






<AxesSubplot:xlabel='INDUS', ylabel='PRICE'>






<AxesSubplot:xlabel='NOX', ylabel='PRICE'>






<AxesSubplot:xlabel='AGE', ylabel='PRICE'>






<AxesSubplot:xlabel='PTRATIO', ylabel='PRICE'>






<AxesSubplot:xlabel='LSTAT', ylabel='PRICE'>






<AxesSubplot:xlabel='RAD', ylabel='PRICE'>

png

# 학습과 테스트 데이터 세트로 분리하고 학습/예측/평가 수행

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'],axis=1,inplace=False)

X_train , X_test , y_train , y_test = train_test_split(X_data , y_target ,test_size=0.3, random_state=156)

# Linear Regression OLS로 학습/예측 수행
lr = LinearRegression()
lr.fit(X_train ,y_train )
y_preds = lr.predict(X_test)

# 평균제곱오차(MSE, Mean squared error) : 수치가 작을 수록 원본과의 오차가 적은 것
mse = mean_squared_error(y_test, y_preds)

# 평균제곱근오차(RMSE, Root mean squared error) : 수치가 낮을수록 정확도가 높다고 판단
rmse = np.sqrt(mse)

print('MSE : {0:.3f}\nRMSE : {1:.3F}'.format(mse , rmse))
print('Variance score : {0:.3f}'.format(r2_score(y_test, y_preds)))
LinearRegression()



MSE : 17.297
RMSE : 4.159
Variance score : 0.757
print('절편 :',lr.intercept_)
print('회귀 계수 :', np.round(lr.coef_, 1))
절편 : 40.995595172164336
회귀 계수 : [ -0.1   0.1   0.    3.  -19.8   3.4   0.   -1.7   0.4  -0.   -0.9   0.
  -0.6]
# 회귀 계수를 큰 값 순으로 정렬하기 위해 Series로 생성. index 컬럼명에 유의
coeff = pd.Series(data=np.round(lr.coef_, 1), index=X_data.columns )
coeff.sort_values(ascending=False)

# RM이 양의 값으로 회귀 계수가 가장 큼
# NOX의 회귀 계수 - 값이 상대적으로 너무 커 보임. 최적화 필요할 듯
RM          3.4
CHAS        3.0
RAD         0.4
ZN          0.1
INDUS       0.0
AGE         0.0
TAX        -0.0
B           0.0
CRIM       -0.1
LSTAT      -0.6
PTRATIO    -0.9
DIS        -1.7
NOX       -19.8
dtype: float64
#### Cross Validation 해보기

from sklearn.model_selection import cross_val_score

y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'],axis=1,inplace=False)
lr = LinearRegression()

# cross_val_score( )로 5 Fold 셋으로 MSE를 구한 뒤 이를 기반으로 다시 RMSE 구함
# cross_val_score()의 인자로 scoring="neg_mean_squared_error"를 지정하면 반환되는 수치 값은 음수 값이므로 -1을 곱해서 양의 값으로
neg_mse_scores = cross_val_score(lr, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
rmse_scores  = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)

# cross_val_score(scoring="neg_mean_squared_error")로 반환된 값은 모두 음수 
print(' 5 folds 의 개별 Negative MSE scores : ', np.round(neg_mse_scores, 2))
print(' 5 folds 의 개별 RMSE scores : ', np.round(rmse_scores, 2))
print(' 5 folds 의 평균 RMSE : {0:.3f} '.format(avg_rmse))
 5 folds 의 개별 Negative MSE scores :  [-12.46 -26.05 -33.07 -80.76 -33.31]
 5 folds 의 개별 RMSE scores :  [3.53 5.1  5.75 8.99 5.77]
 5 folds 의 평균 RMSE : 5.829