【data science-简单的实践】探索员工离职率与哪些因素有较强的关联

数据集

路径:input/Ch3-Turnover.csv

描述:人力资源数据集,记录员工信息。

目的:用于探索员工离职率与哪些因素有较强的关联。

规格:(14999, 10)

思路:

1.查看数据

(1)读入数据 → 查看缺失值 → 属性重命名、移位 → 文字属性值编码

2.查看相关性

(1)相关性矩阵 → turnover与各种属性之间的关系图 → 发现结论

3.评估属性影响力

(1)分析员工集群 → 聚类 → 分析影响力

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn import tree
from sklearn.model_selection import train_test_split


"""  -------- 1-1.数据读入 --------  """
df = pd.read_csv("input/Ch3-Turnover.csv", index_col=None)


"""  -------- 1-2.数据查看 --------  """
# 设置全部显示
pd.set_option('display.max_columns', None)  # 显示所有列
pd.set_option('display.expand_frame_repr', False)  # 不允许水平拓展
pd.set_option('display.max_rows', None)  # 显示所有行
# 查看原始数据
print(df.head())
print(df.tail(3))
# 查看非数据类型的列所含的值,便于后续编码
print(df['sales'].value_counts())
print(df['salary'].value_counts())


"""  -------- 1-3.查看是否有缺失值 --------  """
print(df.isnull().any())  # 输出均为False,没有缺失值


"""  -------- 1-4.重命名 --------  """
df = df.rename(columns={
    'satisfaction_level': 'satisfaction',
    'last_evaluation': 'evaluation',
    'number_project': 'ProjectCount',
    'average_montly_hours': 'averageMonthlyHours',  # 呃,原表格数据就是montly打错了,查半天bug玉玉了
    'time_spend_company': 'yearsAtCompany',
    'Work_accident': 'workAccident',
    'left': 'turnover',
    'promotion_last_5years': 'promotion',
    'sales': 'department'
})  # 重命名以提高可读性
print(df.columns)  # 表首行


"""  -------- 1-5.变量移动位置 --------  """
front = df['turnover']  # 创建一个名为front的新Series
df.drop(labels=['turnover'], axis=1, inplace=True)  # inplace=True表示在原始DataFrame上进行修改
df.insert(0, 'turnover', front)  # 插入索引=0的列(第一列),原先的列自动后退一列
print(df.head())


"""  -------- 1-6.数据描述 --------  """
print(df.shape)  # 规格(14999, 10)
print(df.dtypes)  # 各列的数据类型,返回值是Series对象。
print(df.columns)  # 表首行
print(df.describe().T)  # 将describe转置,每一行对应一个属性的各个描述(count,mean,std,min,25%,50%,75%,max)
print(df['turnover'].value_counts())  # 查看离职人数(0:未离职,1:离职)
print(df['turnover'].value_counts() / len(df))  # 查看离职百分比(0:未离职,1:离职)


"""  -------- 1-7.对文字型数据编码 --------  """
# 定义编码映射字典
department_mapping = {
    'sales': 1, 'technical': 2, 'support': 3, 'IT': 4,
    'product_mng': 5, 'marketing': 6, 'RandD': 7,
    'accounting': 8, 'hr': 9, 'management': 10
}
salary_mapping = {'low': 1, 'medium': 2, 'high': 3}
# 使用replace函数进行编码
df['department'] = df['department'].replace(department_mapping)
df['salary'] = df['salary'].replace(salary_mapping)
# 查看编码后的DataFrame
print(df.head())


"""  -------- 1-7.初步分析离职人员的情况 --------  """
turnover_summary = df.groupby('turnover')
print(turnover_summary.mean())  # 从输出来看。初步分析turnover可能与satisfaction和salary关系很大。


"""  -------- 2-1.查看相关性矩阵 --------  """
corr = df.corr()
print(corr)
# np.fill_diagonal(corr.values, np.nan)  # 这段代码用于屏蔽与自身的相关系数,让图片更加清晰但是不美观
sns.heatmap(corr, annot=True, cmap='coolwarm', fmt=".2f", xticklabels=corr.columns.values, yticklabels=corr.columns.values)
plt.show()
# 与turnover相关系数的绝对值大于0.1的有satisfaction-0.39,yearsAtCompany0.14,workAccident-0.15,salary-0.16
"""2-1结论1:不满意公司的大都倾向于离开公司"""
# 额外注意到evaluation,ProjectCount,averageMonthlyHours之间相关性较强(均>0.3)
"""2-1结论2:说明花更多时间和做更多项目的员工更容易得到高度评价"""


"""  -------- 2-2.绘制分布图 --------  """
"""2-2目标1:用于直观检验2-1中的「evaluation,ProjectCount,averageMonthlyHours之间相关性较强」这一结论"""
f, axes = plt.subplots(ncols=3, figsize=(12, 4))
# displot是一个图形级别的函数,不接受ax参数,而是用于创建一个图形对象。如果想要绘制直方图并将它们放在指定的子图中,应使用histplot
sns.histplot(df['satisfaction'], kde=False, color='g', ax=axes[0]).set_title("Employee-Satisfaction")
axes[0].set_ylabel('Employee Count')
sns.histplot(df['evaluation'], kde=False, color='r', ax=axes[1]).set_title("Employee-Evaluation")
axes[1].set_ylabel('Employee Count')
sns.histplot(df['averageMonthlyHours'], kde=False, color='b', ax=axes[2]).set_title("Employee-averageMonthlyHours")
axes[2].set_ylabel('Employee Count')
plt.show()
"""2-2结论1:发现三个图像都呈现双峰,尤其是Evaluation与averageMonthlyHours的分布比较相似"""


"""  -------- 2-3.绘制关系图并查看具体关系(探索离职率与其他属性的关系) --------  """
""" 2-3-1.离职率与薪水 """
f, ax = plt.subplots(figsize=(12, 6))
sns.countplot(y='salary', hue='turnover', data=df).set_title('Salary-Turnover')
plt.show()
"""2-3-1结论1&目标1:发现高薪的大都没离职,低薪的更容易离职。以下验证离职率"""
LowSalary_df = df[df['salary'] == 1]  # 筛选出薪资低的员工
MediumSalary_df = df[df['salary'] == 2]
HighSalar_df = df[df['salary'] == 3]
turnover_LowSalary = LowSalary_df[LowSalary_df['turnover'] == 1]  # 筛选出低薪离职的员工
turnoverRate_LowSalary = len(turnover_LowSalary) / len(LowSalary_df)  # 计算低薪离职率
turnover_MediumSalary = MediumSalary_df[MediumSalary_df['turnover'] == 1]
turnoverRate_MediumSalary = len(turnover_MediumSalary) / len(MediumSalary_df)
turnover_HighSalary = HighSalar_df[HighSalar_df['turnover'] == 1]
turnoverRate_HighSalary = len(turnover_HighSalary) / len(HighSalar_df)
print(f"低薪员工的离职率为: {turnoverRate_LowSalary:.2%}")  # 29.69%
print(f"中薪员工的离职率为: {turnoverRate_MediumSalary:.2%}")  # 20.43%
print(f"高薪员工的离职率为: {turnoverRate_HighSalary:.2%}")  # 6.63%
# 上面的方法可以替换为groupby,下面用两种方法使用groupby给出离职率
# 1.得到salary与turnover对应的二维矩阵
turnover_rates = df.groupby('salary')['turnover'].value_counts(normalize=True) * 100
print(turnover_rates)
print(f"低薪员工的离职率为: {turnover_rates[1][1]:.2f}%")
print(f"中薪员工的离职率为: {turnover_rates[2][1]:.2f}%")
print(f"高薪员工的离职率为: {turnover_rates[3][1]:.2f}%")
# 2.得到salary对应turnover=1的比率。因为turnover=0,1,所以计算平均值mean就相当于计算了turnover=1的比率,乘100是为了“变成”%
turnover_rates_groupby = df.groupby('salary')['turnover'].mean() * 100
print(turnover_rates_groupby)


""" 2-3-2.离职率与部门 """
color_types = ['#66CCFF', '#FEE4D0', '#39C5BB', '#EE0000', '#AA6680', '#B2D8E8', '#00FFCC', '#FFC0CB', '#FAF9DE', '#FDE6E0']
sns.countplot(x='department', data=df, palette=color_types).set_title('Employee-Department')  # 分布图
# plt.xticks(rotation=-45)  # x坐标顺时针旋转45°
plt.show()
f, ax = plt.subplots(figsize=(15, 5))
sns.countplot(y="department", hue='turnover', data=df).set_title('Employee Department Turnover Distribution')  # 关系图
plt.show()
"""2-3-2结论1:sales,technical,support department的离职率很高,这里不再一一给出离职率"""


""" 2-3-3.离职率与评价 """
fig = plt.figure(figsize=(15, 4), )
ax = sns.kdeplot(df.loc[(df['turnover'] == 0), 'evaluation'], color='b', fill=True, label='no turnover')
ax = sns.kdeplot(df.loc[(df['turnover'] == 1), 'evaluation'], color='r', fill=True, label='turnover')
ax.set(xlabel='Employee Evaluation', ylabel='Frequency')
plt.title('Employee Evaluation Distribution - Turnover V.S. No Turnover')
plt.show()
"""2-3-3结论1:离职率和评价间存在双峰分布。low和high表现的员工更倾向于离开公司。对于员工来讲具有 0.6-0.8 的评价是一个舒适区。"""
sns.boxplot(x="ProjectCount", y="evaluation", hue="turnover", data=df)
plt.show()
"""2-3-3发现1:完成更多项目的离职员工的评价有所提高。但是,未离职员工随着项目数量有所增加其评价却没有变化(稳定在0.7)。
并且当项目数量有所增加时(>3)离职员工的平均评价显著高于未离职员工。
离职的人大都为2个项目但评价是坏 或者 大于3个项目但评价是好"""

""" 2-3-4.离职率与项目数量 """
ax = sns.barplot(x="ProjectCount", y="ProjectCount", hue="turnover", data=df, estimator=lambda x: len(x) / len(df) * 100)
ax.set(ylabel="Percent")
plt.show()
"""2-3-4结论1:有2,6和7个项目的员工中一半多都离开了公司。有7个项目的员工全都离开了公司。随着项目数量的增加,员工的离职率上升。
大多数没有离开公司的员工有3,4,5个项目。"""
"""下面查看项目数和工作时间有什么关系"""
sns.boxplot(x="ProjectCount", y="averageMonthlyHours", hue="turnover", data=df)
plt.show()
""""2-3-4结论2:没有离职的员工的工作时间基本不因为项目数量的增加而增加,但离职的员工的工作时间显著因为项目数量的增加而增加。"""

""" 2-3-5.离职率与工作年限 """
ax = sns.barplot(x="yearsAtCompany", y="yearsAtCompany", hue="turnover", data=df, estimator=lambda x: len(x) / len(df) * 100)
ax.set(ylabel="Percent")
plt.show()
""""2-3-5结论1:工作了4、5年的员工有一半以上离开了公司,或许他们本应该受到重视"""


"""  -------- 3-1.整体分析离职的群体 --------  """
sns.lmplot(x='satisfaction', y='evaluation', data=df, fit_reg=False,  hue='turnover')   # 不显示回归线
plt.show()
"""
3-1结论:
离开公司的员工有 3 个不同的集群:
Cluster 1 (勤奋工作并且不开心的员工): 满意度低于0.2,评价高于0.75。这可能是一个很好的迹象,表明离开公司的员工都是好员工,但对自己的工作感觉很糟糕。
Question1: 当你被高度评价的时候,是什么原因让员工感觉如此糟糕?会不会太辛苦了?这个集群是否意味着“过度工作”的员工?
Answer  1:虽然高评价员工的离职可能引起担忧,但它也可能是一个机会,让公司审查他们的员工满意度和工作条件,以改进工作环境,以满足员工的需求,从而减少离职率。
           这是为什么说Cluster 1可能是一个很好的迹象,因为它可以帮助公司识别和解决潜在的问题,以提高员工满意度和留住高绩效的员工。
Cluster 2 (评价低并且不开心的员工): 满意度在0.35~0.45之间,评价在0.58以下。这可以被看作是在工作中受到了不好的评价和感觉不好的员工。
Question2: 这个集群是否意味着“表现不佳”的员工?
Answer  2:他们在工作中遇到了问题,无法满足公司的期望。或者说他们的潜力可能没有办法在这样的公司里发挥出来。
Cluster 3 (勤奋工作并且开心的员工): 满意度在0.7~1.0之间,评价大于0.8。这可能意味着这个集群中的员工是“理想的”。他们热爱自己的工作,并因工作表现而受到高度评价。
Question3: 这个集群是否意味着员工离开是因为他们找到了另一个工作机会?
Answer  3:或许需要用更有竞争力的薪酬、福利、职业发展机会、管理、指导、工作负荷来挽留这些“理想员工”。
"""


"""  -------- 3-2.聚类 --------  """
"""聚类:Cluster 1 (Blue): 勤奋工作并且不开心的员工,
        Cluster 2 (Red):   评价低并且不开心的员工,
        Cluster 3 (Green): 勤奋工作并且开心的员工。"""
# Graph and create 3 clusters of Employee Turnover
kmeans = KMeans(n_clusters=3, random_state=2, n_init=10)  # 默认情况下,n_init是10,但在将来的版本中将更改为auto。
kmeans.fit(df[df.turnover == 1][["satisfaction", "evaluation"]])
kmeans_colors = ['green' if c == 0 else 'blue' if c == 2 else 'red' for c in kmeans.labels_]
fig = plt.figure(figsize=(10, 6))
plt.scatter(x="satisfaction", y="evaluation", data=df[df.turnover == 1], alpha=0.25, color=kmeans_colors)
plt.xlabel("Satisfaction")
plt.ylabel("Evaluation")
plt.scatter(x=kmeans.cluster_centers_[:, 0], y=kmeans.cluster_centers_[:, 1], color="black", marker="X", s=100)
plt.title("Clusters of Employee Turnover")
plt.show()


"""  -------- 3-3.特征的重要性 --------  """
plt.style.use('fivethirtyeight')
plt.rcParams['figure.figsize'] = (12, 6)
# Convert these variables into categorical variables
df["department"] = df["department"].astype('category').cat.codes
df["salary"] = df["salary"].astype('category').cat.codes
# Create train and test splits
target_name = 'turnover'
X = df.drop('turnover', axis=1)
y = df[target_name]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.15, random_state=123, stratify=y)
dtree = tree.DecisionTreeClassifier(
    # max_depth=3,
    class_weight="balanced",
    min_weight_fraction_leaf=0.01
    )
dtree = dtree.fit(X_train, y_train)
# plot the importances
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 DecisionTreeClassifier")
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.xticks(rotation=45)  # x坐标逆时针旋转45°
plt.show()
"""
3-3结论:
通过使用决策树分类器,它可以对用于预测的特征进行排序。前三个特征是员工满意度、工作年限和评价。
这有助于创建我们的回归模型,因为当我们使用较少的特征时,理解模型中的内容会更容易理解。
"""

代码输出 与 探索思路

PART 1

turnover

0    11428     0.761917

1     3571     0.238083

猜测turnover可能与satisfaction和salary关系很大。

PART 2

2-1 相关性矩阵

不满意公司的大都倾向于离开公司。

2-2 满意度、评价、工作时长的关系

三个图比较相近。工作时间和评价都是双峰,是否说明工作者分为两种(工作久评价高&工作少评价低亦或者其他类型)?

2-3 薪水与离职

高薪的大都没离职,低薪的更容易离职。

低薪员工的离职率为: 29.69%   中薪员工: 20.43%   高薪员工: 6.63%

2-4 部门与离职

sales,technical,support department的离职率很高

2-5 评价与离职

离职率和评价间存在双峰分布。low和high表现的员工更倾向于离开公司。对于员工来讲具有0.6-0.8的评价是一个舒适区。

2-6 评价与完成项目数量&离职

完成更多项目的离职员工的评价有所提高。但是,未离职员工随着项目数量有所增加其评价却没有变化(稳定在0.7)。
并且当项目数量有所增加时(>3)离职员工的平均评价显著高于未离职员工。
离职的人大都为2个项目但评价是坏 或者 大于3个项目但评价是好

2-7 完成项目数量&离职

有2,6和7个项目的员工中一半多都离开了公司。有7个项目的员工全都离开了公司。随着项目数量的增加,员工的离职率上升。
大多数没有离开公司的员工有3,4,5个项目。

没有离职的员工的工作时间基本不因为项目数量的增加而增加,但离职的员工的工作时间显著因为项目数量的增加而增加

2-8 离职与工作年限

工作了4、5年的员工有一半以上离开了公司,或许他们本应该受到重视。

PART 3

3-1 整体分析

离开公司的员工有3个不同的集群:
Cluster 1 (勤奋工作并且不开心的员工): 满意度低于0.2,评价高于0.75。这可能是一个很好的迹象,表明离开公司的员工都是好员工,但对自己的工作感觉很糟糕。
Question1: 当你被高度评价的时候,是什么原因让员工感觉如此糟糕?会不会太辛苦了?这个集群是否意味着“过度工作”的员工?
Answer  1:虽然高评价员工的离职可能引起担忧,但它也可能是一个机会,让公司审查他们的员工满意度和工作条件,以改进工作环境,以满足员工的需求,从而减少离职率。
           这是为什么说Cluster 1可能是一个很好的迹象,因为它可以帮助公司识别和解决潜在的问题,以提高员工满意度和留住高绩效的员工。
Cluster 2 (评价低并且不开心的员工): 满意度在0.35~0.45之间,评价在0.58以下。这可以被看作是在工作中受到了不好的评价和感觉不好的员工。
Question2: 这个集群是否意味着“表现不佳”的员工?
Answer  2:他们在工作中遇到了问题,无法满足公司的期望。或者说他们的潜力可能没有办法在这样的公司里发挥出来。
Cluster 3 (勤奋工作并且开心的员工): 满意度在0.7~1.0之间,评价大于0.8。这可能意味着这个集群中的员工是“理想的”。他们热爱自己的工作,并因工作表现而受到高度评价。
Question3: 这个集群是否意味着员工离开是因为他们找到了另一个工作机会?
Answer  3:或许需要用更有竞争力的薪酬、福利、职业发展机会、管理、指导、工作负荷来挽留这些“理想员工”。

3-2 K-means

聚类:Cluster 1 (Blue): 勤奋工作并且不开心的员工,
      Cluster 2 (Red):  评价低并且不开心的员工,
      Cluster 3 (Green): 勤奋工作并且开心的员工。

3-3 重要性分析

通过使用决策树分类器,它可以对用于预测的特征进行排序。前三个特征是员工满意度、工作年限和评价。
这有助于创建回归模型,因为当使用较少的特征时,理解模型中的内容会更容易理解。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值