Skip to content

Data analysis - Tại sao nhân viên nghỉ việc?

Posted on:September 8, 2017

Pham Thị vốn là một tập đoàn lớn nhất nhì ở cái đất này. Người đông thế mạnh, tiềm lực tài chính lên đến con số hàng nghìn tỉ, tuấn kiệt như sao buổi tối, nhân tài nhiều như lá rụng mùa thu, trai xinh gái đẹp đủ cả. Thực là o-sằm! 😎

Thế nhưng dạo gần đây xuất hiện nhiều sự lạ, các nhân viên lần lượt ra đi, thậm chí cả những khai quốc công thần từng cống hiến cho Pham Thị từ những ngày đầu. Thực đáng quan ngại! 😨

Ban lãnh đạo tập đoàn đã phải lập tức tiến hành các cuộc họp để tìm ra nguyên nhân tại sao xảy ra tình trạng ấy. Một cuộc điều tra đã được diễn ra với sự vào cuộc của tất cả các phòng ban, và những kết quả được đưa ra thực khiến tất cả mọi người không khỏi bất ngờ 😱

1. Business Problems

“You don’t build a business. You build people, and people build the business.” - Zig Ziglar

Câu chuyện bên trên chỉ là một câu chuyện hư cấu =)) tuy nhiên nó cũng đúng phần nào đối với các công ty. Nhân sự luôn luôn là một vấn đề đau đầu nhất đối với các lãnh đạo. Tìm được người phù hợp đã khó, giữ người còn khó hơn.

Bài phân tích này của mình sẽ nhằm mục đích tìm ra một số điểm “đáng lưu ý” khi nhân viên ra đi, dựa trên dataset Human Resources Analytics được cung cấp bởi Kaggle.

📌 Note: Dữ liệu được xây dựng, không phải dữ liệu thực tế của Pham Thị hay bất cứ công ty nào cả.

Các công cụ: Jupyter Notebook, Python 3.5, Numpy, Pandas, Matplotlib, Seaborn, Scikit-Learn.

2. Obtaining Data

Ta sẽ download dữ liệu csv từ Kaggle về và sau đó sử dụng Pandas để load dữ liệu ra.

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

df = pd.DataFrame.from_csv('../input/HR_comma_sep.csv', index_col=None)

Đối với các dữ liệu thống kê nói chung, thì việc thiếu dữ liệu hoặc dữ liệu bị sai là điều khó thể tránh khỏi. Vì thế trước khi phân tích chúng ta đều phải có bước tiền xử lý để hoặc là fill các dữ liệu đó, hoặc là xoá nó đi.

>>> 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

Ô kê, dữ liệu được chuẩn bị khá là ngon rồi :D

Ta sẽ nhìn lướt qua data một chút để nắm được có những thông tin gì ở đây.

>>> df.head()

png Có tất cả 10 thông tin đối với mỗi nhân viên. Trong đó có rất nhiều thông tin thú vị, như số giờ làm việc trung bình trong tháng, lương cao hay thấp, số project đã làm, số phốt,…

Nhận thấy rằng những tên cột đang là physics name, khá khó cho việc đọc hiểu, nên ta sẽ sửa lại tên các cột một chút cho “thân thiện” như sau:

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'
                        })

Trong bài này, ta quan tâm đến việc nhân viên ở lại hay ra đi, nên cột turnover ta sẽ đưa lên đầu cho dễ nhìn

front = df['turnover']
df.drop(labels=['turnover'], axis=1,inplace = True)
df.insert(0, 'turnover', front)
df.head()

png

3. Analyzing Data

Đã có cái nhìn tổng quát về dữ liệu, ta bắt đầu tiến hành phân tích thôi :D

3.1. Thống kê tổng quan

>>> df.shape
(14999, 10)
>>> turnover_rate = df.turnover.value_counts() / 14999
>>> turnover_rate
0    0.761917
1    0.238083
Name: turnover, dtype: float64
>>> df.describe()

png

>>> turnover_Summary = df.groupby('turnover')
>>> turnover_Summary.mean()

png

f, axes = plt.subplots(ncols=3, figsize=(15, 6))
sns.distplot(df.satisfaction, kde=False, color="g", ax=axes[0]).set_title('Employee Satisfaction Distribution')
sns.distplot(df.evaluation, kde=False, color="r", ax=axes[1]).set_title('Employee Evaluation Distribution')
sns.distplot(df.averageMonthlyHours, kde=False, color="b", ax=axes[2]).set_title('Employee Average Monthly Hours Distribution')

png

3.2. Ma trận độ tương quan giữa các features

Ta sẽ hiển thị ra ma trận độ tương quan giữa các features.

corr = df.corr()
corr = (corr)
sns.heatmap(corr,
            xticklabels=corr.columns.values,
            yticklabels=corr.columns.values)
sns.plt.title('Heatmap of Correlation Matrix')
corr

png png

  projectCount vs evaluation: 0.349333
  projectCount vs averageMonthlyHours:  0.417211
  averageMonthlyHours vs evaluation: 0.339742

Nó có ý nghĩa rằng những nhân viên dành nhiều thời gian làm việc tại công ty hơn và tham gia nhiều project hơn sẽ được đánh giá cao hơn.

satisfaction vs turnover:  -0.388375

Một sự thật hiển nhiên thôi, càng ít thoả mãn thì khả năng rời đi càng cao.

💡 Suy ngẫm:

3.3. Nghỉ việc vs Lương

Rõ ràng đây luôn là yếu tố đầu tiên và trực diện nhất =))

f, ax = plt.subplots(figsize=(15, 4))
sns.countplot(y="salary", hue='turnover', data=df).set_title('Employee Salary Turnover Distribution');

png

Summary:

💡 Suy ngẫm: Vẫn có những nhân viên lương cao ra đi, lý do vì đâu?

3.4. Nghỉ việc vs Bộ phận làm việc

color_types = ['#78C850','#F08030','#6890F0','#A8B820','#A8A878','#A040A0','#F8D030', '#E0C068','#EE99AC','#C03028','#F85888','#B8A038','#705898','#98D8D8','#7038F8']
sns.countplot(x='department', data=df, palette=color_types).set_title('Employee Department Distribution');
plt.xticks(rotation=-45)

png

f, ax = plt.subplots(figsize=(15, 5))
sns.countplot(y="department", hue='turnover', data=df).set_title('Employee Department Turnover Distribution');

png Summary:

3.5. Nghỉ việc vs Số lượng project đã tham gia

ax = sns.barplot(x="projectCount", y="projectCount", hue="turnover", data=df, estimator=lambda x: len(x) / len(df) * 100)
ax.set(ylabel="Percent")

png Summary:

💡 Suy ngẫm: Những người làm 6+ projects hẳn là những nhân viên lâu năm, phải chăng họ cần thêm điều gì nữa ngoài những projects để tránh khỏi sự nhàm chán mà ra đi?

3.6. Nghỉ việc vs Đánh giá

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')
plt.title('Employee Evaluation Distribution - Turnover V.S. No Turnover')

png Summary:

💡 Suy ngẫm: Việc đánh giá thấp nhân viên rõ ràng là không tốt, nhưng việc đánh giá quá cao nhân viên cũng không hề tốt hơn. Tại sao ? mỗi chúng ta đều có những mục tiêu riêng cho mình để phấn đấu, khi con người ảo tưởng rằng mình đã quá ngon, đã perfect, cũng giống như đỉnh cao lạnh lẽo, đâu còn mục tiêu gì mà phấn đấu, nên ra đi là điều không hề kỳ lạ.

3.7. Nghỉ việc vs Thời gian làm việc trung bình trong tháng

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')
plt.title('Employee AverageMonthly Hours Distribution - Turnover V.S. No Turnover')

png Summary: Sơ đồ gần giống với Evaluation bên trên

Những điều này dễ hiểu, ngồi chơi không có việc gì để làm, và OT quá độ đều không tốt và dẫn tới sự ra đi của nhân viên. Các sếp hãy tạo điều kiện tốt nhất để ai cũng có việc làm đầy đủ và vui vẻ.

3.8 Đánh giá vs Độ thoả mãn

sns.lmplot(x='satisfaction', y='evaluation', data=df,
           fit_reg=False, # No regression line
           hue='turnover')   # Color by evolution stage

png Summary:3 Nhóm nhân viên có xu hướng rời công ty

3.9. Sử dụng K-Means Clustering

Ta sẽ sử dụng K-Means Clustering để phân loại một cách định lượng các nhân viên rời đi vào 3 class như trên. Cụ thể:

from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=3,random_state=2)
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()

png

4. Kết luận

Đã có rất nhiều điểm đáng chú ý, tuy nhiên dữ liệu là dựng nên vẫn chưa đủ tốt để đánh giá hết các góc cạnh cũng như độ tương quan giữa các yếu tố trong một công ty.

Sẽ cần lắm thêm nữa những dữ liệu nhân sự thực tế của các công ty, để biết đâu nhờ phân tích chúng mà Pham Thị có thể trở thành công ty dẫn đầu về HR Solution trong tương lai. Có thể lắm!


“You don’t build a business. You build people, and people build the business.” - Zig Ziglar


5. Tham khảo