[머신러닝] 로지스틱 회귀

hyun·2022년 8월 11일

머신러닝

목록 보기
3/10

로지스틱 회귀

로지스틱 회귀는 이름은 회귀지만 대표적인 분류 알고리즘이다 !
선형 회귀와 비슷하게 선형 방정식을 학습하고, 독립변수와 종속변수간의 관계를 파악하지만, 가장 큰 차이는 다음과 같다.

💡 ... 하지만 로지스틱 회귀는 선형 회귀 분석과는 다르게 종속 변수가 범주형 데이터를 대상으로 하며 입력 데이터가 주어졌을 때 해당 데이터의 결과가 특정 분류로 나뉘기 때문에 일종의 분류 (classification) 기법으로도 볼 수 있다.
출처 : 위키백과

쉽게 말해 선형회귀는 특정한 값(수치형 종속변수)을 예측하고, 로지스틱 회귀는 데이터가 속한 클래스(범주형 종속변수)를 예측하는 것.

따라서 z=ax+by+cz = ax+by+c (x,yx,y 는 특성의 개수이고 두개일 필요는 없다) 와 같은 식에서 zz값을 추정하고, 값을 확률처럼 0~1 사이의 수로 나타내서 어떤 클래스에 속할 확률이 가장 높은지 나타낸다.

이렇게 zz값을 0~1 사이 값으로 바꾸는 데는 시그모이드 함수소프트맥스 함수(다중 로지스틱 회귀 시)가 쓰인다.

  • 시그모이드 함수 식 : xx값과 무관하게 0~1 사이 값을 유지한다.


출처 : 위키백과

실습

실습은 [혼자 공부하는 머신러닝+딥러닝] 서적을 참고하였다.

데이터 가져오기

import pandas as pd
fish = pd.read_csv("https://bit.ly/fish_csv")
fish.isnull().sum()

결측치가 없으므로 바로 진행.
어떤 생선이 있는지부터 확인하자.


# 고윳값 보기
print(pd.unique(fish['Species']))


네 ~ 확인했습니다 ~

훈련/테스트 데이터 생성

# 입-출력값 만들기
fish_input = fish[['Weight', 'Length', 'Diagonal', 'Height', 'Width']].to_numpy()
fish_target = fish['Species'].to_numpy()
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 훈련, 테스트 세트로 나누기
train_input, test_input, train_target, test_target = train_test_split(fish_input, fish_target, random_state=42)
# 표준화 전처리
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)

로지스틱 회귀

# 로지스틱 해보기
bream_smelt_indexes = (train_target == 'Bream') | (train_target == 'Smelt')
train_bream_smelt = train_scaled[bream_smelt_indexes]
target_bream_smelt = train_target[bream_smelt_indexes]

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
#학습
lr.fit(train_bream_smelt, target_bream_smelt)

print(lr.predict(train_bream_smelt[:5]))

각각에 대한 확률은 predict_proba 메서드를 통해 확인하고,

#확률 확인
print(lr.classes_)
print(lr.predict_proba(train_bream_smelt[:5]))

이 때 로지스틱 회귀로 도출한 선형 방정식의 zz값은 다음과 같이 decision_function을 통해 확인할 수 있다.

# 로지스틱 회귀 값 z 출력 -> 시그모이드 통과시키면 확률로 ?
decisions = lr.decision_function(train_bream_smelt[:5])
print(decisions)

zz값을 시그모이드 함수에 넣어보면 위에서 출력해본 각 클래스당 확률과 동일한 것을 알 수 있다.

from scipy.special import expit #시그모이드 함수 모듈
print(expit(decisions))
# predict_proba의 두번째 열과 같다 = smelt에 대한 확률임

시그모이드 함수 그려보기

#시그모이드 함수
import matplotlib.pyplot as plt
z = np.arange(-5, 5, 0.1)
phi = 1 / (1 + np.exp(-z))
plt.plot(z, phi)
plt.show()

다중 로지스틱 회귀 수행해보기

# 다중 분류 수행
lr = LogisticRegression(C=20, max_iter=1000) #C는 규제 강도, 큰 수를 넣으면 규제 강도 완화 (반비례) max_iter는 최대 수행횟수
lr.fit(train_scaled, train_target)
print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))

로지스틱 회귀 객체를 만들 때, C 인자는 규제의 정도를 지정한다. C가 작을수록 규제의 강도는 빡세지고, C가 크면 완화된다. 반비례 관계.
max_iter의 경우는 최대 반복 횟수로 넉넉하게 주지 않으면 오류가 남.

# 5개 샘플에 대한 예측
print(lr.predict(test_scaled[:5]))

그럼 여러 개의 클래스도 잘 분류할 수 있다.
확률도 되게 많이 나온다.

# 확률 출력
proba = lr.predict_proba(test_scaled[:5])
print(lr.classes_)
print(np.round(proba, decimals=3))

다중 로지스틱 회귀의 방정식

방정식의 계수와 yy절편을 출력해보자.

print(lr.coef_, lr.intercept_)


단순 로지스틱 회귀나 선형 회귀와는 다르게, 굉장히 많은 계수와 절편이 나타난 것을 볼 수 있다.
이는 각 클래스별로 방정식을 다 세웠기 때문.
이게 이진 분류일 때는 한 클래스에 대한 확률을 알면 (pp라고 하자) 나머지 확률은 자동으로 (1-pp)가 되어 다른 클래스에 대한 확률을 계산할 필요가 없는데,
다중 분류에서는 하나의 확률만 가지고는 다른 클래스의 확률을 알아낼 수 없기 때문에 모든 클래스에 대한 확률 계산이 필요하다. 그래서 저 복잡한 계수와 절편이 나오는 것.


오늘은 로지스틱 회귀를 해봤다잉.
얘도 선형 회귀처럼 이름이 좀 깐지남.

0개의 댓글