[혼공머신] 4-1. 로지스틱 회귀

Seyi·2025년 1월 10일
0

오늘의 학습 목표는

🥕 로지스틱 회귀 알고리즘 배우기
🥕 이진 및 다중 분류 문제에서 클래스 확률 예측

입니다~!




마케팅 팀에서 럭키백 프로모션을 제안했습니다. 럭키백의 물품은 생선으로 한정하기로 했는데요, 럭키백에 포함된 생선의 확률을 고객에게 알려주는 방향으로 이벤트를 수정하기로 했습니다.

1. 럭키백의 확률

럭키백의 생선이 어떤 타깃에 속하는지 확률을 구해보겠습니다.

럭키백에 들어가는 생선은 7개 입니다. 생선의 무게, 길이, 높이, 두께, 대각선 등이 주어졌을 때 7개 생선에 대한 확률을 출력해야합니다.

K-최근접 이웃 알고리즘을 사용해서 문제를 해결해보겠습니다.

그림의 샘플 X 주위에 가장 가까운 이웃 샘플 10개를 표시했습니다. X가 사각형일 확률은 30%, 삼각형일 확률은 50%, 원일 확률은 20% 입니다.

데이터 준비

생선의 종류는 총 7가지 입니다. 이 데이터에서 Species 열을 타깃으로 만들고 나머지 5개 열은 입력 데이터로 사용하겠습니다.

데이터 프레임에서 특성에 해당하는 열을 선택해서 넘파이 배열 형태로 fish_input에 저장했습니다.

동일한 방식으로 타깃 데이터를 만들었습니다.

훈련세트와 테스트세트를 나누고 표준화 전처리를 수행했습니다.


K-최근접 이웃 분류기의 확률 예측

사이킷런의 KNeighborsClassifier 클래스 객체를 만들고 훈련 세트로 모델을 훈련한 다음 훈련 세트와 테스트 세트의 점수를 확인해보겠습니다.

다중분류

  • 타깃 데이터에 2개 이상의 클래스가 포함된 문제

이진분류 모델은 클래스를 1과 0으로 지정하여 타깃 데이터를 만들었습니다. 다중 분류에서도 타깃값을 숫자로 바꾸어 입력할 수 있지만 사이킷럼에서는 문자열로 된 타깃값을 그대로 사용할 수 있습니다.

타깃값을 사이킷런 모델에 전달하면 순서가 자동으로 알파벳 순으로 매겨집니다. 정렬된 타깃값은 classes_ 속성에 저장되어있습니다. 그리고 predict( ) 매서드를 사용하면 타깃값으로 예측을 출력해줍니다.

predict_proba( )

  • 예측이 어떤 확률로 만들어졌는지 클래스별 확률값을 반환

np.round( )

  • 소수점 첫째 자리에서 반올림해주는 함수
  • decimals 매개변수를 통해 유지할 소수점 아래 자릿수 지정 가능

predictprob( ) 매서드의 출력 순서는 classes 속성과 같습니다. 즉 첫 번째 열이 'Bream'에 대한 확률, 두 번째 열이 'Parkki'에 대한 확률입니다.

모델이 계산한 확률이 가장 가까운 이웃의 비율이 맞는지 확인해보겠습니다.

kneighbors( ) 매서드의 입력은 항상 2차원 배열이어야 한다. 슬라이싱 연산자는 하나의 샘플만 선택해도 2차원 배열이 만들어진다.

4번째 샘플의 이웃은 Roach가 1개 Perch가 2개 입니다. 따라서 다섯번째 클래스인 'Roach'에 대한 확률은 1/3=0.3333 이고, 세 번째 클래스인 'Perch'에 대한 확률은 2/3=0.6667이 됩니다.

그런데 3개의 이웃만을 사용하기 때문에 가능한 확률은 0, 1/3, 2/3, 1 이 전부네요. 다른 방법을 찾아보도록 하겠습니다!




2. 로지스틱 회귀

로지스틱 회귀

  • 분류 모델
  • 선형 회귀와 동일하게 선형 방정식을 학습

a, b, c, d, e 는 가중치 혹은 계수입니다. 여기서 z가 확률이 되려면 0~1(혹은 0~100%) 사이의 값이 되어야 합니다. 이 때 시그모이드 함수(sigmoid function) 또는 로지스틱 함수(logistic function)을 사용하면 가능합니다.

왼쪽 식이 시그모이드 함수이고, 선형 방정식의 출력 z의 음수를 사용해 자연 상수 e를 거듭제곱하고 1을 더한 값의 역수를 취합니다. 오른쪽의 시그모이드 그래프를 보면 z가 무한하게 큰 음수일 경우 함수값은 0에 가까워지고 z가 무한하게 큰 양수일 때는 1에 가까워 지며 z가 0이 될때는 0.5가 욉니다.

넘파이를 사용해서 시그모이드 그래프를 그려보았습니다.

np.exp( )

  • 지수함수 계산에 사용하는 함수

로지스틱 회귀로 이진 분류 수행하기

로지스틱 회귀모델을 사용해서 이진분류를 먼저 수행해보겠습니다. 시그모이드 함수의 출력이 0.5보다 크면 양성 클래스, 0.5보다 작으면 음성 클래스로 판단합니다.

불리언 인덱싱

  • 넘파이 배열에서 True, False 값을 전달하여 행을 선택하는 방법

불리언 인덱싱을 사용해서 훈련세트에서 도미와 빙어의 행만을 골라 이진분류 데이터셋을 구성합니다.

bream_smelt_indexes 배열은 도미와 빙어일 경우 True 이고 그 외는 모두 False 값이 들어가 있습니다. 따라서 이 배열을 사용해 train_scaled와 train_target 배열에 불리언 인덱싱을 적용하면 도미와 빙어데이터를 골라낼 수 있습니다.

sklearn.linear_model 패키지의 LogisticRegression 클래스를 호출해서 로지스틱 회귀 모델을 훈련했습니다. 처음 5개 샘플에 대해서 예측을 해보았더니 두 번재 샘플을 제외하고는 모두 도미로 예측했습니다. 예측 확률도 출력해보겠습니다.

predict_proba( )

  • 예측 확률 반환 매서드
  • 이진 분류의 경우에는 샘플마다 음성 클래스와 양성 클래스에 대한 확률을 반환
  • 다중 분류의 경우에는 샘플마다 모든 클래스에 대한 확률을 반환

샘플마다 2개의 확률이 출력되었는데요, 첫번재는 음성 클래스(0)에 대한 확률이고 두번째는 양성 클래스(1)에 대한 확률입니다. Bream과 Smelt 중에서 어떤 것이 양성 클래스인지는 classes_속성에서 확인할 수 있습니다.

Bream이 음성, Smelt가 양성 클래스인걸 확인했습니다.

이번에는 선형회귀에서 로지스틱 회귀가 학습한 계수를 확인해보겠습니다.

이 로지스틱 회귀 모델이 학습한 방정식은 아래와 같습니다.

z=0.404×(Weight)0.576×(Length)0.663×(Diagonal)1.013×(Height)0.732×(Width)2.161z = -0.404 \times (\text{Weight}) - 0.576 \times (\text{Length}) - 0.663 \times (Diagonal) -1.013 \times (Height) - 0.732 \times (Width) - 2.161

로지스틱 회귀는 선형 회귀와 매우 비슷하다는 걸 알수 있네요. LogisticRegression 모델로 z 값을 계산하기 위해서 decision_function( ) 매서드를 사용해보겠습니다.

decision_function( )

  • 모델이 학습한 선형 방정식의 출력을 반환
  • 이진 분류의 경우 양성 클래스의 확률이 반환 -> 이 값이 0보다 크면 양성 클래스, 작거나 같으면 음성 클래스로 예측
  • 다중 분류의 경우 각 클래스마다 선형 방정식을 계산. 가장 큰 값의 클래스가 예측 클래스가 됨

처음 5개 샘플의 z값을 출력해보았습니다. 이 z 값을 시그모이드 함수에 통과시키면 확률을 얻을 수 있습니다. 파이썬의 scipy 라이브러리의 시그모이드 함수인 expit( )을 사용하면됩니다. decisions 배열의 값을 확률로 변환해보겠습니다.

출력된 값을 보면 predict_proba( ) 매서드의 두 번째 열과 동일한데요, decision_function( ) 매서드는 양성 클래스에 대한 z 값을 반환한다는 것을 알 수 있습니다.


로지스틱 회귀로 다중 분류 수행하기

지금까지 로지스틱 회귀 이진 분류 모델을 훈련시켰는데요, 이번에는 로지스틱 회귀 모델을 활용해서 다중 분류를 수행해보겠습니다.

LogisticRegression의 매개변수

  • max_iter : 반복 횟수 지정
  • C: 규제를 제어 하는 매개변수로 작을수록 규제가 커짐. 기본값은 1

우선 충분한 훈련을 위해 max_iter를 1000으로 지정했습니다.

그리고 LogisticRegression 클래스는 기본적으로 릿지 회귀와 같이 계수의 제곱을 규제합니다. 이런 규제를 L2 규제라고 하는데요, 릿지 회귀에서 alpha 매개변수로 규제의 강도를 조절했다면 LogisticRegression에서는 C라는 매개변수를 사용해서 규제를 조절합니다. 이번에는 규제를 완화하기 위해 20으로 지정했습니다.

훈련세트와 테스트세트에 대한 점수가 높고 과대적합이나 과소적합으로 치우치지 않은 것 같습니다. 테스트 세트 처음 5개 샘플에 대한 예측을 해보겠습니다.

예측과 함께 예측 확률을 출력해보았는데요, 5개 샘플에 대한 예측이기 때문에 5개 행이 출력되었고 7개의 생선에 대한 확률을 계산했으므로 7개의 열이 출력되었습니다.

각 열에 해당하는 타깃 생선 정보는 classes_ 속성에서 확인할 수 있습니다.
첫 번째 샘플은 Perch를 가장 높은 확률로 예측했음을 알 수 있습니다.

이진 분류는 샘플마다 2개의 확률을 출력하고 다중 분류는 샘플마다 클래스 개수만큼 확률을 출력합니다. 그렇다면 다중 분류일 경우 선형 방정식은 어떤 모습일까요? coef 와 intercept의 크기를 출력해보겠습니다.

이 데이터는 5개의 특성을 사용하므로 coef 배열의 열은 5개 입니다. 그런데 행이 7개이고 intercept도 7개 입니다. 이 말은 이진분류에서 보았던 z를 7개 계산한다는 의미입니다.

다중 분류는 클래스마다 z 값을 하나씩 계산합니다. 그리고 가장 높은 z값을 출력하는 클래스가 예측 클래스가 됩니다.

이진분류에서는 시그모이드 함수를 사용해 z를 0과 1 사이의 값으로 변환했습니다. 다중 분류는 이와 달리 소프트맥스(softmax) 함수를 사용하여 7개의 z 값을 확률로 변환합니다.

Softmax 함수

  • 여러 개의 선형 방정식의 출력값을 0~1 사이로 압축하고 전체 합이 1이 되도록 만듦
  • 이 과정에서 지수 함수를 사용하기 때문에 정규화된 지수 함수라고도 함

소프트 맥스의 계산 방식을 알아보겠습니다.

먼저 7개의 z를 z1 z7z1~z7 이라고 하고 지수함수 e1e^1~ e7e^7 을 계산해 모두 더합니다.

e_sum=e1+e2+e3+e4+e5+e6+e7\text{e\_sum}= e^1 + e^2 + e^3 + e^4 + e^5 + e^6 + e^7

그리고 나서 e1e^1~ e7e^7 를 각각 e_sum\text{e\_sum}으로 나눠 줍니다.

s1=e1esum,s2=e2esum,s3=e3esum,s4=e4esum,s5=e5esum,s6=e6esum,s7=e7esums_1 = \frac{e_1}{e_{\text{sum}}}, \quad s_2 = \frac{e_2}{e_{\text{sum}}}, \quad s_3 = \frac{e_3}{e_{\text{sum}}}, \quad s_4 = \frac{e_4}{e_{\text{sum}}}, \quad s_5 = \frac{e_5}{e_{\text{sum}}}, \quad s_6 = \frac{e_6}{e_{\text{sum}}}, \quad s_7 = \frac{e_7}{e_{\text{sum}}}

decision_function( ) 매서드로 z1z1~z7z7 까지의 값을 구한 다음 소프트맥스 함수를 사용해 확률로 바꾸어보겠습니다.

테스트 세트의 처음 5개 샘플에 대한 z1z1~z7z7 값을 구했습니다.

scipy.special 의 softmax( ) 함수를 임포트해서 확률을 구했습니다. 여기서 axis 매개변수는 소프트맥스를 계산할 축을 지정합니다. axis=1로 지정하여 각 행, 즉 각 샘플에 대해 소프트맥스를 계산합니다. 만약 axis 매개변수를 지정하지 않으면 전체 배열에 대해서 계산합니다.

드디어 로지스틱 회귀 모델을 사용해서 7개 생선에 대한 확률을 예측하는 모델을 만들었습니다. 👏 👏 👏



자료출처: 한빛미디어

profile
머신러닝 딥러닝 학습기록

0개의 댓글

관련 채용 정보