博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【深度之眼】kesci二分类算法大赛之初体验
阅读量:4100 次
发布时间:2019-05-25

本文共 6807 字,大约阅读时间需要 22 分钟。

 

 

0. 写在前面

  作为一个重度社恐的老萌新,决定单枪匹马的来参加这个练习赛,也是我参加的第一个此类比赛。

本次练习赛虽然最终成绩真的很普通,欢迎提提高意见,非常感谢。

不过收获真的很多,尝试了很多没接触过的东西。

希望有同学看到这段话,带我打打更大比赛!我可以

1.问题描述

数据选自UCI机器学习库中的「银行营销数据集(Bank Marketing Data Set)」

这些数据与葡萄牙银行机构的营销活动相关。这些营销活动以电话为基础,一般,银行的客服人员需要联系客户至少一次,以此确认客户是否将认购该银行的产品(定期存款)。

因此,与该数据集对应的任务是「分类任务」,「分类目标」是预测客户是(' 1 ')或者否(' 0 ')购买该银行的产品。

2.字段描述

字段说明

NO 字段名称 数据类型 字段描述
1 ID Int 客户唯一标识
2 age Int 客户年龄
3 job String 客户的职业
4 marital String 婚姻状况
5 education String 受教育水平
6 default String 是否有违约记录
7 balance Int 每年账户的平均余额
8 housing String 是否有住房贷款
9 loan String 是否有个人贷款
10 contact String 与客户联系的沟通方式
11 day Int 最后一次联系的时间(几号)
12 month String 最后一次联系的时间(月份)
13 duration Int 最后一次联系的交流时长
14 campaign Int 在本次活动中,与该客户交流过的次数
15 pdays Int 距离上次活动最后一次联系该客户,过去了多久(999表示没有联系过)
16 previous Int 在本次活动之前,与该客户交流过的次数
17 poutcome String 上一次活动的结果
18 y Int 预测客户是否会订购定期存款业务

 

3.数据预处理

这部分内容比较冗长,虽然不是重点但仔细了解指标,有助于下一节的特征工程,对结果有很大帮助。

 

3.1数据概览

import numpy as npimport pandas as pd#导入数据集def load_data():    home_path = r"..." #输入数据所在位置    train_path = os.path.join(home_path, "train_set.csv")    test_path = os.path.join(home_path, "test_set.csv")    train_data = pd.read_csv(train_path)    test_data = pd.read_csv(test_path)    return train_data, test_datatrainData, testData = load_data()print('train Data:{}   testData:{}'.format(trainData.shape, testData.shape))print(trainData.describe())

    训练集(25317, 18),测试集(10852, 17)        

  age balance day duration campaign   pdays previous y
count 25317.000000 25317 25317 25317 25317 25317 25317 25317
mean 40.93538 1357.555 15.835289 257.7324 2.77205 40.24877 0.591737 0.116957
std 10.63429 2999.823 8.31948 256.9752 3.136097 100.2135 2.568313 0.321375
min 18 -8019 1 0 1 -1 0 0
25% 33 73 8 103 1 -1 0 0
50% 39 448 16 181 2 -1 0 0
75% 48 1435 21 317 3 -1 0 0
max 95 102127 31 3881 55 854 275 1

3.2缺失值处理

#缺失#训练集trainData.isnull().sum()#测试集testData.isnull().sum()

结果表示 训练集与测试集均无缺失值

 

3.3 特征分布

目标分布:

import matplotlib.pyplot as pltimport seaborn as sns#目标分布plt.subplots(figsize=[6,6])trainData['y'].value_counts().plot(kind='pie',autopct='%.1f%%')

88.3%的用户未办理业务,11.7%的用户办理了业务

下面来看看单指标对于目标y的分布情况

#单指标分布#首先看分类变量#jobf, ax = plt.subplots(1, 2, figsize=(10, 5))trainData[['y', 'job']].groupby(['job']).mean().plot(kind='bar', ax=ax[0])sns.countplot('job',hue='y',data=trainData,ax=ax[1])ax[0].set_title('Rate vs job')ax[1].set_title('number vs job')#其他分类变量套用即可

从以上的柱状图可以看出这些指标与能否成功办理业务的关系:

 如无个人/住房贷款,无违约,显然更易成功订购定期存款业务

#再看连续变量sns.FacetGrid(trainData, hue='y', aspect=2, size=5).map(sns.kdeplot, 'age', shade=True).add_legend()

可见,大约25岁以下客户办理成功率更高,这与前面职业为学生/婚姻状况为单身的成功率更高结论的一致

貌似月初月末有一点影响。看不出什么,日这个指标需与月结合起来形成日期一起看,单看日指标没有很大意义。而月之间有存在的明显的差异,且后面有pdays这个指标表示距离上次活动最后一次联系该客户,过去了多久,因此这个指标可能意义不大。

显然交流时长与y之间的关联性较强。

说明联系紧密的成功办理的可能性更高。

4 特征工程

     尽量使用原特征,对二分类变量做序号编码,多分类变量做独热编码,连续变量尽量归一化,这里没有归一化。

from sklearn.model_selection import train_test_split#将测试集和训练集合并full = trainData.append(testData, ignore_index=True, sort=False)full.tail()#哑原处理data_columns=list(full.columns)categoricalCol=['ID','job','marital','education','default','housing','loan','contact','month'                ,'poutcome']#分类变量名continuousCol=list(set(data_columns).difference(categoricalCol))  #连续变量continuousColcontinuousCol.pop(5)#删去y
#对分类变量分别进行序号编码和独热编码default = pd.Series(np.where(full['default']=='yes', 1, 0), name='default')housing = pd.Series(np.where(full['housing']=='yes', 1, 0), name='housing')loan = pd.Series(np.where(full['loan']=='yes', 1, 0), name='loan')job= pd.get_dummies(full['job'],prefix='job')marital= pd.get_dummies(full['marital'],prefix='marital')education= pd.get_dummies(full['education'],prefix='education')contact= pd.get_dummies(full['contact'],prefix='contact')month= pd.get_dummies(full['month'],prefix='month')poutcome= pd.get_dummies(full['poutcome'],prefix='poutcome')#拼回来full1 = pd.concat([job,marital,education,default,contact,housing,loan,month                ,poutcome], axis=1)full2=full[continuousCol].applymap(float) ##连续变量的值变为float格式FULL=full1.join(full2)FULL=FULL.join(full['y'])train_set = FULL[0:25317]test_set = FULL[25317:]test_set = test_set.drop('y',axis=1)#划分训练集和验证集feature = train_set.drop('y',axis=1)label = train_set['y']X_train,X_test,y_train,y_test=train_test_split(feature,label,test_size=0.25,random_state=0)

5.建立模型

在这里我尝试了各种模型,包括knn、逻辑回归、svm等等结果都很不好,然后开始尝试集成学习。

这里主要介绍我尝试gbdt时的过程

 由于评分标准是auc,首先定义一个模型评估的函数

from sklearn.metrics import accuracy_score, roc_auc_score,roc_curve,auc# 性能评估def model_metrics(clf, X_train, X_test, y_train, y_test):    # 预测训练集和测试集    y_train_pred = clf.predict(X_train)    y_test_pred = clf.predict(X_test)        y_train_proba = clf.predict_proba(X_train)[:,1]    y_test_proba = clf.predict_proba(X_test)[:,1]       # AUC取值    print('[auc值]', end = ' ')    print('训练集:', '%.4f'%roc_auc_score(y_train, y_train_proba), end = ' ')    print('测试集:', '%.4f'%roc_auc_score(y_test, y_test_proba))        # ROC曲线    fpr_train, tpr_train, thresholds_train = roc_curve(y_train, y_train_proba, pos_label = 1)    fpr_test, tpr_test, thresholds_test = roc_curve(y_test, y_test_proba, pos_label = 1)        label = ["Train - AUC:{:.4f}".format(auc(fpr_train, tpr_train)),              "Test - AUC:{:.4f}".format(auc(fpr_test, tpr_test))]    plt.plot(fpr_train,tpr_train)    plt.plot(fpr_test,tpr_test)    plt.plot([0, 1], [0, 1], 'd--')    plt.xlabel('False Positive Rate')    plt.ylabel('True Positive Rate')    plt.legend(label, loc = 4)    plt.title("ROC curve")
clf=ensemble.GradientBoostingClassifier()clf.fit(X_train,y_train)model_metrics(clf, X_train, X_test, y_train, y_test)

先是直接用gbdt的默认参数,auc等于

0.9249611515690814

然后进行调参

#大概是这样,前面发现learning_rate=0.29,n_estimators=96时得分最高X_train,X_test,y_train,y_test=train_test_split(feature,label,test_size=0.25,random_state=0)model = ensemble.GradientBoostingClassifier(learning_rate=0.29,n_estimators=96) #maxdepths=np.arange(1,20).tolist()param_grid= {'max_depth':list(range(3,14,2)), 'min_samples_split':list(range(100,801,200))}kflod = StratifiedKFold(n_splits=10, shuffle = True,random_state=7)grid_search = GridSearchCV(model,param_grid,scoring = 'roc_auc',n_jobs = -1,cv = kflod)grid_result = grid_search.fit(X_train, y_train) #运行网格搜索print("Best: %f using %s" % (grid_result.best_score_,grid_search.best_params_))#grid_scores_:给出不同参数情况下的评价结果。best_params_:描述了已取得最佳结果的参数的组合#best_score_:成员提供优化过程期间观察到的最好的评分#具有键作为列标题和值作为列的dict,可以导入到DataFrame中。#注意,“params”键用于存储所有参数候选项的参数设置列表。means = grid_result.cv_results_['mean_test_score']params = grid_result.cv_results_['params']for mean,param in zip(means,params):    print("%f  with:   %r" % (mean,param))

尝试了很多次之后 将参数定为  learning_rate=0.29,n_estimators=96,max_depth=5,min_samples_split=700

此时

auc提高到了0.9326.

6.后记

      我也尝试其他的集成算法,lgb的得分最高,可是参数调整了半天好像默认参数最高。

后来又尝试了一下用StandardScaler融合模型,结果成绩几乎没有提升,模型选的不好甚至还下降了。

但是发现直接取不同算法结果的算数平均值 有效果。

       我还尝试了构建了新的特征,比如有个人贷款或有房贷的令为有贷款,也通过特征重要度删去一些非常不重要的变量,但是效果甚微。

 

另外本文中代码有多处借鉴并调整,感谢各位前人的分享。

转载地址:http://kerii.baihongyu.com/

你可能感兴趣的文章
Android中的Binder(二)
查看>>
Framework之View的工作原理(一)
查看>>
Web应用架构
查看>>
设计模式之策略模式
查看>>
深究Java中的RMI底层原理
查看>>
用idea创建一个maven web项目
查看>>
Kafka
查看>>
9.1 为我们的角色划分权限
查看>>
维吉尼亚之加解密及破解
查看>>
DES加解密
查看>>
TCP/IP协议三次握手与四次握手流程解析
查看>>
PHP 扩展开发 : 编写一个hello world !
查看>>
inet_ntoa、 inet_aton、inet_addr
查看>>
用模板写单链表
查看>>
用模板写单链表
查看>>
链表各类操作详解
查看>>
C++实现 简单 单链表
查看>>
数据结构之单链表——C++模板类实现
查看>>
Linux的SOCKET编程 简单演示
查看>>
正则匹配函数
查看>>