본문 바로가기
#02.천재교육 빅데이터/+06.머신러닝 기초

[천재교육] 로지스틱 회귀, 소프트맥스 회귀

by 돌비오 2023. 3. 15.
728x90
로지스틱 회귀

회귀모델을 분류모델로 활용할 수 있다 ?!

- 이진분류 : 로지스틱 회귀 (Logistic Regression)

- 다중 클래스 분류 : 소프트맥스 회귀 (Softmax Regression)

 

 

- 선형회귀 모델이 예측한 값에 시그모이드 함수를 적용하면
    0 → 0.5
   -2 → 0.1~0.2
 

  시그모이드 함수를 적용해서 0.5 보다 크면 1로 분류. 즉, 양성이다 요런것

 

 

 

※ 학습과 비용함수

- 오른쪽 그래프

  실제 0인데 1의 값에 가깝게 결과를 낼수록

  아래 로그는 커지기 때문에 (=비용함수 결과값이 높아지기 때문에)

  더 낮은 성능을 보인다 할수 있다.

 

 

 

- 로그로스함수. 정답을 더 높은 확률로 예측할수록 더 좋은 모델

 

 

 

<위 그래프>

버지니카 품종인지 아닌지

녹색곡선은 버지니카 품종일 확률을 나타낼 곡선 (petal width가 클수록 높다!)

파란색은 반대

두 곡선이 만나는 지점 0.5(확률값 0.5)를 기준으로 버지니카 품종인지 아닌지 구별할 수 있게된다.

petal width가 1.65? 정도일때겠네 (결정경계)

 

<아래 그래프>

초록색 직선은 버지니카 품종일 가능성이 0.9인 것

검은색 점선이 0.5의 확률. 즉, 결정경계

 

 

 


소프트맥스 회귀 (Softmax Regression)

로지스틱 회귀모델을 일반화하여 다중 클래스 분류를 지원하도록 만든 모델

위: 로지트틱 회귀 / 아래: 소프트맥스 회귀

<위 이미지>

x 값을 선형회귀 모델에 넣었고 0~1사이로 변환해서 0.5 이상이 양성

 

 

<아래 이미지>

똑같이 x값을 넣어서 클래스1일 확률을 먼저 뽑는다. 0.15. 그리고 소프트맥스(클래스별 확률들의 총합이 1 이 되도록 바꿔주는 함수) 를 통과해서 최종결과가 나오게 함. 그 중 가장 높은 두번째 클래스가 이데이터에 대한 예측값이다! 라고 결정하는 것.

 

 

 

 


소프트맥스 회귀 실습

결정경계의 교점이 (클래스가 3개니까) 0.5가 아니라 33.3%가 된다.

(위 그래프에서 세가지 색의 클래스 가운데 접점에 데이터가 있다면 그 데이터는 각 클래스에 33.3%의 확률을 가지고 있다는 얘기)

곡선 자체가 네모데이터일 확률

노란색 0.9에 가까우면 0.9의 확률로 노란색

 

 

 

 

 

 

 

 

 

로지스틱 회귀를 통한 정오답 예측
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sklearn.linear_model import LogisticRegression

df = pd.read_csv('./datasets/초등_4학년_수학_차시문항풀이이력.csv', index_col=0)
pd.set_option('display.max_columns', len(df.columns))
df['정오답'] =  df['정오답'].map({'O': 1, 'X': 0})



Q. 어떤 피쳐가 정오답에 영향을 미칠까?

df = df[['정오답', '강의타입', '동영상재생시간', '실제재생시간', '학습일', '문항코드', '대단원코드', '중단원코드', '소단원코드', '토픽코드', '난이도', '평가영역']]



df = df.dropna(subset=['정오답'])

df['학습일'] = df.학습일.apply(pd.to_datetime)
df['hour'] = df.학습일.apply(lambda x: x.hour)



카테고리형 변수 원핫인코딩
# 원핫인코딩은 카테고리형 변수에 적용가능하나 연속형 자료에는 부적합하다.
   연속형에는 스케일링 추천!

df = pd.get_dummies(df, columns=['강의타입', '문항코드', '대단원코드', '중단원코드', '소단원코드', '토픽코드', '난이도', '평가영역', 'hour'])

df.head(3)
=>



df = df.drop(labels='학습일', axis=1)

X = df.iloc[:,1:].to_numpy()
Y = df['정오답'].to_numpy()

from sklearn.model_selection import train_test_split
X_train , X_test, y_train , y_test = train_test_split(X, Y, test_size=0.2, random_state=0)


# 로지스틱 회귀를 이용하여 학습 및 예측 수행. 
# solver인자값을 생성자로 입력하지 않으면 solver='lbfgs'  
lr_clf = LogisticRegression() # solver='lbfgs'
lr_clf.fit(X_train, y_train)
lr_preds = lr_clf.predict(X_test)

# accuracy와 roc_auc 측정
print('accuracy: {0:.3f}, roc_auc:{1:.3f}'.format(accuracy_score(y_test, lr_preds),
                                                 roc_auc_score(y_test , lr_preds)))

=>
accuracy: 0.722
roc_auc: 0.577





더 성능을 높여보자.
재생시간 스케일링

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
data_scaled = scaler.fit_transform(df[['동영상재생시간','실제재생시간']])


df[['동영상재생시간','실제재생시간']] = data_scaled
df[['동영상재생시간','실제재생시간']]

=>



X = df.iloc[:,1:].to_numpy()
Y = df['정오답'].to_numpy()

from sklearn.model_selection import train_test_split
X_train , X_test, y_train , y_test = train_test_split(X, Y, test_size=0.2, random_state=0)


# 로지스틱 회귀를 이용하여 학습 및 예측 수행. 
# solver인자값을 생성자로 입력하지 않으면 solver='lbfgs'  
lr_clf = LogisticRegression()     # solver='lbfgs'
lr_clf.fit(X_train, y_train)
lr_preds = lr_clf.predict(X_test)


# accuracy와 roc_auc 측정
print('accuracy: {0:.3f}, roc_auc:{1:.3f}'.format(accuracy_score(y_test, lr_preds),
                                                 roc_auc_score(y_test , lr_preds)))

=>
accuracy: 0.751
roc_auc:0.643
        
        
        
pd.DataFrame(data=[lr_preds, y_test])    # 예측값 / 실제값 

=>
728x90