[Imple] 비즈니스 사례 실습 : 인사팀(personnel management) 사례
Udemy 강의 중 비즈니스 데이터 사이언스 사례 강의를 들으며 공부한 내용을 정리한 글이다.
연구 목표 설정
기본적인 목표 : 회사 내에서 어떤 직원이 계속 근무할지, 어떤 직원이 회사를 떠날지에 대한 것을 직업 참여도, 교육, 직업 만족도, 성과, 일, 워라벨 등 다양한 특성을 바탕으로 예측/분류 해보기
라이브러리, 데이터 준비
#필요한 라이브러리 임포트
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
#구글 드라이브를 통한 데이터 파일 불러오기
from google.colab import drive
drive.mount('/content/drive')
employee_df = pd.read_csv('/content/...') #본인 데이터 경로 입력
데이터 정보/요약통계 확인해보기
employee_df.info()
employee_df.describe()
데이터 탐색 - 시각화
먼저 Y/N 으로 되어있는 데이터를 1 | 0 으로 변환해주는 작업 진행.
# 'Yes'면 1로 'No'면 0으로 변환, 람다함수 적용
employee_df['Attrition'] = employee_df['Attrition'].apply(lambda x:1 if x == 'Yes' else 0)
employee_df['OverTime'] = employee_df['OverTime'].apply(lambda x:1 if x == 'Yes' else 0)
employee_df['Over18'] = employee_df['Over18'].apply(lambda x:1 if x == 'Y' else 0)
다음으로 누락된 데이터가 있는지 확인.
# 히트맵을 통해 누락된 데이터가 있는지 확인
sns.heatmap(employee_df.isnull(), yticklabels = False, cbar = False, cmap = 'Blues')
히스토그램으로 각 속성별 분포도 시각화 진행.
# 35개 속성이 플로팅 됨
employee_df.hist(bins = 30, figsize = (20, 20), color = 'r')
의미 없는 속성은 삭제 진행.
employee_df.drop(['EmloyeeCount', 'StandardHours', 'Over18' , 'EmployeeNumber'], axis = 1, inplace = True)
다음으로 회사를 떠난 사람들과 남은 사람들 각각에 해당하는 데이터 프레임을 제작한다.
left_df = employee_df[employee_df['Attrition'] == 1]
stayed_df = employee_df[employee_df['Attrition'] == 0]
#요약 통계 확인
left_df.describe()
stayed_df.describe()
히트맵 이용해 상관관계 플로팅 (차트 시각화) 진행
correlations = employee_df.corr()
f, ax = plt.subplots(figsize = (20,20))
sns.heatmap(correlations, annot = True)
다음은 각 속성별로 퇴사 수와 어떤 연관이 있는지 조금 더 자세히 시각화를 진행한다.
1. age 와 attrition에 대한 시각화를 진행해 각 나이대별 퇴사 수를 비교.
plt.figure(figsize = [25, 12])
sns.countplot(x = 'Age', hue = 'Attrition', data = employee_df)
파란색(0) 막대는 회사에 남은 직원을 의미하고, 주황색(1) 막대는 회사를 떠난 직원을 의미.
그래프 상 29~30대 직원들이 회사를 많이 떠난다고 볼 수 있음.
어린 나이대 직원들이 많이 떠나는 비율이고, 나이가 많아지면 거의 떠나지 않는다고 볼 수 있음.
즉 나이 속성은 퇴사에 대한 유의미한 요인임을 알 수 있음.
2. 여러 속성들 attrition에 대한 시각화를 진행해 각 직별 퇴사 수를 비교.
plt.figure(figsize=[20,20])
#직무
plt.subplot(411)
sns.countplot(x = 'JobRole', hue = 'Attrition', data = employee_df)
#결혼여부
plt.subplot(412)
sns.countplot(x = 'MaritalStatus', hue = 'Attrition', data = employee_df)
#직무관련성
plt.subplot(413)
sns.countplot(x = 'JobInvolvement', hue = 'Attrition', data = employee_df)
#작업수준
plt.subplot(414)
sns.countplot(x = 'JobLevel', hue = 'Attrition', data = employee_df)
그래프 상 판매영업부는 퇴율이 매우 높고, 연구 책임자들은 거의 떠나지 않음을 볼 수 있음.
그래프 상 결혼한 직원보다 미혼의 직원이 퇴사율이 더 높음을 볼 수 있음.
그래프 상 낮은 참여도를 보이는 직원의 퇴사율이 더 높음을 볼 수 있음.
그래프 상 직무 수준이 더 숙달된 직원의 퇴사율이 낮음을 볼 수 있고, 신입의 경우 퇴사율이 높음을 볼 수 있음.
다음으로 연속 변수들을 KDE 플롯을 통해 분석해본다.
사용할 변수로는 집-회사 간 거리 변수이다.
plt.figure(figsize = (12, 7))
sns.kdeplot(left_df['DistanceFromHone'] , label = 'Employees who left', shade = True, color = 'r')
sns.kdeplot(stayed_df['DistanceFromHome'], label = 'Employee who Stayed', shade = True, color = 'b')
plt.xlabel('Distance From Hone')
그래프 상 집-회사 간 거리가 멀어질수록 퇴사율이 높아짐을 알 수 있다.
다음은 box plot 그래프를 통해 직에 따른 월수입을 시각화한다.
plt.figure(figsize = (15, 10))
sns.boxplot(x = 'MonthlyIncome' , y = 'JobRole', data = employee_df)
데이터 정제
범주형 데이터를 모델에 적용할 수 있도록 인코딩해준다.
#원핫인코딩
from sklearn.preprocessing import OneHotEncoder
onehotencoder = OneHotEncoder()
X_cat = onehotencoder.fit_tranform(X_cat).toarray() # 0과 1로 인코딩
X_cat = pd.DataFrame(X_cat) #데이터프레임이 모든 정보를 포함
수치형 데이터 살펴보기
X_numerical = employee_df[['Age', 'DailyRate', 'DistanceFromHome', 'Education', 'EnvironmentSatisfaction', 'HourlyRate', 'JobInvolvement', 'JobLevel', 'JobSatisfaction', 'MonthlyIncome', 'MonthlyRate', 'NumCompaniesWorked', 'OverTime', 'PercentSalaryHike', 'PerformanceRating', 'RelationshipSatisfaction', 'StockOptionLevel', 'TotalWorkingYears' ,'TrainingTimesLastYear' , 'WorkLifeBalance', 'YearsAtCompany' ,'YearsInCurrentRole', 'YearsSinceLastPromotion', 'YearsWithCurrManager']]
모든 범주형, 수치형 데이터 프레임을 합침
X_all = pd.concat([X_cat, X_numerical], axis = 1)
데이터 스케일링
데이터 간 범위를 조절하는 스케일링 진행.
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X = scaler.fit_transform(X_all)
#퇴사 여부 값 y 추출
y = employee_df['Attrition']
로지스틱 회귀 분류기 제작/훈련
로지스틱 회귀 분류기를 만들고 KPI 적용해본다.
from sklearn.modelselection import train_test_split
#테스트 사이즈 25%
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25)
#데이터 표본 확인
X_train.shape
X_test.shape
#로지스틱 회귀분류기 생성
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
model = LogisticRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
모델이 예측한 값과 실제 값 비교
모델의 수행 평가를 시각화한다.
from sklearn.metrics import confusion_matrix, classification_report
# 정확도 측정
print('Accuracy {} %'.format( 1001* accuracy_score(y_pred, y_test)))
# 혼동 행렬
cm = confusion_matrix(y_pred, y_test)
sns.heatmap(cm, annot = True)
print(classification_report(y_test, y_pred))
로지스틱 회귀 분류기 리포트 결과를 보면 정밀도는 클래스 0에서 91%, 클래스 1에서 83%을 기록한다.
재현율은 클래스 0에서 98%, 클래스 1에서는 43%를 기록한다.
f1 score는 0에서 94%, 1에서 56%를 기록한다.
랜덤 포레스트 분류기 제작/훈련
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
cm = confusion_matrix(y_pred, y_test)
sns.heatmap(cm, annot = True)
print(classification_report(y_test, y_pred))
랜덤포레스트 분류기 리포트 결과를 보면 정밀도는 클래스 0에서 87%, 클래스 1에서 92%을 기록한다.
재현율은 클래스 0에서 100%, 클래스 1에서는 20%를 기록한다.
f1 score는 0에서 93%, 1에서 32%를 기록한다.
딥 러닝 모델 훈련 / 평가
딥 러닝 모델 (인공신경망)을 구현해본다.
import tensorflow as tf
#케라스 api 사용
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(units = 500, activation = 'relu', input_shape = (50, )))
model.add(tf.keras.layers.Dense(units = 500, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 500, activation = 'relu'))
model.add(tf.keras.layers.Dense(units = 1, activation = 'sigmoid'))
#작성한 모델 확인
model.summary()
model.compile(optimizer = 'Adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
#진행과정을 모니터링하기위해 변수화
epochs_hist = model.fit(X_train, y_train, epochs = 100, batch_size = 50)
#모델 예측 수행
y_pred = model.predict(X_test)
y_pred = (y_pred > 0.5) #50%보다 큰 값은 1, 작은 값은 0으로 True, False 값으로 리턴
#손실수치 시각화 진행
plt.plot(epochs_hist.history['loss'])
plt.title('Model Loss Progress During Training')
plt.xlabel('Epoch')
plt.ylabel('Training Loss')
plt.legend(['Training Loss'])
#정확도 시각화 진행
plt.plot(epochs_hist.history['accuracy'])
plt.title('Model Accuracy Progress During Training')
plt.xlabel('Epoch')
plt.ylabel('Training Accuracy')
plt.legend(['Training Accuracy'])
#혼동행렬 시각화
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot = True)
#분류기 리포트 확인
print(classification_report(y_test, y_pred))
딥러닝 모델 리포트 결과를 보면 정밀도는 클래스 0에서 91%, 클래스 1에서 51%을 기록한다.
재현율은 클래스 0에서 92%, 클래스 1에서는 46%를 기록한다.
f1 score는 0에서 91%, 1에서 49%를 기록한다.