본문 바로가기
LG 헬로비전 DX DATA SCHOOL/Python

회귀분석

by 황밤 2023. 8. 30.
728x90
반응형

2023/08/30

 

 

 

 

6) 다변량 회귀 분석

  • 독립 변수의 개가 2개 이상인 경우
  • LinearRegression 클래스를 이용해서 수행 가능
  • 다변량 회귀를 수행할 때 주의할 점은 다중 공선성 문제
  • 보스톤 주택 가격 예측
#데이터 가져오기
y_target = bostonDF['PRICE]
X_data = bostionDF.drop(['PRICE'], axis =1, inplace = False)
print(y_target.head())
print(X_data.head())
#훈련 데이터와 테스트 데이터 분리

from sklearn.model_selection import train_test_split

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

print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
#회귀 모델을 생성하고 훈련
from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(X_train, y_train)
#평가

y_pred = lr.predict(X_test)

from sklearn.metrics import mean_squared_error, r2_score
#mse 는 낮아야하고 r2 score은 높아야 좋다.

mse = mean_squared_error(y_test, y_pred) # 제곱이므로 test, pred의 순서가 상관이 없음, 스케일이 큼
r2score = r2_score(y_test, y_pred)

#mse의 제곱근이나 로그를 사용하기도 함.
rmse = np.sqrt(mse)
print("MSE :",mse)
print("RMSE :",rmse)
print("R2_score :", r2score)
# 회귀계수와 절편값을 확인

print("절편 :", lr.intercept_)
print("기울기 :", lr.coef_)


##실행결과

절편 : 31.63108403569186
기울기 : [-1.335e-01  3.581e-02  4.952e-02  3.120e+00 -1.542e+01  4.057e+00
 -1.082e-02 -1.386e+00  2.427e-01 -8.702e-03 -9.107e-01  1.179e-02
 -5.471e-01]

 


 

7) 다중 공선성(Multicollinearity)

  • 회귀분석에서 독립 변수들 간에 강한 상관관계가 나타나는 문제
  • 회귀 분석의 전제 가정을 위배하는 것
  • 확인하는 방법
R2_score의 값은 높은데 p-value(유의 확률)도 높은 경우
독립 변수들 간의 상관 계수를 확인
VIF(Variance Inflation Factor - 분산 팽창 요인) 의 값이 10이 넘는 경우
  • 해결하는 방법
상관 관계가 높은 변수들 중에서 하나 or 일부를 제거
변수를 변형하거나 새로운 변수를 이용
주성분 분석 등을 통해서 변수를 하나로 합치기
자료를 수집하는 과정에서 이유를 찾아 해결하기 (어려움)

 

8) statsmodel

  • 통계 분석을 위한 python 패키지 - http://www.statsmodels.org
  • 기초 통계와 회귀 분석에 관련된 기능을 제공
  • score.csv 파일의 데이터를 이용해서 iq와 academy, game, tv를 이용한 시간을 이용해서 score를 예측
df = pd.read_csv("./score.csv", encoding="cp949")
df.head()
import statsmodels.formula.api as sm

result = sm.ols(formula = 'score ~ iq + academy + game + tv', data=df).fit()
print("절편 과 기울기 :", result.params)
print("유의 확률 :", + result.pvalues)
print("결정 계수 :", + result.rsquared)

## 실행결과 
절편 과 기울기 : Intercept    23.299232
iq            0.468422
academy       0.717901
game         -0.838955
tv           -1.385408
dtype: float64
유의 확률 : Intercept    0.117508
iq           0.003376
academy      0.534402
game         0.131001
tv           0.184269
dtype: float64
결정 계수 : 0.9608351062148871

#결정 계수가 높아서 아주 신뢰할 만한 결과인것 같으나, p-value도 높음
#IQ 가 130 이고 학월을 3개 다니고 게임을 2시간, tv를 1시간 보는 학생의 예상 점수

y = result.params.Intercept + 130*result.params.iq + 3*result.params.academy + 2*result.params.game + 1*result.params.tv
print("예상 점수는 :",y)


## 결과

예상 점수는 : 83.28448678034155
#예측값과 실제값의 시각화

plt.figure()
plt.plot(df['score'], label='실제 성적')
plt.plot(result.predict(), label="예측 성적")
plt.xticks(range(0, 10, 1), df['name'])
plt.legend()
plt.show()

#결정 계수가 높아서 오차가 별로 없음

 

#VIF(분산 팽창 요인) 출력
X = df.drop(['score', 'name'], axis =1)

from statsmodels.stats.outliers_influence import variance_inflation_factor

vif = pd.DataFrame()
vif['VIF Factor'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif['Features'] = X.columns
print(vif)

## result

   VIF Factor Features
0   31.162062       iq
1   13.444494  academy
2    3.054510     game
3    7.783607       tv


## academy 제거시

#VIF(분산 팽창 요인) 출력
X = df.drop(['score', 'name', 'academy'], axis =1)

from statsmodels.stats.outliers_influence import variance_inflation_factor

vif = pd.DataFrame()
vif['VIF Factor'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif['Features'] = X.columns
print(vif)

## result
   VIF Factor Features
0    3.542391       iq
1    2.918459     game
2    2.954177       tv

 

#academy 제거 후 변수 들의 계수 확인
import statsmodels.formula.api as sm

result = sm.ols(formula = 'score ~ iq + game + tv', data=df).fit()
print("절편 과 기울기 :", result.params)
print("유의 확률 :", + result.pvalues)
print("결정 계수 :", + result.rsquared)


## 결과
절편 과 기울기 : Intercept    25.047397
iq            0.473669
game         -0.903660
tv           -1.823124
dtype: float64
유의 확률 : Intercept    0.071898
iq           0.001412
game         0.082017
tv           0.020863
dtype: float64
결정 계수 : 0.957351876527423

 


 

 

9) 다항 회귀

  • 모든 관계를 직선으로만 파악할 수 없는데 이 경우 회귀가 독립 변수의 단항식이 아니라 2차나 3차 방정식과 같은 다항식으로 표현되는 것이 다항(Polynomial) 회귀
  • 비선형 회귀와 유사하지만 선형 회귀로 분류
  • 회귀 모델을 선형과 비선형으로 나누는 것은 회귀 계수가 선형인지 비선형인지 이다.
  • sklearn은 비선형 회귀 클래스를 지원하지 않으므로 비선형 회귀를 하고자 하는 경우는 PolynomialFeatures 클래스를 이용해서 피처를 Polynomial(다항식)으로 변환해서 사용.
  • degree 라는 매개변수를 이용해서 다항식 피처로 변환
이 수치가 높을수록 정확도는 높아질 가능성이 높지만 overfitting 될 간으성도 높아집니다.

 

10) 규제

  • L1 과 L2 Loss
L1 Loss : 실제 값과 예측 값 사이의 오차의 절대값을 구하고 그 오차들의 합을 구한 것

L2 Loss : 실제 값에서 예측 값을 뺀 후 제곱한 값들의 합으로 이상치에 더 민감함

Outlier가 적당히 무시되기를 원하면 L1 Loss를 사용하고 Outlier의 등장에 민감하게 반응하고자 하면 L2 Loss를 사용

 

  • L1 과 L2 norm(벡터의 크기를 측정하는 방법)
L1 norm : 맨하튼 거리
L2 norm : 유클리드 거리
  • 일반화 - regularization 
공선성을 다루거나 데이터에서 잡음을 제거해서 과대 적합을 방지하는 것
모델의 복잡도에 패널티를 부여해서 Overfitting을 방지하고 성능을 높이는데 도움을 주는 것
  • 패널티를 부여하는 방법 - 선형 회귀 규제
Ridge
Lasso
ElasticNet
  • L1 정규화 : Lasso

기본 L1 Loss 에 어떤 값을 더해서 가중치가 너무 크지 않은 방향으로 학습되도록 하는 것

0에 가까울 수록 정규화의 효과는 없어지고, 너무 높게 설정하면 가중치가 전부 없어질 수도 있음

 

  • L2 정규화 : Ridge

L2 Loss 에 어떤 값을 더해서 영향력이 적은 방향으로 학습되도록 하는 것

 

  • ElasticNet

Lasso 와 Ridge를 모두 사용

 

  • 정규화를 수행하게 되면 영향력이 약한 피처의 가중치를 감소시키거나 제거해서 조금 더 나은 모델을 만들 수 있음

Lasso 를 적용하면 영향력이 약한 피처의 가중치를 감소시키고 Ridge를 적용하면 영향력이 약한 피처를 제거

 

  • sklearn 에서는 Lasso, Ridge, Elasticnet 이라는 클래스를 이용해서 제공

페널티는 alpha라는 매개변수를 이용해서 설정

 

보스턴 주택 가격에 Ridge 모델 적용
from sklearn.linear_model import Ridge

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

# 적용할 규제 값
from sklearn.model_selection import cross_val_score

alphas = [0, 0.1, 1, 10, 100]

for alpha in alphas :
    ridge = Ridge(alpha = alpha)
    
    neg_mse_scores = cross_val_score(ridge, X_data, y_target,
                                   scoring="neg_mean_squared_error", cv=5)
    avg_rmse = np.mean(np.sqrt(-1 * neg_mse_scores))
    print("alpha {0} 일 때 folds의 평균 RMSE:{1}".format(alpha, avg_rmse))
    
## 실행 결과
    
alpha 0 일 때 folds의 평균 RMSE:5.828658946215806
alpha 0.1 일 때 folds의 평균 RMSE:5.788486627032412
alpha 1 일 때 folds의 평균 RMSE:5.652570965613549
alpha 10 일 때 folds의 평균 RMSE:5.518166280868973
alpha 100 일 때 folds의 평균 RMSE:5.329589628472148

 

11) 조기 종료

  • 선형 회귀가 경사 하강법을 주로 사용하는데 경사 하강법은 반복적인 학습 알고리즘입니다
  • 검증 에러가 최소값에 도달하면 훈련을 조기중지 가능
  • 한 번의 학습이 진행되면 훈련 세트에 대한 에러를 감소시켜 가면서 학습을 하지만 어느 정도에 도달하면 다시 에러가 증가하기 시작합니다.
이 경우가 Overfitting 이 발생을 하기 시작한 지점이 되는데 이 지점에 도달하면 더 이상 학습을 할 필요가 없음
  • 제공되는 대다수의 선형 회귀 모델들은 조기 종료를 할 수 있도록 만들어져 있습니다.

반복 횟수를 설정할 때 max_iter로 설정합니다.

 


12) 선형 회귀를 수행할 때 데이터 변환

  • 범주형 데이터를 인코딩 할 때는 이진 인지 순서형인지 무순서 형인지를 판단해서 인코딩을 수행해야 합니다.
  •  feature 들의 범위가 다른 경우, scaling을 해주는 것이 좋습니다.
  • 타겟의 분포들의 차이가 너무 많이 나면(범위가 너무 넓은 경우) 로그 변환을 해주는 것이 좋다.
로그 변환을 했을 때 만들어진 모델이 성능이 좋은 경우가 많다

 


5. 비선형 회귀

5.1)KNN(최근접 이웃)

  • 이웃의 개수를 설정해서 거리가 가까운 이웃을 구하고 그 이웃의 값을 가지고 예측
  • 분류의 경우는 다수결의 원칙을 따르고 회귀의 경우는 평균을 구해서 예측

평균을 구할 때 가중치를 부여할 수 있다.

 

from sklearn.neighbors import KNeighborsRegressor
#거리를 가지고 가중 평균을 구해서 예측
#uniform을 설정하면 일반 평균
regressor = KNeighborsRegressor(n_neighbors = 3, weights = "distance")

X_train = [
    [0.5, 0.2, 0.1],
    [0.9, 0.7, 0.3],
    [0.4, 0.5, 0.7],
    [0.2, 0.3, 0.5]
]

y_train = [5.0, 6.8, 9.0, 4.3]

regressor.fit(X_train, y_train)

 

X_test = [
    [0.2, 0.1, 0.7],
    [0.4, 0.7, 0.6]
]
pred = regressor.predict(X_test)
print(pred)

## result
[5.893 7.324]

5.2) 트리 기반 회귀

  • 트리 형태로 분할 한 후 leaf node 의 평균을 이용해서 예측
  • 모든 트리 기반 알고리즘은 분류와 회귀 모두에 사용 가능
  • Regressor를 Classifier로 변경하면 됩니다.
  • Decision Tree를 이용한 학습 및 시각화
#샘플 데이터를 생성
np.random.seed(42)
m = 200
X = np.random.rand(m, 1)
y = y * (X - 0.5) ** 2
y = y + np.random.randn(m, 1) / 10

from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(max_depth=2, random_state=42)
#트리 모델 학습
tree_reg.fit(X,y)

 

 

#트리 시각화
from graphviz import Source
from sklearn.tree import export_graphviz

export_graphviz(
        tree_reg,
        out_file="decision_tree.dot",
        feature_names=["X"],
        class_names=["y"],
        rounded=True,
        filled=True
    )

with open('decision_tree.dot') as f:
    dot_graph = f.read()
src = Source(dot_graph)

src
  • max_depth 를 높게 설정하면 중간 가지를 많이 만들어 냅니다.

max_depth를 높게 설정시 분류에서의 정확도나 회귀의 잔차는 좋은 쪽으로 변화할 가능성이 높습니다.

max_depth를 무한정 높게하면 훈련 데이터와 일치하는 모델이 만들어져서 새로운 데이터를 제대로 예측하지 못할 수 있다.

 

from sklearn.tree import DecisionTreeRegressor
#터미널(자식이 없는 노드 - leaf node) 의 개수가 10 이상이어야 한다는 제약
#min_samples_leaf 를 설정하게 되면 각 터미널의 depth 가 일정하지 않을 수 있다

tree_reg = DecisionTreeRegressor(min_samples_leaf=5, random_state=42)
tree_reg.fit(X,y)

#트리 시각화
from graphviz import Source
from sklearn.tree import export_graphviz

export_graphviz(
        tree_reg,
        out_file="./decision_tree.dot",
        feature_names=["X"],
        class_names=["y"],
        rounded=True,
        filled=True
    )

with open('./decision_tree.dot') as f:
    dot_graph = f.read()
src = Source(dot_graph)

src

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
LIST

'LG 헬로비전 DX DATA SCHOOL > Python' 카테고리의 다른 글

군집 분석 2  (0) 2023.09.04
(Python)군집 분석 및 과일 이미지 군집 분석 실습  (0) 2023.09.01
Pandas 의 연산  (0) 2023.08.16
Python 탐색적 시각화  (2) 2023.08.11
Python 데이터 분석 Pandas 2  (0) 2023.08.09