Введение

Увольнение сотрудников - это сокращение числа сотрудников в организации в результате увольнения, выхода на пенсию или смерти. Основное внимание мы уделим сотрудникам, решившим покинуть организацию в связи с увольнением. Мы собираемся изучить имеющиеся данные с помощью статистических методов и спрогнозировать факторы, ответственные за то, почему сотрудники покидают свою организацию.

  1. 1. Почему сотрудники увольняются?

Есть так много причин, по которым сотрудники увольняются из своих организаций. Есть поговорка: «Люди не бросают работу, они бросают начальника». Это не всегда так. Сотрудник может уйти с работы, когда почувствует, что его ценности не нужны; когда они чувствуют, что их работа не соответствует их интересам, когда их не повысили по службе или если нет возможностей для карьерного роста.

Кроме того, существует высокая убыль, когда сотрудники чувствуют, что им мало платят, или когда они тратят больше денег на проезд до места работы из-за расстояния от дома или у них больше сверхурочной работы. Удовлетворение сотрудников организацией является большой проблемой. Что бы ни случилось с уходом сотрудников. Настало время компаниям начать уделять больше внимания своим сотрудникам и вовлекать их в большее количество программ приобретения навыков, которые будут полезны для их карьеры, а также принесут пользу организации.

Для организаций крайне важно также учитывать тот факт, что их интеллектуальная собственность может оказаться под угрозой, и это будет стоить им больше денег при найме новых людей.

1.2 Наша цель

Наша цель — использовать методы исследования и анализа данных с различными алгоритмами машинного обучения, чтобы предсказать основные факторы, ответственные за то, почему сотрудники увольняются с работы в организации.

Давайте запачкаем руки вымышленным набором данных HR Employee Attrition, созданным IBM.

1.3 Импорт библиотек

Самое первое, что нужно сделать, это импортировать все необходимые библиотеки.

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

1.4 Импорт набора данных

Здесь начинается ваше путешествие по машинному обучению, поэтому давайте начнем импортировать наш набор данных об убыли сотрудников отдела кадров. Мы будем использовать библиотеку Pandas в Python для изучения набора данных. Библиотеки NumPy также можно использовать для чтения данных в виде массива NumPy.

Набор данных, который мы собираемся использовать, довольно мал, он состоит из 1470 строк и 35 столбцов. Набор данных также содержит как числовые, так и категориальные переменные.

Здесь мы будем использовать read_csv() библиотеки Pandas для доступа к данным, поскольку они были сохранены в виде файла переменной с разделителями-запятыми (CSV) в процессе обработки данных.

  • data = pd.read_csv(‘.csv’)* — это переменная имени, в которой теперь хранится DataFrame. Вы можете использовать любое желаемое имя.
data = pd.read_csv(‘C:\\...ML-Doc\\HR-Employee-Attrition.csv’)

C:\\…ML-Doc\\ — это путь к каталогу, в котором хранится файл.

2. Исследовательский анализ данных

Исследовательский анализ данных (EDA) — это статистический метод, используемый для анализа наборов данных, обработки пропущенных значений, выявления ошибок/аномалий и оценки взаимосвязи между исследовательскими переменными с использованием визуальных методов. Основная цель EDA — изучить, что данные могут сказать нам помимо стандартного моделирования или проверки гипотез.

Функция столбца показывает все имена столбцов в наборе данных:

data.columns

Мы можем выполнять множество функций, используя библиотеки pandas, чтобы получить больше информации о нашем наборе данных. Давайте проверим несколько строк набора данных, используя функцию pandas .head() и .tail().

data.head()

Выполнение data.head() показывает нам первые 5 строк набора данных с 35 столбцами. Чтобы отобразить последние пять строк, см. код ниже.

data.tail()

#Grabbing the first 5 rows of more than one column.
data[['Attrition', 'Age', 'Gender', 'YearsAtCompany', 'MonthlyIncome', 'MaritalStatus', 'JobSatisfaction']].head()

#This stores the number of rows (1,470) and columns (35) as a tuple.
data.shape

#Another important function of Pandas is the .info() function - This shows the datatype for each column of your dataset.
data.info()

2.1 Подсчет пропущенных значений

#To check for NAN values in each column. This generates a count of how many missing values our DataFrame has per column:
data.isnull().sum()
The good news is that our data does not contain missing values. Learn more on handling missing values.

2.2 Уникальные значения столбца

data.nunique()

2.3 Выбор функций

Функции EmployeeCount, EmployeeNumber, StandardHours и Over18 не важны для нас.

#Lets remove them from the dataset using the .drop function with the axis set to equal 1. To make this changes take effect immediately we will use inplace=True.
data.drop('EmployeeCount', axis=1, inplace=True)
data.drop('EmployeeNumber', axis=1, inplace=True)
data.drop('StandardHours', axis=1, inplace=True)
data.drop('Over18', axis=1, inplace=True)
# Total number of employees by JobSatisfaction.
data['JobSatisfaction'].value_counts()

# Percentage of employees by JobSatisfaction.
data['JobSatisfaction'].value_counts(normalize=True)*100

31,22% сотрудников очень довольны работой, а 19,65% – низко.

# Total number of employees by BusinessTravel.
data['BusinessTravel'].value_counts()

# Percentage of employees by BusinessTravel.
data['BusinessTravel'].value_counts(normalize=True)*100

Как мы видим выше, 70,95% (1043) сотрудников редко путешествуют, в то время как 18,84% (277) путешествуют часто.

#Total Number of employees who stayed (No) and those who left (Yes).
data['Attrition'].value_counts()

# Percentage of Attrition.
data['Attrition'].value_counts(normalize=True)*100

Общее количество уволившихся сотрудников составляет 16,1 % от общего числа занятых, а количество оставшихся сотрудников составляет 83,8 %. Это означает, что у нас есть 83,8% шанс правильно предположить, что сотрудник останется.

Мы также можем использовать приведенный ниже код, чтобы показать количество значений всех категориальных атрибутов, как мы делали выше.

for column in data.columns:
    if data[column].dtype == object:
        print(str(column) + ':' + str(data[column].unique()))
        print(data[column].value_counts())
        print(data[column].value_counts(normalize=True)*100) 
        
print('___________________________________________________________')

# Transform the target attributes (Attrition) from non-numeric to numeric.
Attrition_Transform = {‘Yes’: 1, ‘No’: 0}
data['Attrition'] = data['Attrition'].map(Attrition_Transform)
# Total number of Attrition
data[‘Attrition’].value_counts()

Как мы видим ниже, истощение было изменено с нечислового на числовое:

data.head()

Attrition = data.groupby('Attrition')
Attrition.mean()

  • Средний возраст сотрудников, уволившихся/ушедших, составляет около 33,6 лет, а средний возраст тех, кто остался, — 37,5 лет.
  • Среднемесячный доход уволившихся сотрудников составляет 4787 долларов по сравнению с теми, кто остался (6832 доллара). В этот момент сотрудники одной возрастной группы могут расстраиваться из-за того, что они зарабатывают меньше, чем их коллеги той же возрастной группы.

Там много информации, которую мы можем вывести из приведенного выше кода.

# The describe function gives us the summary statistics (count, mean, standard deviation, min and max, the quartile values) for each column.
data.describe()

MaritalStatus = data.groupby(‘MaritalStatus’)
MaritalStatus.describe()

Department = data.groupby(‘Department’)
Department.describe()

# let’s get the correlation of the attributes
data.corr()

3. Визуализация данных

Чтобы получить более подробное представление о данных, важно критически проанализировать данные, используя правильный процесс визуализации. Давайте визуализируем данные.

# Heatmap: This help with feature selections.
plt.figure(figsize=(25,20))
sns.heatmap(data.corr(),cmap='cividis', annot=True)

data.hist(bins=50, figsize=(20,15))
plt.show()

3.1. Визуализация гистограмм

Как мы видим выше, большинство распределений переменных имеют положительную асимметрию, это означает, что наши распределения не являются ни симметричными, ни нормальными, поскольку значения данных более резко смещаются к одной стороне графика, чем к другой. Вы можете запустить приведенный ниже код для других переменных, чтобы увидеть, какая из них имеет положительную или отрицательную асимметрию.

#Skewness and Kurtosis
print("Skewness: {:0.3f}".format(data['MonthlyIncome'].skew()))
print("Kurtosis: {:0.3f}".format(data['MonthlyIncome'].kurt()))

# Plot boxplots of numerical columns.
attributes = [
    'Age', 'DistanceFromHome', 'JobLevel',
    'JobInvolvement', 'YearsAtCompany', 'YearsWithCurrManager',
    'YearsInCurrentRole', 'TotalWorkingYears', 'MonthlyIncome'
]
f, ((ax1, ax2, ax3), (ax4, ax5, ax6), (ax7, ax8, ax9)) = plt.subplots(3, 3, figsize=(20, 25))
ax = [ax1, ax2, ax3, ax4, ax5, ax6, ax7, ax8, ax9]
for i in range(len(attributes)):
    sns.boxplot(x = 'Attrition', y = attributes[i], data=data, ax=ax[i])

plt.figure(figsize=(12,6))
sns.boxplot(x='Gender', y='Age', hue='Attrition', data=data)

features = ['Age', 'DistanceFromHome', 'YearsAtCompany', 
             'YearsSinceLastPromotion', 'Attrition', 'JobInvolvement', 
             'JobLevel', 'JobSatisfaction', 'MaritalStatus',
             'Gender','BusinessTravel', 'Department']
fig=plt.subplots(figsize=(25,18))
for i, j in enumerate(features):
    plt.subplot(4, 3, i+1)
    plt.subplots_adjust(hspace = 0.8)
    sns.countplot(x=j,data = data, hue='Attrition')
    plt.xticks(rotation=90)
    plt.title("No. of employee")

from sklearn import metrics
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

4. Предварительная обработка

4.1 Кодирование категориальных признаков

Давайте преобразуем категориальные признаки из текста в числа с помощью Scikit-Learn LabelEncoder, поскольку алгоритмы машинного обучения требуют чисел в качестве входных данных (машина понимает только числа, а не текст).

# Import LabelEncoder
from sklearn import preprocessing
#creating labelEncoder
le = preprocessing.LabelEncoder()
# Convert string labels into numbers
data[‘BusinessTravel’]=le.fit_transform(data[‘BusinessTravel’])
data[‘Department’]=le.fit_transform(data[‘Department’])
data[‘EducationField’]=le.fit_transform(data[‘EducationField’])
data[‘Gender’]=le.fit_transform(data[‘Gender’])
data[‘JobRole’]=le.fit_transform(data[‘JobRole’])
data[‘MaritalStatus’]=le.fit_transform(data[‘MaritalStatus’])
data[‘OverTime’]=le.fit_transform(data[‘OverTime’])
data.tail() # As we can see all the categorical variables has been converted from text to numbers.

4.2 Разделение данных

# Split the data into independent 'X' and dependent 'y' variables.
X = data.drop('Attrition', axis = 1)
y = data['Attrition']

5. Выберите и обучите модель

# Split the dataset into 75% Training set and 25% Testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25)

6. Обучение и оценка

from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
classifiers = {
    'Naive Bayes': GaussianNB(),
    'AdaBoost': AdaBoostClassifier(),
    'KNN(3)': KNeighborsClassifier(3),
    'Random Forest': RandomForestClassifier(max_depth=7, n_estimators=10, max_features=4),
    'GradientBoosting': GradientBoostingClassifier(random_state = 10, n_estimators = 400, learning_rate = 0.04, max_features = "sqrt")
}

6.1 Подбор модели и прогнозы

for name, classifier in classifiers.items():
 classifier.fit(X_train, y_train)
 score = classifier.score(X_test, y_test)
 
 y_pred = classifier.predict(X_test)
 
 # Model Accuracy, how often is the classifier correct?
 
print(‘{:<10} | accuracy = {:.3f}’.format(name, score))
 
# Model Precision
 
print(‘Precision:’,metrics.precision_score(y_test, y_pred))
 
# Model Recall
 
print(‘Recall:’,metrics.recall_score(y_test, y_pred))
print(confusion_matrix(y_test, y_pred))
print(metrics.classification_report(y_test, y_pred))

7. Важность функции

# Return the feature importance (the higher, the more important the feature).
importance = pd.DataFrame({‘feature’:X.columns,’importance’:np.round(classifier.feature_importance_,3)}) #Note: The target column is at position 0
importance = importance.sort_values(‘importance’,ascending=False).set_index(‘feature’)
importance

importance.plot.barh(figsize=(18,8))

8. Результат модели

Наша модель была обучена и оценена с хорошей производительностью с точностью 86%. Прогноз верен только в 65% случаев, когда он предсказывает увольнение сотрудников на тестовых наборах.

9. Выводы

  1. Используя различные алгоритмы, мы обнаружили, что GradientBoost и AdaBoost работают лучше всего с показателем точности 87,8% и 87,2% соответственно. В то время как KNN является наименее эффективным классификатором с точностью 80,7%.
  2. OverTime, MonthlyIncome, Age и StockOptionLevel являются основными факторами, которые отвечают за то, почему сотрудники увольняются с работы в организации, в то время как наименьшие факторы — это PromotionRating и Gender.
  3. Сотрудники, у которых нет показателя производительности, с меньшей вероятностью уволятся.

10. Заключение

В заключение вы узнали, как загружать данные. Чтобы получить некоторое представление, мы использовали статистический метод для изучения, обработки, визуализации и анализа данных. Кроме того, мы предварительно обработали данные, преобразовав категориальные переменные в числовую переменную, затем мы выбрали и обучили модель машинного обучения с использованием различных алгоритмов. Наконец, мы провели статистическую классификацию, оценили нашу модель и определили основные факторы, ответственные за то, почему сотрудники увольняются с работы в организации.

Результат нашей модели показывает, что GradientBoost показал лучшие результаты среди других алгоритмов с точностью 87%.

11. Рекомендации

Другим новичкам, таким как я, я рекомендую взглянуть на ROC и AUC, чтобы определить, какая из моделей является лучшим предсказателем. Еще есть возможности для улучшения в области настройки параметров.

12. Ссылки

  1. Модель оттока сотрудников со стратегическим планом удержания: кейс HR-аналитики
  2. Обработка пропущенных значений
  3. Источник набора данных IBM HR Analytics Attrition
  4. Прогнозировать увольнение сотрудников
  5. Прогнозирование оттока сотрудников в Python

Спасибо, что дочитали до этого места. Я надеюсь, что дал вам некоторое представление об исследовательском анализе данных и моделировании данных.

Полный код Python см. в этом репозитории GitHub.