【Python实践案例】电商平台数据分析和挖掘 -分析员工出勤
第一步:数据加载与清洗
首先数据是一份 Excel 文件,我们需要预处理,包含了员工的打卡记录,包括 CheckIn(上班时间)和 CheckOut(下班时间)。:
df = pd.read_excel("employee_attendance.xlsx")
df['CheckIn'] = pd.to_datetime(df['CheckIn'], errors='coerce')
df['CheckOut'] = pd.to_datetime(df['CheckOut'], errors='coerce')
df.dropna(subset=['CheckIn', 'CheckOut'], inplace=True)
然后我计算了每位员工的每日工作时长,并提取了时间维度,比如周、月、星期几等,为后续分析做准备。
📈 第二步:可视化分析开始!
接下来,我开始用图表来“讲故事”。
1. 员工平均工作时长排名
首先,我绘制了每个员工的平均工作时长,看看谁是“加班狂魔”:
avg_work = df.groupby('Name')['Work Duration'].mean().sort_values(ascending=False)
plot_bar(avg_work, '员工平均工作时长排名', '员工姓名', '平均工作时长(小时)')
2. 总工作时长:谁是“劳模”?
统计了每个人的总工作时长,看看谁是真正的“劳模”:
total_work = df.groupby('Name')['Work Duration'].sum().sort_values(ascending=False)
plot_bar(total_work, '员工总工作时长排名', '员工姓名', '总工作时长(小时)')
图表显示,总时长与平均时长并不完全一致,说明有些人“靠时间”,有些人“靠效率”。
3. 每周 / 每月工作分布:堆叠条形图登场
为了进一步分析,用堆叠条形图展示了每位员工每周和每月的工作分布情况。这种图表非常适合观察趋势变化:
weekly_work = df.groupby(['Name', 'Week'])['Work Duration'].sum().unstack(fill_value=0)
plot_stacked_bar(weekly_work, '员工每周工作时长分布', '员工姓名', '总工作时长(小时)')
通过这个图,可以轻松发现某些员工在特定周次工作强度特别高,这可能与项目周期有关。
4. 工作趋势分析:折线图揭示变化
为了观察每位员工的工作趋势,绘制了每月工作时长的折线图:
monthly_trends = {name: group.groupby('Month')['Work Duration'].sum()
for name, group in df.groupby('Name')}
plot_line(monthly_trends, '员工每月工作时长趋势分析', '月份', '总工作时长(小时)')
有些员工在年初表现积极,到了年底反而“躺平”了,这也许能为 HR 提供一些管理上的启发。
5. 热力图:一图胜千言
热力图是我最喜欢的一种可视化方式,它能直观地展示二维数据的密集程度。分别绘制了每周和每月的工作热力图:
pivot_weekly = df.pivot_table(index='Name', columns='Week',
values='Work Duration', aggfunc='sum', fill_value=0)
plot_heatmap(pivot_weekly, '员工每周工作时长热力图', '周次', '员工姓名')
6. 饼图:工作日分布分析最后,我还用饼图展示了员工的工作日分布情况,看看大家更喜欢哪一天上班:weekday_counts = df['Weekday'].value_counts()
plt.pie(weekday_counts, autopct='%1.1f%%', startangle=90)
📌 如果你也想尝试你可以轻松复用我的代码,只需要:准备一份包含员工打卡时间的 Excel 文件;确保列名包含 CheckIn 和 CheckOut;运行代码,生成属于你的可视化分析报告!📥 获取完整代码如果你对这个项目感兴趣,可以复制下列完整代码和示例数据。也欢迎你分享自己的分析结果,我们一起探讨数据的魅力!
数据:DateEmployeeIDNameDepartmentCheckInCheckOut
2025/10/2E001张三技术部
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from matplotlib.ticker import FuncFormatter
# 设置全局样式和字体
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("husl") # 使用更协调的配色方案
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 12
plt.rcParams['axes.titlesize'] = 16
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['legend.fontsize'] = 12
def load_and_preprocess_data(file_path):
"""加载并预处理数据"""
df = pd.read_excel(file_path)
df['CheckIn'] = pd.to_datetime(df['CheckIn'], errors='coerce')
df['CheckOut'] = pd.to_datetime(df['CheckOut'], errors='coerce')
df.dropna(subset=['CheckIn', 'CheckOut'], inplace=True)
# 计算工作时长
df['Work Duration'] = (df['CheckOut'] - df['CheckIn']).dt.total_seconds() / 3600
# 提取时间维度
df['Week'] = df['CheckIn'].dt.isocalendar().week
df['Month'] = df['CheckIn'].dt.month
df['Weekday'] = df['CheckIn'].dt.day_name()
return df
def plot_bar(data, title, xlabel, ylabel, color=None, figsize=(12, 6), add_values=True):
"""优化后的条形图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
ax = data.plot(kind='bar', color=color, edgecolor='white', linewidth=0.7, zorder=2)
# 添加数值标签
if add_values:
for p in ax.patches:
height = p.get_height()
ax.annotate(f'{height:.1f}',
(p.get_x() + p.get_width() / 2., height),
ha='center', va='center',
xytext=(0, 5),
textcoords='offset points',
fontsize=10,
color='dimgrey')
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
plt.xticks(rotation=45, ha='right')
plt.grid(axis='y', linestyle='--', alpha=0.7, zorder=1)
plt.tight_layout()
plt.show()
def plot_line(data_dict, title, xlabel, ylabel, figsize=(14, 7)):
"""优化后的折线图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
# 获取颜色循环
colors = sns.color_palette("husl", len(data_dict))
for i, (name, series) in enumerate(data_dict.items()):
plt.plot(series.index, series.values,
marker='o', markersize=8,
linewidth=2.5,
color=colors[i],
label=name,
zorder=3)
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
# 优化图例
plt.legend(title='员工',
bbox_to_anchor=(1.02, 1),
loc='upper left',
frameon=True,
framealpha=0.9,
edgecolor='white')
# 添加网格
plt.grid(True, linestyle='--', alpha=0.6, zorder=1)
# 优化坐标轴
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
def plot_heatmap(pivot_table, title, xlabel, ylabel, figsize=(14, 8)):
"""优化后的热力图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
# 创建自定义颜色映射
cmap = sns.diverging_palette(220, 20, as_cmap=True)
ax = sns.heatmap(pivot_table,
annot=True,
fmt='.1f',
cmap=cmap,
linewidths=0.5,
linecolor='white',
cbar_kws={
'label': '工作时长(小时)',
'shrink': 0.8,
'format': '%.1f'
},
annot_kws={"size": 10, "color": "black"})
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
# 优化坐标轴标签
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)
# 调整颜色条位置
cbar = ax.collections[0].colorbar
cbar.ax.yaxis.label.set_size(12)
plt.tight_layout()
plt.show()
def plot_stacked_bar(data, title, xlabel, ylabel, figsize=(14, 7)):
"""优化后的堆叠条形图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
ax = data.plot(kind='bar', stacked=True,
edgecolor='white', linewidth=0.7,
zorder=2)
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
plt.xticks(rotation=45, ha='right')
# 优化图例
plt.legend(title='周/月',
bbox_to_anchor=(1.02, 1),
loc='upper left',
frameon=True,
framealpha=0.9)
# 添加网格
plt.grid(axis='y', linestyle='--', alpha=0.7, zorder=1)
# 优化坐标轴
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
# 主程序逻辑
if __name__ == '__main__':
# 加载并处理数据
df = load_and_preprocess_data("employee_attendance.xlsx")
print(df.head())
# 1. 每个员工的平均工作时长(优化条形图)
avg_work = df.groupby('Name')['Work Duration'].mean().sort_values(ascending=False)
plot_bar(avg_work,
'员工平均工作时长排名',
'员工姓名',
'平均工作时长(小时)',
color=sns.color_palette("viridis", len(avg_work)),
add_values=True)
# 2. 每个员工的总工作时长(优化条形图)
total_work = df.groupby('Name')['Work Duration'].sum().sort_values(ascending=False)
plot_bar(total_work,
'员工总工作时长排名',
'员工姓名',
'总工作时长(小时)',
color=sns.color_palette("plasma", len(total_work)),
add_values=True)
# 3. 每个员工每周的工作时长(优化堆叠条形图)
weekly_work = df.groupby(['Name', 'Week'])['Work Duration'].sum().unstack(fill_value=0)
plot_stacked_bar(weekly_work,
'员工每周工作时长分布',
'员工姓名',
'总工作时长(小时)')
# 4. 每个员工每月的工作时长(优化堆叠条形图)
monthly_work = df.groupby(['Name', 'Month'])['Work Duration'].sum().unstack(fill_value=0)
plot_stacked_bar(monthly_work,
'员工每月工作时长分布',
'员工姓名',
'总工作时长(小时)')
# 5. 每个员工每月工作趋势折线图(优化折线图)
monthly_trends = {name: group.groupby('Month')['Work Duration'].sum()
for name, group in df.groupby('Name')}
plot_line(monthly_trends,
'员工每月工作时长趋势分析',
'月份',
'总工作时长(小时)')
# 6. 热力图:每周工作分布(优化热力图)
pivot_weekly = df.pivot_table(index='Name', columns='Week',
values='Work Duration', aggfunc='sum', fill_value=0)
plot_heatmap(pivot_weekly,
'员工每周工作时长热力图',
'周次',
'员工姓名')
# 7. 热力图:每月工作分布(优化热力图)
pivot_monthly = df.pivot_table(index='Name', columns='Month',
values='Work Duration', aggfunc='sum', fill_value=0)
plot_heatmap(pivot_monthly,
'员工每月工作时长热力图',
'月份',
'员工姓名')
# 新增:工作日分布分析(饼图)
weekday_counts = df['Weekday'].value_counts()
plt.figure(figsize=(10, 8), dpi=100)
colors = sns.color_palette("pastel")[0:7]
wedges, texts, autotexts = plt.pie(weekday_counts,
autopct='%1.1f%%',
startangle=90,
colors=colors,
wedgeprops={'linewidth': 1, 'edgecolor': 'white'},
textprops={'fontsize': 12})
plt.title('工作日分布比例', pad=20, fontweight='bold', fontsize=16)
plt.legend(wedges, weekday_counts.index,
title="星期",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
# 美化百分比标签
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
plt.tight_layout()
plt.show()
案例2
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from matplotlib.ticker import FuncFormatter
# 设置全局样式和字体
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("husl") # 使用更协调的配色方案
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 12
plt.rcParams['axes.titlesize'] = 16
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['legend.fontsize'] = 12
def load_and_preprocess_data(file_path):
"""加载并预处理数据"""
df = pd.read_excel(file_path)
df['CheckIn'] = pd.to_datetime(df['CheckIn'], errors='coerce')
df['CheckOut'] = pd.to_datetime(df['CheckOut'], errors='coerce')
df.dropna(subset=['CheckIn', 'CheckOut'], inplace=True)
# 计算工作时长
df['Work Duration'] = (df['CheckOut'] - df['CheckIn']).dt.total_seconds() / 3600
# 提取时间维度
df['Week'] = df['CheckIn'].dt.isocalendar().week
df['Month'] = df['CheckIn'].dt.month
df['Weekday'] = df['CheckIn'].dt.day_name()
return df
def plot_bar(data, title, xlabel, ylabel, color=None, figsize=(12, 6), add_values=True):
"""优化后的条形图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
ax = data.plot(kind='bar', color=color, edgecolor='white', linewidth=0.7, zorder=2)
# 添加数值标签
if add_values:
for p in ax.patches:
height = p.get_height()
ax.annotate(f'{height:.1f}',
(p.get_x() + p.get_width() / 2., height),
ha='center', va='center',
xytext=(0, 5),
textcoords='offset points',
fontsize=10,
color='dimgrey')
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
plt.xticks(rotation=45, ha='right')
plt.grid(axis='y', linestyle='--', alpha=0.7, zorder=1)
plt.tight_layout()
plt.show()
def plot_line(data_dict, title, xlabel, ylabel, figsize=(14, 7)):
"""优化后的折线图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
# 获取颜色循环
colors = sns.color_palette("husl", len(data_dict))
for i, (name, series) in enumerate(data_dict.items()):
plt.plot(series.index, series.values,
marker='o', markersize=8,
linewidth=2.5,
color=colors[i],
label=name,
zorder=3)
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
# 优化图例
plt.legend(title='员工',
bbox_to_anchor=(1.02, 1),
loc='upper left',
frameon=True,
framealpha=0.9,
edgecolor='white')
# 添加网格
plt.grid(True, linestyle='--', alpha=0.6, zorder=1)
# 优化坐标轴
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
def plot_heatmap(pivot_table, title, xlabel, ylabel, figsize=(14, 8)):
"""优化后的热力图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
# 创建自定义颜色映射
cmap = sns.diverging_palette(220, 20, as_cmap=True)
ax = sns.heatmap(pivot_table,
annot=True,
fmt='.1f',
cmap=cmap,
linewidths=0.5,
linecolor='white',
cbar_kws={
'label': '工作时长(小时)',
'shrink': 0.8,
'format': '%.1f'
},
annot_kws={"size": 10, "color": "black"})
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
# 优化坐标轴标签
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)
# 调整颜色条位置
cbar = ax.collections[0].colorbar
cbar.ax.yaxis.label.set_size(12)
plt.tight_layout()
plt.show()
def plot_stacked_bar(data, title, xlabel, ylabel, figsize=(14, 7)):
"""优化后的堆叠条形图绘制函数"""
plt.figure(figsize=figsize, dpi=100)
ax = data.plot(kind='bar', stacked=True,
edgecolor='white', linewidth=0.7,
zorder=2)
plt.title(title, pad=20, fontweight='bold')
plt.xlabel(xlabel, labelpad=10)
plt.ylabel(ylabel, labelpad=10)
plt.xticks(rotation=45, ha='right')
# 优化图例
plt.legend(title='周/月',
bbox_to_anchor=(1.02, 1),
loc='upper left',
frameon=True,
framealpha=0.9)
# 添加网格
plt.grid(axis='y', linestyle='--', alpha=0.7, zorder=1)
# 优化坐标轴
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.tight_layout()
plt.show()
# 主程序逻辑
if __name__ == '__main__':
# 加载并处理数据
df = load_and_preprocess_data("employee_attendance.xlsx")
print(df.head())
# 1. 每个员工的平均工作时长(优化条形图)
avg_work = df.groupby('Name')['Work Duration'].mean().sort_values(ascending=False)
plot_bar(avg_work,
'员工平均工作时长排名',
'员工姓名',
'平均工作时长(小时)',
color=sns.color_palette("viridis", len(avg_work)),
add_values=True)
# 2. 每个员工的总工作时长(优化条形图)
total_work = df.groupby('Name')['Work Duration'].sum().sort_values(ascending=False)
plot_bar(total_work,
'员工总工作时长排名',
'员工姓名',
'总工作时长(小时)',
color=sns.color_palette("plasma", len(total_work)),
add_values=True)
# 3. 每个员工每周的工作时长(优化堆叠条形图)
weekly_work = df.groupby(['Name', 'Week'])['Work Duration'].sum().unstack(fill_value=0)
plot_stacked_bar(weekly_work,
'员工每周工作时长分布',
'员工姓名',
'总工作时长(小时)')
# 4. 每个员工每月的工作时长(优化堆叠条形图)
monthly_work = df.groupby(['Name', 'Month'])['Work Duration'].sum().unstack(fill_value=0)
plot_stacked_bar(monthly_work,
'员工每月工作时长分布',
'员工姓名',
'总工作时长(小时)')
# 5. 每个员工每月工作趋势折线图(优化折线图)
monthly_trends = {name: group.groupby('Month')['Work Duration'].sum()
for name, group in df.groupby('Name')}
plot_line(monthly_trends,
'员工每月工作时长趋势分析',
'月份',
'总工作时长(小时)')
# 6. 热力图:每周工作分布(优化热力图)
pivot_weekly = df.pivot_table(index='Name', columns='Week',
values='Work Duration', aggfunc='sum', fill_value=0)
plot_heatmap(pivot_weekly,
'员工每周工作时长热力图',
'周次',
'员工姓名')
# 7. 热力图:每月工作分布(优化热力图)
pivot_monthly = df.pivot_table(index='Name', columns='Month',
values='Work Duration', aggfunc='sum', fill_value=0)
plot_heatmap(pivot_monthly,
'员工每月工作时长热力图',
'月份',
'员工姓名')
# 新增:工作日分布分析(饼图)
weekday_counts = df['Weekday'].value_counts()
plt.figure(figsize=(10, 8), dpi=100)
colors = sns.color_palette("pastel")[0:7]
wedges, texts, autotexts = plt.pie(weekday_counts,
autopct='%1.1f%%',
startangle=90,
colors=colors,
wedgeprops={'linewidth': 1, 'edgecolor': 'white'},
textprops={'fontsize': 12})
plt.title('工作日分布比例', pad=20, fontweight='bold', fontsize=16)
plt.legend(wedges, weekday_counts.index,
title="星期",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
# 美化百分比标签
for autotext in autotexts:
autotext.set_color('white')
autotext.set_fontweight('bold')
plt.tight_layout()
plt.show()