0%

员工离职预测训练赛-DC

比赛介绍

数据集

本数据集来源于DC竞赛平台。数据主要包括影响员工离职的各种因素(工资、出差、工作环境满意度、工作投入度、是否加班、是否升职、工资提升比例等)以及员工是否已经离职的对应记录。

其中训练数据主要包括1100条记录,31个字段,测试数据主要包括350条记录,30个字段,测试数据不包括员工是否已经离职的记录,要求使用逻辑回归等对员工离职进行预测。(注:比赛所用到的数据取自于IBM Watson Analytics分析平台分享的样例数据。该平台只选取了其中的子集,并对数据做了一些预处理使数据更加符合逻辑回归分析比赛的要求。)

评测标准

使用混淆矩阵来评价模型的准确率acc。
acc = (TP+TN)/(TP+FP+FN+TN)

数据分析和预处理

首先观察数据类型train.info()test.info()。可以看到既有int也有object,要对他们进行分别处理。当然,有时候int其实也代表着离散变量,可当作object处理。

1
train.describe()

查看数字型参数。其中,EmployeeNumber列是没有意义的参数,可以删去。同时,可以发现Over18StandardHours中的元素全部相同,也删去。

1
2
3
4
5
6
7
8
train['Over18'].unique() # 输出array(['Y'], dtype=object),只含一种元素,'StandardHours'同理
# 对训练集和测试集一起进行数据处理
test['Attrition']=-1
data = train.append(test).reset_index(drop=True) # data即为训练集+测试集
# 删除没有意义的列
data.drop(['Over18', 'StandardHours','EmployeeNumber'], axis=1, inplace=True)
# 筛选出类别特征
feat_col = [i for i in data.select_dtypes(object).columns if i not in ['Attrition']]

可以看到现在的object列为['BusinessTravel', 'Department', 'EducationField', 'Gender', 'JobRole', 'MaritalStatus', 'OverTime']

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 自定义one-hot
def encode_onehot(df,column_name):
feature_df=pd.get_dummies(df[column_name], prefix=column_name)
all_col = pd.concat([df.drop([column_name], axis=1),feature_df], axis=1)
return all_col
# 对类别特征进行one-hot
for i in cat_col:
data = encode_onehot(data,i)
# 使用LR需要对所有参数进行归一化
max_min_scaler = lambda x : (x-np.min(x))/(np.max(x)-np.min(x))
for i in feats:
data[i]=data[[i]].apply(max_min_scaler)

data.isnull().sum() # 确认数据没有空值

此时再打印data可以看到所有数据都被转化成了[0,1]之间的浮点数。

建模及预测

1
2
3
4
5
6
7
8
9
10
# 重新分割出train和test
X_train = data[data['Attrition'] !=-1][feats]
y_train = data[data['Attrition'] !=-1]['Attrition']
X_test = data[data['Attrition'] ==-1][feats]
# 训练模型
lr_model = LogisticRegression()
lr_model.fit(X_train,y_train)
pre = lr_pre.predict(X_test)
result = pd.DataFrame({'result':pre.astype(int)}) # 比赛要求整型
result.to_csv(path+'output/new_lr',index=False)

逻辑回归单个模型simple版得分0.89428。可以做更进一步的分析处理。

进一步提升

之前也简单写过数据清洗和特征工程对于一个模型的优劣有着重要的影响,下面就来看一下效果。

Solution1:特征提取
1
2
3
4
5
6
7
8
9
# 绘制特征相关性图
corr = data.corr()
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.style.use({'figure.figsize':(10,8)})

sns.heatmap(corr, xticklabels=corr.columns.values, yticklabels=corr.columns.values,cmap="YlGnBu")
plt.show()

heatmap
可以看到MonthlyIncomeJobLevel高度相关,TotalWorkingYears和多个特征都较相关,故尝试删除JobLevelTotalWorkingYears

Solution2:交叉验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from sklearn.model_selection import KFold
model=LogisticRegression()
n_splits=5
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
res['pred'] = 0
model.random_state = 42
for train_idx, val_idx in kfold.split(X_train):
model.random_state = model.random_state + 1
train_x1 = X_train.loc[train_idx]
train_y1 = y_train.loc[train_idx]
test_x1 = X_train.loc[val_idx]
test_y1 = y_train.loc[val_idx]
model.fit(train_x1, train_y1)
result = model.predict(X_test)

结合Solution1和2得分为0.905714(96/2816)。

Solution3:模型融合