본문 바로가기
Python/ML&DL

[파이썬, Python] 머신러닝 - 3️⃣ 로지스틱 회귀(Logistic Regression)

by coding-choonsik 2023. 6. 15.
728x90
반응형
SMALL

📄 예제에 사용한 파일

hr.csv
3.58MB

 

 

1. hr 데이터셋 살펴보기

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from google.colab import drive

hr_df = pd.read_csv('/content/drive/MyDrive/KDT/Python/4.머신러닝 딥러닝/hr.csv')
hr_df.head()

 

✅ 데이터셋 정보 알아보기

hr_df.info()

 

 

✅ 데이터셋의 수치형 데이터 정보 알아보기

hr_df.describe()

 

✅ 작년의 고과점수와 승진 확률에 대해 시각화하여 알아보기

sns.barplot(x='previous_year_rating', y='is_promoted', data=hr_df)

▲ 작녀 고과점수가 높을수록 승진확률이 높다.

 

 

✅ 평균고과점수와 승진 확률에 대해 시각화하여 알아보기

sns.lineplot(x='avg_training_score', y='is_promoted', data=hr_df)

▲ 평균 고과점수가 90점 이상이 되면 승진 확률이 급격히 상승함

 

✅ 채용방법과 승진확률에 대해 시각화하여 알아보기

 

sns.barplot(x='recruitment_channel', y='is_promoted', data=hr_df)

▲ referred 방식이 승진확률이 가장 높지만 오차범위가 가장 큼

 

 

✅ 중복값을 제외한 채용방법의 종류와 수 알아보기

hr_df['recruitment_channel'].value_counts()

▲referred의 데이터 수가 적기 때문에 오차범위가 큼

 

✅ 성별에 따른 승진확률에 대해 알아보기

sns.barplot(x='gender', y='is_promoted', data=hr_df)  # 여자인 데이터의 수가 적기 때문에 승진 비율을 더 높아보임(오차 확률이 높음)

▲ 여자의 승진확률이 더 높지만 오차범위가 넓음

 

✅ 중복값을 제외한 성별의 종류와 개수 알아보기

hr_df['gender'].value_counts()

 

 

✅ 부서에 따른 승진 확률 알아보기

sns.barplot(x='department', y='is_promoted', data=hr_df)
plt.xticks(rotation=45)

▲ 부서에 따른 승진 확률이 유의미한 연관성으로 판단

 

✅ 중복값을 제외한 부서 종류와 개수 알아보기

hr_df['department'].value_counts()

 

✅ 지역에 따른 승진 확률 알아보기

plt.figure(figsize=(15,10))
sns.barplot(x='region', y='is_promoted', data=hr_df)
plt.xticks(rotation=45)

▲회사의 지사(지역)별로 승진여부에 유의미한 영향이 있다고 판단 -> 원핫인코딩 컬럼에 추가하여 모델 학습

✅ 결측지 알아보기

hr_df.isna().sum()

 

✅ 학력 컬럼에 중복값을 제외한 데이터의 종류와 개수 알아보기

hr_df['education'].value_counts()

▲ Below Secondary의 데이터 수가 적음

 

✅ 전년도 고과 점수의 중복값 제외 데이터 종류와 개수 알아보기

hr_df['previous_year_rating'].value_counts()

 

✅ NaN 데이터 삭제하기

hr_df = hr_df.dropna()  # NaN인 데이터가 미비하기 때문에 삭제

 

✅ NaN값 알아보기

hr_df.isna().sum()

 

 

 

✅ object형 컬럼 알아보기

for i in ['department', 'region','education','gender','recruitment_channel']:
  print(i, hr_df[i].nunique())

 

✅  object형 데이터들의 유니크한 값들의 수 알아보기(원핫인코딩을 위해)

for i in ['department', 'region','education','gender','recruitment_channel']:
  print(i, hr_df[i].nunique())

 

✅ 원 핫 인코딩 하기

hr_df = pd.get_dummies(hr_df, columns=['department', 'region','education','gender','recruitment_channel'])
hr_df.head()

▲ 원 핫 인코딩한 컬럼의 일부

 

✅ 학습 데이터와 검증 데이터 분리하기

 

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(hr_df.drop('is_promoted', axis=1), hr_df['is_promoted'], test_size=0.2, random_state=10)

X_train.shape, X_test.shape
>>> ((38928, 58), (9732, 58))

y_train.shape, y_test.shape
>>> ((38928,), (9732,))

2. 로지스틱 회귀(Logistic Regression)

  • 둘 중 하나를 결정하는 문제(이진 분류)를 풀기 위한 대표적인 알고리즘
  • 3개 이상의 클래스에 대한 판별을 하는 경우 OvR(One-vs-Rest), OvO(One-vs-One) 전략으로 판별
    • one-vs-rest(OvR): K개의 클래스가 존재할 때, 1개의 클래스를 제외한 다른 클래스를 K개 만들어, 각각의 이진 분류에 대한 확률을 구하고, 총합을 통해 최종 클래스를 판별
    •  one-vs-one(OvO): 4개의 계정을 구분하는 클래스가 존재한다고 할 때, 0vs1, 0vs2, 0vs3,...,2vs3까지의 NX(N-1)/2개의 분류기를 만들어 가장 많이 양성으로 선택된 클래스를 판별
대부분 OvR전략을 선호, 데이터가 한쪽으로 많이 치우친 경우 OvO을 사용

 

# 모델 불러오기
from sklearn.linear_model import LogisticRegression

# 모델 객체 생성
lr = LogisticRegression()

# 학습
lr.fit(X_train, y_train)

# 예측
pred = lr.predict(X_test)

 

2-1. accuracy_score

from sklearn.metrics import accuracy_score, confusion_matrix

accuracy_score(y_test, pred)  
>>> 0.9114262227702425

 

📍 약 91.14%의 정답률, 분류 문제에 있어서 accuracy_score는 신빙성이 떨어짐(데이터가 한쪽으로 치우친 경우 치우친 쪽으로 판단할 가능성이 높음)

hr_df['is_promoted'].value_counts()

📍 이진분류 ➡ 데이터가 한쪽으로 치우쳤기 때문에 평가용 지표를 accuracy_score을 쓰는것 보다 confusion_matrix를 쓰는 것이 좋음

 

 

 

2-2. confusion_matrix

 

  • 정밀도와 재현율(민감도)을 활용하는 평가용 지표

 

  • TN: 승진하지 못했는데 승진하지 못했다고 예측
  • FN: 승진하지 못했는데 승진했다고 예측
  • FP: 승진했는데 승진하지 못했다고 예측
  • TP: 승진했는데 승진했다고 예측
confusion_matrix(y_test, pred)

 

✅ heatmap으로 연관관계 알아보기

sns.heatmap(confusion_matrix(y_test, pred), annot=True, cmap='Blues')

▲ 연관성이 높을수록 진한색으로 표시

 

3-1. 정밀도(precision)

  • TP / (TP + FP)
  • 무조건 양성으로 판단해서 계산하는 방법
  • 실제 1인 것중에 얼마 만큼을 제대로 맞추었는가에 대한 퍼센티지(%)

 

3-2. 재현율(recall)

  •  TP / (TP+FN)
  •  정확하게 감지한 양성 샘플의 비율
  •  1이라고 예측한 것 중, 얼마 만큼을 제대로 맞추었는가에 대한 퍼센티지(%)
  •  민감도 또는 TPR(True Positive Rate)라고도 부름

 

3-3. f1 score

  • 정밀도와 재현율의 조화 평균을 나타내는 지표

▲ 산술평균과 조화평균의 차이

 

from sklearn.metrics import precision_score, recall_score, f1_score

# 정밀도
precision_score(y_test, pred)
>>> 1.0

# 재현율
recall_score(y_test, pred)
>>> 0.0011587485515643105

# f1 score
f1_score(y_test, pred)
>>> 0.0023148148148148147

 

lr.coef_

 

X_train

 

# 독립변수 2개, 종속변수 1개
# 임의의 데이터를 만들어 평가지표를 활용하여 보자.
TempX = hr_df[['age', 'length_of_service']]
tempY = hr_df['is_promoted']

# 모델 객체 생성
temp_lr = LogisticRegression()

# 학습
temp_lr.fit(TempX, tempY)

# 데이터프레임으로 보기
temp_df = pd.DataFrame({'age':[20, 27, 35],  'length_of_service':[1, 3, 7]})
temp_df

# 학습에 대한 예측
pred = temp_lr.predict(temp_df)  
pred
>>> array([0, 0, 0])  # 승진을 다 못했다고 예측

#age, length_of_service에 대한 기울기값
temp_lr.coef_  

# y절편값
temp_lr.intercept_  # y절편값

📍 분류 예측 식 

y = -0.01074458x2 + -0.00053409x2 + (-1.96818509)

 

proba = temp_lr.predict_proba(temp_df)
proba

▲ 0과 1에 대한 확률 - 더 높은 쪽을 선택(0,0,0 결과에 대한 이유)


4. 교차 검증(Cross Validation)

  • train_test_split 에서 발생하는 데이터의 섞임에 따라 성능이 좌우되는 문제를 해결하기 위한 기술
  • K겹 교차 검증(K-Fold)을 가장 많이 사용

 

✅ 교차검증 원리

1. 데이터 세트를 k개의 동일한 크기로 나눔.  이때, 각각의 부분 집합을 "fold"라고 함
2. 첫 번째 fold를 검증 세트로 선택하고 나머지 k-1개의 fold를 훈련 세트로 사용하여 모델을 학습
3. 모델을 검증 세트에서 평가하고 성능 지표를 기록
4. 다음 fold를 검증 세트로 선택하고 나머지 fold를 훈련 세트로 사용하여 모델을 다시 학습
5. 위 과정을 k번 반복하고, 각 반복에서 얻은 성능 지표들의 평균을 계산하여 최종 성능 평가를 얻습니다.
from sklearn.model_selection import KFold

# 데이터셋을 5개로 나눔
Kf = KFold(n_splits=5)  

Kf
>>> KFold(n_splits=5, random_state=None, shuffle=False)

hr_df

▲ 데이터셋 일부

# hr_df의 K-fold 개수(5개)만큼 돌면서 train_index와 test_index를 split하기
for train_index, test_index in Kf.split(range(len(hr_df))):    
  print(train_index, test_index)
  print(len(train_index), len(test_index))  # 차례대로 나눔(shuffle X, random_state X)

▲ 순서대로 데이터가 나누어짐

 

✅ 하이퍼 파라미터 튜닝

# 데이터셋을 5개로 나눔, 하이퍼파라미터 튜닝 -> 데이터를 고루 섞어줌
Kf = KFold(n_splits=5, random_state=10, shuffle=True)

# hr_df의 K-fold 개수(5개)만큼 돌면서 train_index와 test_index를 split하기
for train_index, test_index in Kf.split(range(len(hr_df))):    
  print(train_index, test_index)
  print(len(train_index), len(test_index))  # 데이터가 섞여서 나누어짐

 

✅ 예측 정확도 알아보기

acc_list = []

for train_index, test_index in Kf.split(range(len(hr_df))):
  X = hr_df.drop('is_promoted', axis=1)
  y = hr_df['is_promoted']

  # K겹으로 나눈 데이터셋을 학습데이터와 test 데이터로 나누어줌
  X_train = X.iloc[train_index]
  X_test = X.iloc[test_index]
  y_train = y.iloc[train_index]
  y_test = y.iloc[test_index]

  # 학습
  lr = LogisticRegression()
  lr.fit(X_train, y_train)
  # 예측
  pred = lr.predict(X_test)
  # 예측값에 대힌 accuracy_score을 계산하고 acc_list에 담음
  acc_list.append(accuracy_score(y_test, pred))
  
# 한 번 학습시킬때마다의 accuracy_score - 데이터가 어떻게 섞이냐에 따라 성능도 달라짐
acc_list  
>>> 
[0.9114262227702425,
 0.9094739005343198,
 0.9173859432799013,
 0.914406083025072,
 0.9125565145910398]
 
 # 정확도의 평균
np.array(acc_list).mean()
>>> 0.913049732840115
Cross Validation을 사용하는 이유는 결과를 좋게 하기 위함이 아니라 믿을만한 학습 모델인지를 평가하기 위함
(데이터로 인한 모델의 신뢰도)

 

 

 

728x90
반응형
LIST