1. 라소 (Lasso)
확장된 보스턴 주택가격 데이터셋에 라소를 적용해보겠습니다.
from sklearn.linear_model import Lasso
lasso = Lasso().fit(X_train, y_train)
print("훈련 세트 점수 : {:.2f}".format(lasso.score(X_train, y_train)))
print("테스트 세트 점수 : {:.2f}".format(lasso.score(X_test, y_test)))
print("사용한 특성의 개수 : ", np.sum(lasso.coef_ != 0))
# lasso.coef_ != 0 을 하면 0이 아닌 값은 true, 0인 값은 false 인 np 1차원 배열이 생성
# bool 값의 1차원 배열의 sum 은 true 의 개수를 반환
# 따라서 coef 의 값이 0 이 아닌 개수를 반환한다.
# pandas dataframe 에서도 필터링할때 사용하는 방법이다.
결과에서 볼 수 있듯이 Lasso 는 훈련 세트와 테스트 세트 모두에서 결과가 좋지 못했습니다. 이는 과소적합하다는 것을 보여주며, 104개의 특성중 4개의 특성만을 사용한 것을 볼 수 있습니다.
Ridge와 마찬가지로 Lasso 도 계수를 얼마나 강하게 0으로 보낼지를 조절하는 alpha 매개변수를 지원합니다. 앞에서는 기본값인 alpha = 1.0 을 사용했습니다. 과소적합을 줄이기 위해 alpha 값을 줄여보겠습니다.
(* 이렇게 하려면 max_iter (* 반복 실행하는 최대 횟수) 의 기본값을 늘려야 합니다.)
(* Lasso 는 L1,L2 규제를 함께 사용하는 엘리스틱넷(* Elastic_Net) 방식에서 L2 규제가 빠진 것입니다. 이들은 한 특성씩 좌표축을 따라 최적화하는 좌표 하강법(* coordinate descent) 방식을 이용하며 학습과정이 반복적으로 여러 번 진행되면서 최적의 해를 찾습니다. 이때 alpha 값을 줄이게 되면 가장 낮은 오차를 찾아가는 이 반복횟수가 늘어나게 됩니다.)
alpha 값을 낮추면 모델의 복잡도는 증가하여 훈련 세트와 테스트 세트에서의 성능이 좋아집니다. 성능은 Ridge 보다 조금 나은데 사용된 특성은 104개 중 33개 뿐이어서, 아마도 모델을 분석하기가 조금 더 쉽습니다.
그러나 alpha 값을 너무 낮추면 규제의 효과가 없어져 과대적합 되므로 LinearRegression 과 성능이 비슷해집니다.
alpha = 1 일 때 계수 대부분이 0일 뿐만 아니라 나머지 계수들도 크기가 작다는 것을 알 수 있습니다. alpha = 0.01 로 줄이면 대부분의 특성이 0이 되는 분포를 얻게 됩니다. alpha = 0.1 인 Ridge 모델은 alpha=0.01 인 Lasso 모델과 성능이 비슷하지만 Ridge 를 사용하면 어떤 계수도 0이 되지 않습니다.
실제로 이 두 모델 중 보통은 리지 회귀를 선호합니다. 하지만 특성이 매우 많고 그중 이부분만 중요하다면 Lasso 가 좋은 선택일 수 있습니다. 또한 분석하기 쉬운 모델을 원한다면 Lasso 가 입력 특성 중 일부만 사용하므로 쉽게 해석할 수 있는 모델을 만들어줄 것입니다.
scikit-learn 은 Lasso 와 Ridge 의 페널티를 결합한 ElasticNet 도 제공합니다. 실제로 이 조합은 최상의 성능을 내지만 L1 규제와 L2 규제를 위한 매개변수 두 개를 조정해야 합니다.
2. 분류용 선형 모델
2.1 이진 분류 (binary classification)
선형 모델은 분류에도 사용됩니다. 먼저 이진 분류(* binary classification) 를 살펴보겠습니다. 이 경우 예측을 위한 방정식은 다음과 같습니다.
- y_hat = w[0] x X[0] + w[1] x X[1] + ... + w[p] x X[p] > 0
이 방정식은 선형 회귀와 매우 비슷합니다. 하지만 특성들의 가중치 합을 그냥 사용하는 대신 예측한 값을 임계치 0과 비교합니다. 함수에서 계산한 값이 0보다 작으면 클래스를 -1 이라고 예측하고 0보다 크면 +1 이라고 예측합니다.
회귀용 선형 모델에서는 출력 y_hat 이 특성의 선형 함수였습니다. 즉 직선, 평면, 초평면(* 차원이 3 이상일 때) 입니다. 분류용 선형 모델에서는 결정 경계(* Decision Boundary) 가 입력의 선형 함수입니다. 다른 말로 하면 (이진)선형 분류기는 선, 평면, 초평면을 이용하여 두 개의 클래스를 구분하는 분류기입니다.
선형 모델을 학습시키는 알고리즘은 다양한데, 다음의 두 방법으로 구분할 수 있습니다.
- 특정 계수와 절편의 조합이 훈련 데이터에 얼마나 잘 맞는지 측정하는 방법
- 사용할 수 있는 규제가 있는지, 있다면 어떤 방식인지
알고리즘들은 훈련 세트를 잘 학습하는지 측정하는 방법이 각기 다릅니다. 불행하게도 수학적이고 기술적인 이유로, 알고리즘들이 만드는 잘못된 분류의 수를 최소화하도록 w와 b를 저정하는 것은 불가능합니다.
(* 분류에서 잘못 분류된 결과를 직접 나타내는 0-1 손실 함수는 완전한 계단 함수입니다. 따라서 대리할 수 있는 다른 함수(* surrogate loss function) 를 사용하여 최적화를 수행합니다.)
가장 잘 알려진 두 개의 선형 분류 알고리즘은 linear_model.LogisticRegression 에 구현된 로지스틱 회귀(* Logistic Regression) 과 svm.LinearSVC(* SVC는 support vector classifier 의 약자입니다.) 에 구현된 선형 서포트 벡터 머신(* Support Vector Machine) 입니다.
forge 데이터셋을 사용하여 LogisticRegression 과 LinearSVC 모델을 만들고 이 선형 모델들이 만들어낸 결정 경계를 그림으로 나타내보겠습니다.
(* model 의 이름을 __class__.__name__ 으로 얻을 수 있다)
LinearSVC 와 LogisticRegression 으로 만든 결정 경계가 직선으로 표현되었고 위쪽은 클래스 1, 아래쪽은 클래스 0 으로 나누고 있습니다.
이 두 모델은 비슷한 결정 경계를 만들었습니다. 그리고 똑같이 포인트 두 개를 잘못 분류했습니다. 회귀에서 본 Ridge 와 마찬가지로 이 두 모델은 기본적으로 L2 규제를 사용합니다.
LogisticRegression 과 LinearSVC 에서 규제의 강도를 결정하는 매개변수는 C입니다(* C의 기본값은 둘 다 1.0입니다.) C의 값이 높아지면 규제가 감소합니다(* Ridge 의 alpha 와 반대) 다시 말해 매개변수로 높은 C값을 지정하면 모델의 계수 벡터 (w) 는 훈련 세트에 최대한 맞추려고 하고(* Overfitting), 반대의 경우 계수 벡터 (w) 가 0에 가까워지도록 만듭니다.
왼쪽 그림과 같이 규제가 강해진 모델은 비교적 수평에 가까운 결정 경계를 만들었고(* 기울기가 가파르다는것은 특성 하나가 결과에 미치는 영향이 크다는 의미이다. 따라서 규제가 강해지면 특성 하나 하나가 미치는 영향이 줄어들고 자연스레 기울기가 줄어드는 방향으로 이를 해석할 수 있다.) 잘못 분류된 데이터 포인트는 두 개 입니다. C가 커져감에 따라 결정 경계는 더 많이 기울고, 마침내 클래스 0 의 모든 데이터 포인트를 올바로 분류했습니다.
이 데이터셋의 모든 포인트를 직선으로는 완벽히 분류할 수 없기에 클래스 1의 포인트 하나는 여전히 잘못 분류되었습니다. 오른쪽 모델은 과대적합된 것으로 보입니다.
회귀와 비슷하게 분류에서의 선형 모델은 낮은 차원의 데이터에서는 결정 경계가 직선이거나 평면이어서 매우 제한적인 것처럼 보입니다. 하지만 고차원에서는 분류에 대한 선형 모델이 매우 강력해지며 특성이 많아지면 과대적합되지 않는 것이 중요합니다.
유방암 데이터셋을 이용하여 LogisticRegression 을 좀 더 자세히 분석해보겠습니다.
기본값 C=1이 훈련 세트와 테스트 세트 양쪽에서 95% 정확도로 꽤 훌륭한 성능을 내고 있습니다. 하지만 훈련 세트와 테스트 세트의 성능이 매우 비슷하므로 과소적합인 것 같습니다. 모델의 제약을 좀 더 풀어주기 위해 C를 증가시켜보겠습니다.
C=100 을 사용하니 훈련 세트의 정확도가 높아졌고 테스트 세트의 정확도도 조금 증가했습니다. 이는 복잡도가 높은 모델일수록 성능이 좋음을 말해줍니다.
이번에는 규제를 더 강하게 하기 위해 기본값 (C=1) 이 아니라 C=0.01 을 사용하면 어떻게 되는 지 살펴보겠습니다.
예상대로 이미 과소적합된 모델에서 더 모델이 단순해지니 훈련 세트와 테스트 세트의 정확도는 기본 매개변수일 때보다 낮아집니다.
(* xticks 의 매개변수로 range(cancer.data.shape[1]) 을 넣어서 (* cancer.data.shape[1] 는 열의 개수, cancer.data.shape[0] 은 행의 개수) xtick 의 개수를 열의 개수만큼 설정했고, rotation=90 을 해줘서 특성들의 이름이 겹쳐서 보이지 않도록 해줬다. logreg.coef_ 는 transpose 해주어서 가로로 볼 수 있게 해주었다.)
(* NOTE : 세 번째 계수(mean perimeter) 를 보면 재미 있는 현상을 확인할 수 있습니다. C=100, C=1 일 때 이 계수는 음수이지만, C=0.01 일 때는 양수가 되며 C=1 일 때보다도 절댓값이 더 큽니다. 이와 같은 모델을 해석하면 계수가 클래스와 특성의 연관성을 알려줄 수 있습니다. 예를 들면 높은 "texture error" 특성은 악성인 샘플과 관련이 깊습니다. 그러나 "mean perimeter" 계수의 부호가 바뀌는 것으로 보아 "mean perimeter" 값은 양성이나 악성의 신호 모두가 될 수 있습니다)
더 이해하기 쉬운 모델을 원한다면 L1 규제를 사용하는 것이 좋습니다.
for C, marker in zip([0.001, 1, 100], ['o', '^', 'v']):
lr_l1 = LogisticRegression(solver='liblinear', C=C, penalty="l1",
max_iter=1000).fit(X_train, y_train)
print("C={:.3f} 인 ㅣ1 로지스틱 회귀의 훈련 정확도: {:.2f}"
.format(C, lr_l1.score(X_train, y_train)))
print("C={:.3f} 인 ㅣ1 로지스틱 회귀의 테스트 정확도: {:.2f}"
.format(C, lr_l1.score(X_test, y_test)))
plt.plot(lr_l1.coef_.T, marker, label="C={:.3f}".format(C))
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
xlims = plt.xlim()
plt.hlines(0, xlims[0], xlims[1])
plt.xlabel("feature")
plt.ylabel("feature value")
plt.ylim(-5,5)
plt.legend(loc=3)
(* LinearSVC 는 loss 매개변수에 사용할 손실 함수를 지정합니다. 기본값은 제곱 힌지 손실인 'squared_hinge' 입니다. 제곱 힌지 손실 함수는 penalty 매개변수에 'l1' 과 'l2' 를 지정할 수 있습니다. 다른 손실 함수로는 힌지 손실인 'hinge' 를 지정할 수 있습니다. 이 때는 penalty 매개변수에 'l2' 만을 사용할 수 있습니다.)
(* LogisticRegression 은 penalty 매개변수에 'l1' 과 'l2' 그리고 L1, L2 규제를 모두 사용하는 'elasticnet', 마지막으로 규제를 사용하지 않으려면 'none' 으로 지정할 수 있습니다. 사용할 알고리즘을 지정하는 solver 매개변수를 'saga' 로 지정하면 모든 페널티를 지정할 수 있습니다. 만약 'liblinear' 로 지정하면 'l1' 과 'l2' 를 지정할 수 있습니다. 그 외 'newton-cg', 'lbfgs', 'sag' 는 'l2'와 'none' 만 지원합니다.)
(* LogisticRegression 과 LinearSVC 는 알고리즘이 max_iter 반복 안에 수렴하지 않는 경우 반복 횟수를 증가시키라는 경고를 출력합니다. LogisticRegression 의 기본값은 100이고, LinearSVC 의 기본값은 1000입니다.)
회귀에서처럼, 모델들의 주요 차이는 규제에서 모든 특성을 이용할지 일부 특성만을 사용할지 결정하는 penalty 매개변수입니다.
- feedback
hinge, squared_hinge, saga, liblinear, newton-cg, lbfgs, sag 에 대해 알 필요가 있음
L1, L2 규제에 대해 자세히 알 필요가 있음(-> 4.1 로 포스팅 함)
'[Deep daiv.] > 머신러닝' 카테고리의 다른 글
머신러닝 공부 4.1 - 규제 Regularization (0) | 2024.03.30 |
---|---|
머신러닝 공부 - 3 Ridge Regression and Lasso (0) | 2024.03.23 |
머신러닝 공부 - 2 KNN Regression and Linear Model (0) | 2024.03.22 |
머신러닝 공부 - 1 머신러닝에 대한 기본적인 이해와 KNN 알고리즘 (0) | 2024.03.19 |