# 【阿旭机器学习实战】【35】员工离职率预测---决策树与随机森林预测

## 1.获取数据

# 引入工具包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as matplot
import seaborn as sns
%matplotlib inline
# 读入数据到Pandas Dataframe "df"
df = pd.read_csv('HR_comma_sep.csv', index_col=None)

## 2.数据预处理

# 检测是否有缺失数据
df.isnull().any()
satisfaction_level       False
last_evaluation          False
number_project           False
average_montly_hours     False
time_spend_company       False
Work_accident            False
left                     False
promotion_last_5years    False
sales                    False
salary                   False
dtype: bool
# 数据的样例
df.head()
 satisfaction_level last_evaluation number_project average_montly_hours time_spend_company Work_accident left promotion_last_5years sales salary 0 0.38 0.53 2 157 3 0 1 0 sales low 1 0.80 0.86 5 262 6 0 1 0 sales medium 2 0.11 0.88 7 272 4 0 1 0 sales medium 3 0.72 0.87 5 223 5 0 1 0 sales low 4 0.37 0.52 2 159 3 0 1 0 sales low

# 重命名
df = df.rename(columns={'satisfaction_level': 'satisfaction',
'last_evaluation': 'evaluation',
'number_project': 'projectCount',
'average_montly_hours': 'averageMonthlyHours',
'time_spend_company': 'yearsAtCompany',
'Work_accident': 'workAccident',
'promotion_last_5years': 'promotion',
'sales' : 'department',
'left' : 'turnover'
})
# 将预测标签‘是否离职’放在第一列
front = df['turnover']
df.drop(labels=['turnover'], axis=1, inplace = True)
df.insert(0, 'turnover', front)
df.head()
 turnover satisfaction evaluation projectCount averageMonthlyHours yearsAtCompany workAccident promotion department salary 0 1 0.38 0.53 2 157 3 0 0 sales low 1 1 0.80 0.86 5 262 6 0 0 sales medium 2 1 0.11 0.88 7 272 4 0 0 sales medium 3 1 0.72 0.87 5 223 5 0 0 sales low 4 1 0.37 0.52 2 159 3 0 0 sales low

## 3.分析数据

• 14999 条数据, 每一条数据包含 10 个特征
• 总的离职率： 24%
• 平均满意度为 0.61
df.shape
(14999, 10)
# 特征数据类型.
df.dtypes
turnover                 int64
satisfaction           float64
evaluation             float64
projectCount             int64
averageMonthlyHours      int64
yearsAtCompany           int64
workAccident             int64
promotion                int64
department              object
salary                  object
dtype: object
turnover_rate = df.turnover.value_counts() / len(df)
turnover_rate
0    0.761917
1    0.238083
Name: turnover, dtype: float64
# 显示统计数据
df.describe()
 turnover satisfaction evaluation projectCount averageMonthlyHours yearsAtCompany workAccident promotion count 14999.000000 14999.000000 14999.000000 14999.000000 14999.000000 14999.000000 14999.000000 14999.000000 mean 0.238083 0.612834 0.716102 3.803054 201.050337 3.498233 0.144610 0.021268 std 0.425924 0.248631 0.171169 1.232592 49.943099 1.460136 0.351719 0.144281 min 0.000000 0.090000 0.360000 2.000000 96.000000 2.000000 0.000000 0.000000 25% 0.000000 0.440000 0.560000 3.000000 156.000000 3.000000 0.000000 0.000000 50% 0.000000 0.640000 0.720000 4.000000 200.000000 3.000000 0.000000 0.000000 75% 0.000000 0.820000 0.870000 5.000000 245.000000 4.000000 0.000000 0.000000 max 1.000000 1.000000 1.000000 7.000000 310.000000 10.000000 1.000000 1.000000
# 分组的平均数据统计
turnover_Summary = df.groupby('turnover')
turnover_Summary.mean()
 satisfaction evaluation projectCount averageMonthlyHours yearsAtCompany workAccident promotion turnover 0 0.666810 0.715473 3.786664 199.060203 3.380032 0.175009 0.026251 1 0.440098 0.718113 3.855503 207.419210 3.876505 0.047326 0.005321

### 3.1 相关性分析

# 相关性矩阵
corr = df.corr()
#corr = (corr)
sns.heatmap(corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values)
corr
 turnover satisfaction evaluation projectCount averageMonthlyHours yearsAtCompany workAccident promotion turnover 1.000000 -0.388375 0.006567 0.023787 0.071287 0.144822 -0.154622 -0.061788 satisfaction -0.388375 1.000000 0.105021 -0.142970 -0.020048 -0.100866 0.058697 0.025605 evaluation 0.006567 0.105021 1.000000 0.349333 0.339742 0.131591 -0.007104 -0.008684 projectCount 0.023787 -0.142970 0.349333 1.000000 0.417211 0.196786 -0.004741 -0.006064 averageMonthlyHours 0.071287 -0.020048 0.339742 0.417211 1.000000 0.127755 -0.010143 -0.003544 yearsAtCompany 0.144822 -0.100866 0.131591 0.196786 0.127755 1.000000 0.002120 0.067433 workAccident -0.154622 0.058697 -0.007104 -0.004741 -0.010143 0.002120 1.000000 0.039245 promotion -0.061788 0.025605 -0.008684 -0.006064 -0.003544 0.067433 0.039245 1.000000

• projectCount VS evaluation: 0.349333
• projectCount VS averageMonthlyHours: 0.417211
• averageMonthlyHours VS evaluation: 0.339742

• satisfaction VS turnover: -0.388375
# 比较离职和未离职员工的满意度
emp_population = df['satisfaction'][df['turnover'] == 0].mean()
emp_turnover_satisfaction = df[df['turnover']==1]['satisfaction'].mean()
print( '未离职员工满意度: ' + str(emp_population))
print( '离职员工满意度: ' + str(emp_turnover_satisfaction) )
未离职员工满意度: 0.666809590479516

### 3.2 进行 T-Test

import scipy.stats as stats
stats.ttest_1samp(a = df[df['turnover']==1]['satisfaction'], # 离职员工的满意度样本
popmean = emp_population)  # 未离职员工的满意度均值
Ttest_1sampResult(statistic=-51.3303486754725, pvalue=0.0)

T-Test 显示pvalue (0) 非常小, 所以他们之间是显著不同的

degree_freedom = len(df[df['turnover']==1])
LQ = stats.t.ppf(0.025,degree_freedom)  # 95%致信区间的左边界
RQ = stats.t.ppf(0.975,degree_freedom)  # 95%致信区间的右边界
print ('The t-分布 左边界: ' + str(LQ))
print ('The t-分布 右边界: ' + str(RQ))
The t-分布 左边界: -1.9606285215955626
The t-分布 右边界: 1.9606285215955621
# 概率密度函数估计
fig = plt.figure(figsize=(15,4),)
ax=sns.kdeplot(df.loc[(df['turnover'] == 0),'evaluation'] , color='b',shade=True,label='no turnover')
ax=sns.kdeplot(df.loc[(df['turnover'] == 1),'evaluation'] , color='r',shade=True, label='turnover')
ax.set(xlabel='Employee Evaluation', ylabel='Frequency')
ax.legend()
plt.title('Employee Evaluation Distribution - Turnover V.S. No Turnover')
Text(0.5, 1.0, 'Employee Evaluation Distribution - Turnover V.S. No Turnover')

# 概率密度函数估计
fig = plt.figure(figsize=(15,4))
ax=sns.kdeplot(df.loc[(df['turnover'] == 0),'averageMonthlyHours'] , color='b',shade=True, label='no turnover')
ax=sns.kdeplot(df.loc[(df['turnover'] == 1),'averageMonthlyHours'] , color='r',shade=True, label='turnover')
ax.legend()
ax.set(xlabel='Employee Average Monthly Hours', ylabel='Frequency')
plt.title('Employee AverageMonthly Hours Distribution - Turnover V.S. No Turnover')
Text(0.5, 1.0, 'Employee AverageMonthly Hours Distribution - Turnover V.S. No Turnover')

# 概率密度函数估计
fig = plt.figure(figsize=(15,4))
ax=sns.kdeplot(df.loc[(df['turnover'] == 0),'satisfaction'] , color='b',shade=True, label='no turnover')
ax=sns.kdeplot(df.loc[(df['turnover'] == 1),'satisfaction'] , color='r',shade=True, label='turnover')
plt.title('Employee Satisfaction Distribution - Turnover V.S. No Turnover')
ax.legend()
<matplotlib.legend.Legend at 0x281a5a6b820>

from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report, precision_score, recall_score, confusion_matrix, precision_recall_curve
# 将string类型转换为整数类型
df["department"] = df["department"].astype('category').cat.codes
df["salary"] = df["salary"].astype('category').cat.codes
# 产生X, y
target_name = 'turnover'
X = df.drop('turnover', axis=1)
y = df[target_name]
# 将数据分为训练和测试数据集
# 注意参数 stratify = y 意味着在产生训练和测试数据中, 离职的员工的百分比等于原来总的数据中的离职的员工的百分比
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.15, random_state=123, stratify=y)
df.head()
 turnover satisfaction evaluation projectCount averageMonthlyHours yearsAtCompany workAccident promotion department salary 0 1 0.38 0.53 2 157 3 0 0 7 1 1 1 0.80 0.86 5 262 6 0 0 7 2 2 1 0.11 0.88 7 272 4 0 0 7 2 3 1 0.72 0.87 5 223 5 0 0 7 1 4 1 0.37 0.52 2 159 3 0 0 7 1

## 4. 建立预测模型：Decision Tree V.S. Random Forest

from sklearn.metrics import roc_auc_score
from sklearn.metrics import classification_report
from sklearn.ensemble import RandomForestClassifier
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
# 决策树
dtree = tree.DecisionTreeClassifier(
criterion='entropy',
#max_depth=3, # 定义树的深度, 可以用来防止过拟合
min_weight_fraction_leaf=0.01 # 定义叶子节点最少需要包含多少个样本(使用百分比表达), 防止过拟合
)
dtree = dtree.fit(X_train,y_train)
print ("\n\n ---决策树---")
dt_roc_auc = roc_auc_score(y_test, dtree.predict(X_test))
print ("决策树 AUC = %2.2f" % dt_roc_auc)
print(classification_report(y_test, dtree.predict(X_test)))
# 随机森林
rf = RandomForestClassifier(
criterion='entropy',
n_estimators=1000,
max_depth=None, # 定义树的深度, 可以用来防止过拟合
min_samples_split=10, # 定义至少多少个样本的情况下才继续分叉
#min_weight_fraction_leaf=0.02 # 定义叶子节点最少需要包含多少个样本(使用百分比表达), 防止过拟合
)
rf.fit(X_train, y_train)
print ("\n\n ---随机森林---")
rf_roc_auc = roc_auc_score(y_test, rf.predict(X_test))
print ("随机森林 AUC = %2.2f" % rf_roc_auc)
print(classification_report(y_test, rf.predict(X_test)))
---决策树---

precision    recall  f1-score   support
0       0.97      0.98      0.97      1714
1       0.93      0.89      0.91       536
accuracy                           0.96      2250
macro avg       0.95      0.93      0.94      2250
weighted avg       0.96      0.96      0.96      2250
---随机森林---

precision    recall  f1-score   support
0       0.98      1.00      0.99      1714
1       0.99      0.94      0.97       536
accuracy                           0.98      2250
macro avg       0.99      0.97      0.98      2250
weighted avg       0.98      0.98      0.98      2250

## 5. 模型评估

### 5.1ROC 图

# ROC 图
from sklearn.metrics import roc_curve
rf_fpr, rf_tpr, rf_thresholds = roc_curve(y_test, rf.predict_proba(X_test)[:,1])
dt_fpr, dt_tpr, dt_thresholds = roc_curve(y_test, dtree.predict_proba(X_test)[:,1])
plt.figure()
# 随机森林 ROC
plt.plot(rf_fpr, rf_tpr, label='Random Forest (area = %0.2f)' % rf_roc_auc)
# 决策树 ROC
plt.plot(dt_fpr, dt_tpr, label='Decision Tree (area = %0.2f)' % dt_roc_auc)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Graph')
plt.legend(loc="lower right")
plt.show()

### 5.2通过决策树分析不同的特征的重要性

## 画出决策树特征的重要性 ##
importances = rf.feature_importances_
feat_names = df.drop(['turnover'],axis=1).columns
indices = np.argsort(importances)[::-1]
plt.figure(figsize=(12,6))
plt.title("Feature importances by RandomForest")
plt.bar(range(len(indices)), importances[indices], color='lightblue',  align="center")
plt.step(range(len(indices)), np.cumsum(importances[indices]), where='mid', label='Cumulative')
plt.xticks(range(len(indices)), feat_names[indices], rotation='vertical',fontsize=14)
plt.xlim([-1, len(indices)])
plt.show()

## 画出决策树的特征的重要性 ##
importances = dtree.feature_importances_
feat_names = df.drop(['turnover'],axis=1).columns
indices = np.argsort(importances)[::-1]
plt.figure(figsize=(12,6))
plt.title("Feature importances by Decision Tree")
plt.bar(range(len(indices)), importances[indices], color='lightblue',  align="center")
plt.step(range(len(indices)), np.cumsum(importances[indices]), where='mid', label='Cumulative')
plt.xticks(range(len(indices)), feat_names[indices], rotation='vertical',fontsize=14)
plt.xlim([-1, len(indices)])
plt.show()

|
8小时前
|

【7月更文挑战第24天】在数据科学中,数据可视化是探索与沟通的关键。从Matplotlib的基础绘图到Seaborn的统计图形,再到Plotly的交互式图表,这些工具助你成为数据叙事大师。示例代码涵盖正弦波图、小费散点图及鸢尾花分布图,展现从简单到复杂的可视化之旅。掌握这些技巧,你就能更有效地解析和呈现数据故事。
10 4
|
1天前
|

【7月更文挑战第23天】在Python机器学习中,模型评估不可或缺。Matplotlib与Seaborn作为数据可视化工具,助力洞察模型性能。Matplotlib基础灵活,构建复杂图表;Seaborn在其上层,简化绘图,提升美观。从折线图追踪损失到条形图对比准确率,两者互补,促进高效决策制定。尽管Matplotlib掌控力强,但Seaborn友好快捷,适于统计图形。结合使用,可将数据转化成深刻见解。
12 6
|
7天前
|

38 5
|
11天前
|

【7月更文挑战第13天】本文详细介绍了基于机器学习的房价预测项目的实战过程。从数据准备、特征工程、模型构建到结果评估，每一步都至关重要。通过合理的特征选择和模型优化，我们可以构建出性能优异的房价预测模型，为房地产行业的决策提供有力支持。未来，随着机器学习技术的不断发展和应用场景的不断拓展，房价预测模型将更加智能化和精准化。
41 7
|
11天前
|

12 0
|
22天前
|

【7月更文第2天】阿里云百炼是AI大模型开发平台，提供一站式服务，涵盖模型训练到部署。用户从注册登录、创建应用开始，选择模型框架，配置资源。接着，进行数据准备、预处理，上传至阿里云OSS。模型训练涉及设置参数、启动训练及调优。训练后，模型导出并部署为API，集成到应用中。平台提供监控工具确保服务性能。通过百炼，开发者能高效地进行大模型实战，开启AI创新。
229 2
|
27天前
|

24 0
|
1月前
|

29 2
|
1月前
|

28 3
|
1月前
|

【机器学习】AI在空战决策中的崛起：从理论到实践的跨越
【机器学习】AI在空战决策中的崛起：从理论到实践的跨越
142 0