机器学习相关操作分享(一)

# 目录
[1 数据简介及数据读取](#1)<br>
[2 数据清洗](#2)<br>
[3 探索性数据分析](#3)<br>
&emsp;&emsp;[3.1 各部门团队的组成情况](#3.1)<br>
&emsp;&emsp;[3.2 员工生产率分布情况](#3.2)<br>
&emsp;&emsp;[3.3. 数据相关性分析](#3.3)<br>
[4 特征工程](#4)<br>
[5 预测员工生产率](#4)<br>
&emsp;&emsp;[5.1 训练集测试集划分](#5.1)<br>
&emsp;&emsp;[5.2 线性回归](#5.2)<br>
&emsp;&emsp;[5.3 回归决策树](#5.3)<br>
&emsp;&emsp;[5.4 Bagging回归](#5.4)<br>
[6 总结](#6)<br>
    
<div id="1"></div>

# 1 数据简介及数据读取
服装厂员工生产率数据集共包含1197行、15列,其中`actual_productivity`一列为我们最终需要进行预测的员工实际生产率,各字段类型和含义如下表所示:
| 列名 | 类型 | 含义说明 |
|------:|------:|------:|
|**date**|字符型|日期 MM-DD-YYYY|
|**quarter**|字符型|每月第几周|
|**department**|字符型|部门|
|**day**|字符型|星期|
|**team**|整型|团队编号|
|**targeted_productivity**|浮点型|目标生产率|
|**smv**|浮点型|标准分钟值,任务分配的时间|
|**wip**|浮点型|在制品,包括产品未完成项的数量|
|**over_time**|整型|代表每个团队的超时时间,以分钟为单位|
|**incentive**|整型|激励特定行动的奖金|
|**idle_time**|浮点型|由于多种原因导致生产中断的时间|
|**idle_men**|整型|因生产中断而闲置的工人数|
|**no_of_style_change**|整型|特定产品风格的变化次数|
|**no_of_workers**|浮点型|每个团队的工人数量|
|**actual_productivity**|浮点型|工人交付的实际生产率百分比,取值范围是0-1|
首先,我们使用Pandas库读取数据,并查看数据的基本信息。
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
# plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
# plt.rcParams['font.family'] = ['sans-serif']
import warnings

# 不显示警告
warnings.filterwarnings('ignore')

# 读取数据,查看数据前五行
garments = pd.read_csv('./input/garments_worker_productivity.csv')
garments.loc[garments.department=='finishing ', 'department'] = 'finishing'
garments.head()
cols = [f for f in garments.columns if f not in ['date','quarter','department','day']]
garments[cols].corr()
garments.info()
数据集共包含1197行、15列,其中`date`、`quarter`、`department`和`day`字段数据类型为object,其余为数字类型。同时可以发现,`wip`一列存在缺失值。下面我们查看一下数据的基本统计信息:
garments['quarter'].value_counts()
garments.describe(include='all')
从结果中可以看出`actual_productivity`实际生产率的最大值为1.120437,而该字段实际取值范围为0-1,后续我们会对其进行处理。
<div id="2"></div>

# 2 数据清洗
在上一部分我们发现`wip`一列存在缺失值,在处理之前我们先计算一下缺失值的比例:
# 查看wip缺失值比例
round(garments.wip.isnull().sum()/len(garments.wip),2)
`wip`中有42%的缺失值,由于占比较大,这里我们直接删去该字段。
# 删去wip这一列
garments.drop(columns=['wip'], inplace=True)
接下来使用`pd.to_datetime()`函数将`date`一列数据类型改为日期类型,并将其设置为索引:
# 将日期转换为时间类型,设置为索引
garments.date = pd.to_datetime(garments.date)

garments.set_index(['date'],inplace=True)

# 查看日期范围
garments.index
可以看到数据是从2015年1月1日到2015年3月11日期间收集的。我们根据日期在数据集中添加月份`month`一列:
# 添加月份
garments['month'] = garments.index.month_name().values
garments.head()
从数据中发现,`over_time`每个团队的超时时间字段数值较大,这是由于该字段以分钟为单位,为了便于观察我们将单位转化为小时。
# 将超时时间over_time改为以小时为单位
garments['over_time'] = garments['over_time']/60
garments.head()
数据中`team`团队编号一列为数值型,而实际分析中应将其视为离散型变量,这里使用`astype`方法将其转为`object`。
# 将团队编号team类型改为object
garments['team'] = garments['team'].astype('object')
现在,我们开始分析数据中是否存在异常值,通过观察发现,`department`部门字段中的唯一值存在异常:
# 查看部门字段的唯一取值
garments['department'].value_counts()
garments['department'].unique()
garments.groupby(['department'])[['targeted_productivity','actual_productivity']].agg({'mean','max','min'})
该字段的取值出现拼写错误及空格问题,我们将该列的取值进行统一:`sewing`为缝纫部门,`finishing`为精加工车间。
# # 修改为finishing和sewing
# garments['department'] = garments.department.apply(lambda x: 'finishing' if 'finishing' in x else 'sewing')
# garments['department'].value_counts()
数据中缝纫部有691条记录,精加工车间有506条记录。
最后,我们将`actual_productivity`实际生产率大于1的值统一为1。
# 将生产率大于1的设置为1
garments.actual_productivity = garments.actual_productivity.apply(lambda x: 1 if x>1 else x)

<div id="3"></div>

# 3 探索性数据分析
在这一部分,我们将结合可视化分析方法对数据进行初步的了解,首先查看各部门团队的组成情况,及记录数量的比例。
<div id="3.1"></div>

## 3.1 各部门团队的组成情况
# 分组聚合统计各部门各个团队的记录数量
team = garments.groupby(['department','team'])['team'].count()
team
garments.groupby(['department','team'])[['targeted_productivity','actual_productivity']].agg({'mean','max','min'})
team_c = round(garments.groupby(['department','team'])['no_of_workers'].mean())
team_c
## 3.2 员工生产率分布情况
在分析完各部门团队组成之后,我们将一起来观察各部门生产率的分布情况。
# 设置颜色
my_colors = ["#F1B5B9", "#AAC8D1"]
sns.set_palette( my_colors )

fig, ax =plt.subplots(figsize=(8,4))

dpt_g = garments.groupby('department')['actual_productivity']

sns.distplot(dpt_g.get_group('finishing'),label='精加工车间')
sns.distplot(dpt_g.get_group('sweing'), label='缝纫部')

plt.title('各部门生产率分布情况',size=15)
plt.legend()
plt.xlabel('生产率', size=12)
plt.ylabel('频次', size=12)

plt.show()
两部门生产率整体均集中于0.6至1之间,同时较少员工生产率低于0.5。相比之下,缝纫部员工更多集中在0.8左右,精加工车间较多员工生产率接近于1,但整体分布较为分散。
下面我们通过绘制箱线图,查看两部门各个团队生产率的分散情况。
fig, ax =plt.subplots(figsize=(12,4))

sns.boxplot(x='team',y='actual_productivity',data=garments,hue='department')

plt.title('各团队生产率分散情况',size=15)
plt.xlabel('团队编号', size=12)
plt.ylabel('生产率', size=12)
plt.legend(loc='lower left')

plt.show()
从上图可知,缝纫部各团队生产率均比较集中,但同时存在较多生产率偏低的异常点。精加工车间中团队6和11生产率最分散,团队1-5、10、11和12生产率均较高。
接着我们将探究不同时间对员工生产率的影响。
fig, ax =plt.subplots(3,1,figsize=(8,10))

# 设置颜色
my_colors = ["#F1B5B9", "#AAC8D1"]
sns.set_palette( my_colors )

sns.boxplot(x='day',y='actual_productivity',data=garments,hue='department', order=['Monday','Tuesday','Wednesday','Thursday','Saturday','Sunday'], ax=ax[0])
sns.boxplot(x='quarter',y='actual_productivity',data=garments,hue='department', ax=ax[1])
sns.boxplot(x='month',y='actual_productivity',data=garments,hue='department', ax=ax[2])

ax[0].set_title('不同星期对员工生产率的影响',size=15)
ax[1].set_title('每月各周对员工生产率的影响',size=15)
ax[2].set_title('不同月份对员工生产率的影响',size=15)

ax[0].legend(loc='lower right')
ax[1].legend(loc='lower right')
ax[2].legend(loc='lower right')

#设置默认的间距
plt.tight_layout() 
plt.show()
从上面三幅图可知,不同时间对员工生产率并无明显影响,仅在每月第五周两部门员工生产率略有提升。
<div id="3.3"></div>

## 3.3 数据相关性分析
最后,我们使用数据中的连续型字段绘制相关系数矩阵热力图。
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

# # 正常显示中文标签
# plt.rcParams['font.sans-serif'] = ['SimHei']
# # 正常显示负号
# plt.rcParams['axes.unicode_minus'] = False
# 全局字体的大小设置
plt.rcParams.update({'font.size': 9})

# 计算相关系数
cols = [f for f in garments.columns if f not in ['quarter','department','day','month']]
corr = garments[cols].corr()

fig = plt.figure(figsize=(7,7))

cmap = sns.diverging_palette(220,10,as_cmap=True)
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True

sns.heatmap(corr, annot=True, square=True,linewidths=1.5, cmap=cmap, mask=mask, center=0, cbar_kws={"shrink": .5})

plt.title("特征间的相关性",fontsize=15)

plt.show()
从图中能够发现,`no_of_workers`每个团队的员工人数、`smv`任务分配时间及`over_time`每个团队超时时间之间有明显的正相关关系。此外,`idle_time`生产中断时间和`idle_men`因中断而闲置的工人数也存在较强的正相关性。
<div id="4"></div>

# 4 特征工程
在这一部分,我们将进行特征工程。首先,对`department`进行数值编码,缝纫部`sewing`为1,精加工车间`finishing`为0。
from sklearn.preprocessing import LacbelEncoder

le = LabelEncoder()
garments['department'] = le.fit_transform(garments['department'])

garments.head()
接下来,我们对数据集中的离散型变量进行独热编码。
## 添加特征
tmp_df = garments.groupby(['department','team'])[['actual_productivity','targeted_productivity','smv','incentive','over_time','idle_time','idle_men','no_of_style_change','no_of_workers']].agg({'mean','max','min'})
tmp_df = tmp_df.reset_index()

tmp_df.columns = ['department','team'] + ['_'.join(f) for f in tmp_df.columns if f[0] not in ['department','team']]
tmp_df.head()
garments = garments.merge(tmp_df, on=['department','team'], how='left')
garments = pd.get_dummies(garments)
garments.head()
<div id="5"></div>

# 5 预测员工生产率
<div id="5.1"></div>

## 5.1 训练集测试集划分
在训练模型之前,我们先将训练集测试集按照4:1进行划分,并将特征进行Z-Score标准化处理。
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

X=garments.drop(['actual_productivity'], axis=1)
y=garments['actual_productivity']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)

# 数据标准化
# s = StandardScaler()
# X_train_sm = s.fit_transform(X_train)
# X_test_sm = s.transform(X_test)

X_train_sm = X_train
X_test_sm = X_test
<div id="5.2"></div>

## 5.2 线性回归
首先,在训练集上训练线性回归模型,并在测试集上进行预测和评估,输出决定系数R2和均方误差:
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score,mean_squared_error

mlr = LinearRegression()
mlr.fit(X_train_sm, y_train)
y_pred_sm = mlr.predict(X_test_sm)

print(f'R2 为 {round(r2_score(y_test,y_pred_sm),4)}')
print('均方误差 (MSE): %.4f' % mean_squared_error(y_test, y_pred_sm))

# 可视化
plt.figure(figsize=(6, 4))

plt.scatter(x=y_test,y=y_pred_sm, alpha=.5)

plt.xlabel('实际值')
plt.ylabel('预测值')
plt.title('实际值预测值对比',size=15)

plt.show()
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.metrics import r2_score,mean_squared_error

mlr = Ridge()
mlr.fit(X_train_sm, y_train)
y_pred_sm = mlr.predict(X_test_sm)

print(f'R2 为 {round(r2_score(y_test,y_pred_sm),4)}')
print('均方误差 (MSE): %.4f' % mean_squared_error(y_test, y_pred_sm))

# 可视化
plt.figure(figsize=(6, 4))

plt.scatter(x=y_test,y=y_pred_sm, alpha=.5)

plt.xlabel('实际值')
plt.ylabel('预测值')
plt.title('实际值预测值对比',size=15)

plt.show()
决定系数仅为0.19,模型预测效果较差。
<div id="5.3"></div>

## 5.3 回归决策树
接下来我们尝试构建回归决策树模型,设置树的最大深度为10:
from sklearn.model_selection import KFold
from sklearn.tree import DecisionTreeRegressor

skf = KFold(n_splits=5, shuffle=True, random_state=2021)
for train_index, test_index in skf.split(X,y):
    
    dtreg = DecisionTreeRegressor(max_depth=10,random_state=0)
    
    dtreg.fit(X.loc[train_index], y[train_index])

    y_pred = dtreg.predict(X.loc[test_index])

    print(f'R2 为 {round(r2_score(y[test_index],y_pred),4)}')
    print('均方误差 (MSE): %.4f' % mean_squared_error(y[test_index], y_pred))
# 使用回归决策树
from sklearn.tree import DecisionTreeRegressor
from sklearn import tree

dtreg = DecisionTreeRegressor(max_depth=10,random_state=0)

dtreg.fit(X_train_sm, y_train)

y_pred_sm = dtreg.predict(X_test_sm)

print(f'R2 为 {round(r2_score(y_test,y_pred_sm),4)}')
print('均方误差 (MSE): %.4f' % mean_squared_error(y_test, y_pred_sm))

# 可视化
plt.figure(figsize=(6, 4))

plt.scatter(x=y_test, y=y_pred_sm, alpha=.5)

plt.xlabel('实际值')
plt.ylabel('预测值')
plt.title('实际值预测值对比',size=15)

plt.show()
模型在测试集上决定系数R2为0.43,均方误差 (MSE)为 0.02,预测效果略有提高。
<div id="5.4"></div>

## 5.4 Bagging回归
最后使用`BaggingRegressor`构建模型,我们使用回归决策树作为基模型。
from sklearn.ensemble import BaggingRegressor
from sklearn import tree

br = BaggingRegressor(n_estimators=800, random_state=11)

br.fit(X_train_sm, y_train)

y_pred_sm = br.predict(X_test_sm)

print(f'R2 为 {round(r2_score(y_test,y_pred_sm),4)}')
print('均方误差 (MSE): %.4f' % mean_squared_error(y_test, y_pred_sm))

# 可视化
plt.figure(figsize=(6, 4))

plt.scatter(x=y_test,y=y_pred_sm, alpha=.5)

plt.xlabel('实际值')
plt.ylabel('预测值')
plt.title('实际值预测值对比',size=15)

plt.show()
最终R2提升到了0.5052,均方误差为0.0155。
<div id="6"></div>

## 6 总结
本案例我们使用了服装厂员工生产效率数据集,结合可视化分析方法探索了数据中隐藏的信息,并通过建立线性回归、回归决策树和Bagging回归三种模型预测员工实际生产率。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值