您的位置:首页 >聚焦 >

全球快资讯:《如何打一场数据挖掘赛事》进阶版

2022-07-26 07:48:26    来源:程序员客栈
Datawhale干货贡献者:牧小熊、Datawhale幕后贡献者

经过上一篇的入门学习,大家已经熟悉如何去打一场比赛,并能训练经典的机器学习算法模型,去解决实际的问题。如果你还不了解,可以先学习《如何打一个数据挖掘比赛》入门版,然后再进行本节的学习。

这个比赛是一个医疗领域的数据挖掘实践,赛事的任务是构建一种模型,该模型能够根据患者的测试数据来预测这个患者是否患有糖尿病。这种类型的任务是典型的二分类问题(患有糖尿病 / 不患有糖尿病)。本文将以任务学习和启发性思考的方式,帮助大家深入学习。

获取进阶版PDF教程,公众号后台回复:进阶


(相关资料图)

赛事背景:

本次比赛是一个医疗领域数据挖掘赛,需要选手通过训练集数据构建模型,对验证集数据进行预测,并将预测的结果提交到科大讯飞数据竞赛平台中,得到排名反馈。

报名地址:https://challenge.xfyun.cn/topic/info?type=diabetes&ch=ds22-dw-gzh02

教程说明:

本教程共有6个任务,任务难度逐渐增加。每个任务中分为不同的模块,具体要求如下:

主线任务需要学习者独立完成支线任务为学有余力的同学独立完成思考为学习者提供了可以思考的方向,可通过讨论或搜索获得结果
任务详情及难度
任务1:比赛报名与环境配置主线任务:访问糖尿病遗传风险检测挑战赛网页,并注册相关账号点击页面中赛事概要,了解比赛的赛事背景、赛事任务、提交说明、评估指标等相关信息安装并配置好python的编程环境思考:为什么要了解比赛的相关信息?比赛的评估指标有哪几种?本次比赛中为什么使用F1-score,相比其他评估指标有什么优势?任务2:数据的读取与数据类型主线任务:解压比赛数据,使用pandas读取比赛数据,并查看训练集和测试集数据大小查看训练集和测试集的数据类型思考:为什么要查看训练集和测试集的大小?为什么查看训练集和测试集的数据类型?参考代码:

importpandasaspdtrain_df=pd.read_csv("比赛训练集.csv",encoding="gbk")test_df=pd.read_csv("比赛测试集.csv",encoding="gbk")print("训练集的数据大小:",train_df.shape)print("测试集的数据大小:",test_df.shape)print("-"*30)print("训练集的数据类型:")print(train_df.dtypes)print("-"*30)print(test_df.dtypes)

任务3:数据的分析与探索主线任务:查看训练集和测试集的缺失值,并比训练集和测试集的缺失值分布是否一致使用.corr()函数查看数据间的相关性对训练集和测试集数据进行可视化统计思考:数据中的缺失值产生的原因?怎么查看数据间的相关性?如果相关性高说明了什么?参考代码:

#----------------查数据的缺失值----------------print(train_df.isnull().sum())print("-"*30)print(test_df.isnull().sum())#可以看到训练集和测试集中都是舒张压有缺失值#----------------查数据相关性----------------print("-"*30)print("查看训练集中数据的相关性")print(train_df.corr())print(test_df.corr())#----------------数据的可视化统计----------------importmatplotlib.pyplotaspltimportseabornassnstrain_df["性别"].value_counts().plot(kind="barh")sns.set(font="SimHei",font_scale=1.1)#解决Seaborn中文显示问题并调整字体大小sns.countplot(x="患有糖尿病标识",hue="性别",data=train_df)sns.boxplot(y="出生年份",x="患有糖尿病标识",hue="性别",data=train_df)sns.violinplot(y="体重指数",x="患有糖尿病标识",hue="性别",data=train_df)plt.figure(figsize=[20,10],dpi=100)sns.countplot(x="出生年份",data=train_df)plt.tight_layout()

任务4:数据的特征工程主线任务:将数据中的糖尿病家族史中的文本数据进行编码将数据中的舒张压的缺失值进行填充将出生年份的数据转换成年龄数据并进行分组对体重和舒张压的数据进行分组删除数据中的编号这一列支线任务:计算每个个体口服耐糖量测试、胰岛素释放实验、舒张压这三个指标对糖尿病家族史进行分组求平均值后的差值计算每个个体口服耐糖量测试、胰岛素释放实验、舒张压这三个指标对年龄进行分组求平均值后的差值思考:文本数据为什么要进行编码?有没有其他的处理方法?除了编码为连续数字,有没有其他形式?为什么要填充缺失值?你觉得参考代码中将所有的缺失值全部填充为0是否正确?为什么要将出生年份转换成年龄?为什么要对年龄分组?为什么对体重和舒张压进行了分组?这么做是否正确?为什么要删除编号这一列?参考代码:

#这里将文本数据转成数字数据dict_糖尿病家族史={"无记录":0,"叔叔或姑姑有一方患有糖尿病":1,"叔叔或者姑姑有一方患有糖尿病":1,"父母有一方患有糖尿病":2}train_df["糖尿病家族史"]=train_df["糖尿病家族史"].map(dict_糖尿病家族史)test_df["糖尿病家族史"]=test_df["糖尿病家族史"].map(dict_糖尿病家族史)#考虑到舒张压是一个较为重要的生理特征,并不能适用于填充平均值,这里采用填充为0的方法train_df["舒张压"].fillna(0,inplace=True)test_df["舒张压"].fillna(0,inplace=True)#将数据中的出生年份换算成年龄train_df["出生年份"]=2022-train_df["出生年份"]test_df["出生年份"]=2022-test_df["出生年份"]#将年龄进行一个分类""">50<=1819-3031-50"""defresetAge(input):ifinput<=18:return0elif19<=input<=30:return1elif31<=input<=50:return2elifinput>=51:return3train_df["rAge"]=train_df["出生年份"].apply(resetAge)test_df["rAge"]=test_df["出生年份"].apply(resetAge)#将体重指数进行一个分类"""人体的成人体重指数正常值是在18.5-24之间低于18.5是体重指数过轻在24-27之间是体重超重27以上考虑是肥胖高于32了就是非常的肥胖。"""defBMI(a):ifa<18.5:return0elif18.5<=a<=24:return1elif24

任务5:模型的构建与优化主线任务:构建用于模型训练的训练集、训练标签以及测试集从以下4个不同模型中选择1个完成模型构建,并提交分数思考:能够用于二分类的机器学习算法有哪些?在逻辑回归代码中,为什么要进行数据标准化?本次比赛中逻辑回归算法有较差的分数可能有哪些原因?参考代码:

train_label=train_df["患有糖尿病标识"]train=train_df.drop(["患有糖尿病标识"],axis=1)test=test_df---逻辑回归(分数:0.74):fromsklearn.linear_modelimportLogisticRegressionfromsklearn.preprocessingimportMinMaxScalerfromsklearn.pipelineimportmake_pipeline#构建模型model=make_pipeline(MinMaxScaler(),LogisticRegression())model.fit(train,train_label)pre_y=model.predict(test)result=pd.read_csv("提交示例.csv")result["label"]=pre_yresult.to_csv("LR.csv",index=False)决策树(分数:0.93):fromsklearn.treeimportDecisionTreeClassifier#构建模型model=DecisionTreeClassifier()model.fit(train,train_label)pre_y=model.predict(test)result=pd.read_csv("提交示例.csv")result["label"]=pre_yresult.to_csv("CART.csv",index=False)lightgbm版本(分数:0.95):importlightgbmdefselect_by_lgb(train_data,train_label,test_data,random_state=2022,metric="auc",num_round=300):clf=lightgbmtrain_matrix=clf.Dataset(train_data,label=train_label)params={"boosting_type":"gbdt","objective":"binary","learning_rate":0.1,"metric":metric,"seed":2020,"nthread":-1}model=clf.train(params,train_matrix,num_round)pre_y=model.predict(test_data)returnpre_y#输出预测值test_data=select_by_lgb(train,train_label,test)pre_y=pd.DataFrame(test_data)pre_y["label"]=pre_y[0].apply(lambdax:1ifx>0.5else0)result=pd.read_csv("提交示例.csv")result["label"]=pre_y["label"]result.to_csv("lgb.csv",index=False)lightgbm版本5折交叉验证(分数:0.96):importlightgbmfromsklearn.model_selectionimportKFolddefselect_by_lgb(train_data,train_label,test_data,random_state=2022,n_splits=5,metric="auc",num_round=10000,early_stopping_rounds=100):kfold=KFold(n_splits=n_splits,shuffle=True,random_state=random_state)fold=0result=[]fortrain_idx,val_idxinkfold.split(train_data):random_state+=1train_x=train_data.loc[train_idx]train_y=train_label.loc[train_idx]test_x=train_data.loc[val_idx]test_y=train_label.loc[val_idx]clf=lightgbmtrain_matrix=clf.Dataset(train_x,label=train_y)test_matrix=clf.Dataset(test_x,label=test_y)params={"boosting_type":"gbdt","objective":"binary","learning_rate":0.1,"metric":metric,"seed":2020,"nthread":-1}model=clf.train(params,train_matrix,num_round,valid_sets=test_matrix,early_stopping_rounds=early_stopping_rounds)pre_y=model.predict(test_data)result.append(pre_y)fold+=1returnresulttest_data=select_by_lgb(train,train_label,test)pre_y=pd.DataFrame(test_data).Tpre_y["averge"]=pre_y[[iforiinrange(5)]].mean(axis=1)pre_y["label"]=pre_y["averge"].apply(lambdax:1ifx>0.5else0)result=pd.read_csv("提交示例.csv")result["label"]=pre_y["label"]result.to_csv("lgb.csv",index=False)

任务6:模型构建的进阶:主线任务:使用不同模型来评估预测准确性对3个预测准确度最高的模型参数的搜索,并比较不同模型的预测准确性思考:模型融合的优点在哪里?运行主线任务1,思考这些算法为什么要较高的准确度?为什么可以通过搜索来调整模型的参数?模型参数的调整一定会让预测更准确嘛?你觉得参考代码中搜索的参数设置合理嘛?如果不合理应该如何改进?参考代码:

fromsklearn.model_selectionimportcross_val_scorefromsklearn.model_selectionimporttrain_test_splitfromsklearn.ensembleimportRandomForestClassifier,GradientBoostingClassifierfromsklearn.treeimportDecisionTreeClassifierfromsklearn.neighborsimportKNeighborsClassifierfromsklearnimportsvmfromsklearn.linear_modelimportLogisticRegressiontrain_label=train_df["患有糖尿病标识"]train=train_df.drop(["患有糖尿病标识"],axis=1)test=test_df#分割训练集和验证集train_x,val_x,train_y,val_y=train_test_split(train,train_label,test_size=0.25,random_state=2020)model={}model["rfc"]=RandomForestClassifier()model["gdbt"]=GradientBoostingClassifier()model["cart"]=DecisionTreeClassifier()model["knn"]=KNeighborsClassifier()model["svm"]=svm.SVC()model["lr"]=LogisticRegression()foriinmodel:model[i].fit(train_x,train_y)score=cross_val_score(model[i],val_x,val_y,cv=5,scoring="f1")print("%s的f1为:%.3f"%(i,score.mean()))"""rfc的f1为:0.927gdbt的f1为:0.925cart的f1为:0.899knn的f1为:0.811svm的f1为:0.751lr的f1为:0.718"""---fromsklearn.model_selectionimportGridSearchCVmodel=["rfc","gbdt","cart"]temp=[]rfc=RandomForestClassifier(random_state=0)params={"n_estimators":[50,100,150,200,250],"max_depth":[1,3,5,7,9,11,13,15,17,19],"min_samples_leaf":[2,4,6]}temp.append([rfc,params])gbt=GradientBoostingClassifier(random_state=0)params={"learning_rate":[0.01,0.05,0.1,0.15,0.2],"n_estimators":[100,300,500],"max_depth":[3,5,7]}temp.append([gbt,params])cart=DecisionTreeClassifier(random_state=0)params={"max_depth":[1,3,5,7,9,11,13,15,17,19],"min_samples_leaf":[2,4,6]}temp.append([cart,params])foriinrange(len(model)):best_model=GridSearchCV(temp[i][0],param_grid=temp[i][1],refit=True,cv=5).fit(train,train_label)print(model[i],":")print("bestparameters:",best_model.best_params_)"""rfc:bestparameters:{"max_depth":17,"min_samples_leaf":2,"n_estimators":100}gbdt:bestparameters:{"learning_rate":0.01,"max_depth":7,"n_estimators":300}cart:bestparameters:{"max_depth":7,"min_samples_leaf":2}"""model={}model["rfc"]=RandomForestClassifier(max_depth=17,min_samples_leaf=2,n_estimators=100)model["gdbt"]=GradientBoostingClassifier(learning_rate=0.01,max_depth=7,n_estimators=300)model["cart"]=DecisionTreeClassifier(max_depth=7,min_samples_leaf=2)foriinmodel:model[i].fit(train_x,train_y)score=cross_val_score(model[i],val_x,val_y,cv=5,scoring="f1")print("%s的f1为:%.3f"%(i,score.mean()))"""rfc的f1为:0.931gdbt的f1为:0.922cart的f1为:0.920"""---rfc版本(分数:0.965):model=RandomForestClassifier(max_depth=17,min_samples_leaf=2,n_estimators=100)model.fit(train,train_label)pre_y=model.predict(test)result=pd.read_csv("提交示例.csv")result["label"]=pre_yresult.to_csv("rfc.csv",index=False)

作者寄语

行文至此,数据挖掘比赛项目就告一段落了,经过这2次教程的学习,你应该体验到了数据挖掘比赛从报名到模型构建到优化的全过程,这将是你打开数据科学/算法工程/数据分析的第一步。正所谓“路漫漫其修远兮,吾将上下而求索”,这一步终究只是开始,在距离你的成为AI大师还有漫长的路要探索,但这也是一个美好的开始。正所谓“千里之行,始于足下”,相信这个简短的数据挖掘比赛教程将打开你数据挖掘的大门,若干年后,你将还会记得当初那个跟着教程不断尝试的自己。也期待成长后你加入幕后的贡献者团队,我们将一起坚持初心,帮助更多学习者成长。

整理不易,点赞三连↓

关键词: 数据挖掘 主线任务 数据类型

相关阅读