栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Coggle 30 Days of ML - 糖尿病遗传风险检测挑战赛

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Coggle 30 Days of ML - 糖尿病遗传风险检测挑战赛

  • 比赛报名
    • 查看训练、测试集的包含字段及字段类型,代码如下:
      import pandas as pd
      
      train_df = pd.read_csv('./糖尿病遗传风险预测挑战赛公开数据/比赛训练集.csv', encoding='gbk')
      test_df = pd.read_csv('./糖尿病遗传风险预测挑战赛公开数据/比赛测试集.csv', encoding='gbk')
      
      print(train_df.shape, test_df.shape)
      print(train_df.dtypes, test_df.dtypes)
  • 比赛数据分析
    • 缺失值统计

      • def do_nan(train_df,test_df,method = None):
            #口服耐糖量测试为-1,也应该为null
            train_df['口服耐糖量测试'] = train_df['口服耐糖量测试'].replace(-1, np.nan)
            test_df['口服耐糖量测试'] = test_df['口服耐糖量测试'].replace(-1, np.nan)
        
            train_df['口服耐糖量测试'] = train_df['口服耐糖量测试'].replace(0, np.nan)
            test_df['口服耐糖量测试'] = test_df['口服耐糖量测试'].replace(0, np.nan)
            if method is not None:
                train_df['胰岛素释放实验'] = train_df['胰岛素释放实验'].replace(0, np.nan)
                test_df['胰岛素释放实验'] = test_df['胰岛素释放实验'].replace(0, np.nan)
        
                train_df['肱三头肌皮褶厚度'] = train_df['肱三头肌皮褶厚度'].replace(0, np.nan)
                test_df['肱三头肌皮褶厚度'] = test_df['肱三头肌皮褶厚度'].replace(0, np.nan)
        
            train_df['体重指数'] = train_df['体重指数'].replace(0, np.nan)
            test_df['体重指数'] = test_df['体重指数'].replace(0, np.nan)
        
            # 训练集缺失值情况
            print(train_df.isnull().mean(0))
            # 训练集缺失值情况
            print(test_df.isnull().mean(0))
        
        
            #将糖尿病家族史转换为类别变量
            dict_糖尿病家族史 = {
                '无记录': 0,
                '叔叔或姑姑有一方患有糖尿病': 1,
                '叔叔或者姑姑有一方患有糖尿病': 1,
                '父母有一方患有糖尿病': 2
            }
            train_df['糖尿病家族史'] = train_df['糖尿病家族史'].map(dict_糖尿病家族史)
            test_df['糖尿病家族史'] = test_df['糖尿病家族史'].map(dict_糖尿病家族史)
        
            #出生年份转换
            train_df['年龄'] = 2022 - train_df['出生年份']
            test_df['年龄'] = 2022 - test_df['出生年份']
        
            #填充缺失值处理
            #下列三个字段比例较低,可以直接填充
            train_df['舒张压'].fillna(89, inplace=True)
            test_df['舒张压'].fillna(89, inplace=True)
        
            train_df['口服耐糖量测试'].fillna(6,inplace = True)
            test_df['口服耐糖量测试'].fillna(6,inplace = True)
        
            train_df['体重指数'].fillna(38,inplace = True)
            test_df['体重指数'].fillna(38,inplace = True)
        
        
            #胰岛素释放实验	肱三头肌皮褶厚度    字段缺失比例较高,试试统计填充(多元线性回归)
            all_df = pd.concat([train_df,test_df])
            all_df.drop(['患有糖尿病标识'],axis=1,inplace=True)
            all_df.dropna(inplace=True)
            if method == 'lg':
                lg_g3 = LinearRegression()
                lg_yd = LinearRegression()
                lg_features = [f for f in all_df.columns if f not in ['编号','肱三头肌皮褶厚度','胰岛素释放实验']]
        
                lg_g3.fit(all_df[lg_features],all_df['肱三头肌皮褶厚度'])
                lg_yd.fit(all_df[lg_features],all_df['胰岛素释放实验'])
        
                for index,bool in enumerate (train_df['胰岛素释放实验'].isnull()):
                    if  bool:
                        train_df.loc[index,'胰岛素释放实验']  = lg_yd.predict(np.array(train_df.loc[index,lg_features]).reshape(1, -1))
                        
                    
                for index,bool in enumerate (train_df['肱三头肌皮褶厚度'].isnull()):
                    if  bool:
                        train_df.loc[index,'肱三头肌皮褶厚度']  = lg_g3.predict(np.array(train_df.loc[index,lg_features]).reshape(1, -1))
                        
                for index,bool in enumerate (test_df['胰岛素释放实验'].isnull()):
                    if  bool:
                        test_df.loc[index,'胰岛素释放实验']  = lg_yd.predict(np.array(test_df.loc[index,lg_features]).reshape(1, -1))
                        
                    
                for index,bool in enumerate (test_df['肱三头肌皮褶厚度'].isnull()):
                    if  bool:
                        test_df.loc[index,'肱三头肌皮褶厚度']  = lg_g3.predict(np.array(test_df.loc[index,lg_features]).reshape(1, -1))        
            
            #试试knn拟合
            if method == 'knn':
                train_df = pd.DataFrame(KNN(k=5).fit_transform(train_df),columns= train_df.columns)
                test_df = pd.DataFrame(KNN(k=5).fit_transform(test_df),columns= test_df.columns)
            
            
        
                
        
            return train_df,test_df        
      • 口服耐糖量测试为-1,0,也认为缺失
      • 体重指数为0,认为缺失
      • 胰岛素释放实验 为0 ,认为缺失
      • 肱三头肌皮褶厚度为0,认为缺失
      • 缺失值(左:测试,右:验证)

        • 舒张压分布一致, 缺失比例约为4.9%
        • 口服耐糖量测试,缺失比例不同,测试集:1.6%;训练集:4.9%
        • 体重指数,缺失比例不同,测试集:0.2%;训练集:0.15%
      • 测试了将胰岛素释放实验和肱三头肌皮褶厚度为0认为缺失,用KNN和线性拟合,模型结果不好,所以最终还是只用平均值填充了 口服耐糖量、舒张压和体重指数

      • 后面再想想辙吧,这个就搞了两三个小时。

    • 字段类型分析
      • 结合比赛报名中的字段类型(int、float、object)
      • 数值类型:
        • 体重指数,舒张压,口服耐糖量测试、胰岛素释放试验,肱三头肌皮褶厚度,肱三头肌皮褶厚度
      • 类别类型:
        • 性别、糖尿病家族史、患有糖尿病标识、性别、出生年份(后续处理为年龄)
    • 相关性计算
      • 相关性
        #将糖尿病家族史转换为类别变量
        dict_糖尿病家族史 = {
            '无记录': 0,
            '叔叔或姑姑有一方患有糖尿病': 1,
            '叔叔或者姑姑有一方患有糖尿病': 1,
            '父母有一方患有糖尿病': 2
        }
        train_df['糖尿病家族史'] = train_df['糖尿病家族史'].map(dict_糖尿病家族史)
        test_df['糖尿病家族史'] = test_df['糖尿病家族史'].map(dict_糖尿病家族史)
        
        #出生年份转换
        train_df['年龄'] = 2022 - train_df['出生年份']
        test_df['年龄'] = 2022 - test_df['出生年份']
        
        train_df.corr().loc['患有糖尿病标识',:]

        • 肱三头肌皮喆厚度、体重指数、口服耐糖量测试、舒张压、胰岛素释放实验、相关性较高
      • 查看不同标签下,各字段分布
      • for column in train_df.columns:
            if column == '编号':
                continue
            if column == '患有糖尿病标识':
                continue
            plt.figure()
            for i in [0,1]:
                train_df[column][train_df['患有糖尿病标识']==i].hist()
            plt.title("{}".format(column))    
            plt.savefig("fig/{}.png".format(column))
         

  • 尝试逻辑回归
    • from sklearn.linear_model import LogisticRegression
      from sklearn.preprocessing import MinMaxScaler
      from sklearn.pipeline import make_pipeline
      from sklearn.model_selection import train_test_split
      from sklearn.model_selection import GridSearchCV
      from sklearn.metrics import accuracy_score
      
      
      #填充空值
      train_df['舒张压'].fillna(89.42, inplace=True)
      test_df['舒张压'].fillna(89.42, inplace=True)
      
      train_df['口服耐糖量测试'].fillna(5.95,inplace = True)
      test_df['口服耐糖量测试'].fillna(5.95,inplace = True)
      
      #划分训练集、验证集
      features = [f for f in train_df.columns if f not in ['编号','出生年份','患有糖尿病标识']]
      x_train, x_test, y_train, y_test = train_test_split(train_df[features],train_df['患有糖尿病标识'],test_size=0.2, random_state=2022)
      
      
      #构建模型
      lr_l1 = make_pipeline(
          MinMaxScaler(),
          LogisticRegression(penalty="l1", C=1, solver="liblinear")
      )
      
      lr_l2 = make_pipeline(
          MinMaxScaler(),
          LogisticRegression(penalty="l2", C=1, solver="liblinear")
      )
      
      # 训练集表现
      l1_train_predict = []
      l2_train_predict = []
      
      # 测试集表现
      l1_test_predict = []
      l2_test_predict = []
      
      for c in np.linspace(0.01, 10, 100) :
          lr_l1 = LogisticRegression(penalty="l1", C=c, solver="liblinear", max_iter=2000)
          lr_l2 = LogisticRegression(penalty='l2', C=c, solver='liblinear', max_iter=2000)
          
          # 训练模型,记录L1正则化模型在训练集测试集上的表现
          lr_l1.fit(x_train, y_train)
          l1_train_predict.append(accuracy_score(lr_l1.predict(x_train), y_train))
          l1_test_predict.append(accuracy_score(lr_l1.predict(x_test), y_test))
          
          # 记录L2正则化模型的表现
          lr_l2.fit(x_train, y_train)
          l2_train_predict.append(accuracy_score(lr_l2.predict(x_train), y_train))
          l2_test_predict.append(accuracy_score(lr_l2.predict(x_test), y_test))
          
      data = [l1_train_predict, l2_train_predict, l1_test_predict, l2_test_predict]
      label = ['l1_train', 'l2_train', 'l1_test', "l2_test"]
      color = ['red', 'green', 'orange', 'blue']
      
      plt.figure(figsize=(12, 6))
      for i in range(4) :
          plt.plot(np.linspace(0.01, 10, 100), data[i], label=label[i], color=color[i])
      
      plt.legend(loc="best")
      plt.show()
      
      
      #取出最优参数,进行训练、预测
      best_model = LogisticRegression(penalty="l1", C=0.01, solver="liblinear", max_iter=2000)
      best_model.fit(train_df[features],train_df['患有糖尿病标识'])
      
      test_df['label'] = best_model.predict(test_df.drop(['编号'], axis=1))
      test_df.rename({'编号': 'uuid'}, axis=1)[['uuid', 'label']].to_csv('submit.csv', index=None)
      
      

    • 基于训练集验证集的准确率:82.05%

  • 特征工程
    • 基于性别的新特征(考虑到体重指数和舒张压与性别有关)
      df_sex = train_df[['体重指数','舒张压']].groupby(train_df['性别']).mean()
      
      train_df['体重指数_diff'] = [train_df.loc[i,'体重指数'] - df_sex.loc[train_df.loc[i,'性别'],'体重指数'] for i in range(len(train_df))]
      train_df['舒张压_diff'] = [train_df.loc[i,'舒张压'] - df_sex.loc[train_df.loc[i,'性别'],'舒张压'] for i in range(len(train_df))]
      • 基于训练集验证集的准确率:82.35%
    • 基于糖尿病家族史的新特征(考虑到部分因素与糖尿病家族史相关)
      df_family = train_df[['口服耐糖量测试','胰岛素释放实验','肱三头肌皮褶厚度']].groupby(train_df['糖尿病家族史']).mean()
      
      for column in ['口服耐糖量测试','胰岛素释放实验','肱三头肌皮褶厚度']:
          train_df[column +'_diff'] = [train_df.loc[i,column] - df_family.loc[train_df.loc[i,'糖尿病家族史'],column] for i in range(len(train_df))]
      
      • 基于训练集验证集的准确率:82.05%
  • 特征筛选
    # 构建模型
    model = make_pipeline(
        MinMaxScaler(),
        DecisionTreeClassifier()
    )
    #拟合结果
    model.fit(x_train,y_train)
    #查看特征重要度
    for index, importance in enumerate(model.named_steps['decisiontreeclassifier'].feature_importances_):
        print(index, importance)
    
    • top5
      • ['体重指数','舒张压','口服耐糖量测试', '胰岛素释放实验','肱三头肌皮褶厚度',]

      • 10个指标重要度:[0.0030843 , 0.31595439, 0.00559351, 0.11861977, 0.16319968, 0.08296783, 0.25307058, 0.03212695, 0.01597175, 0.00941124]

    • 没有明显提高:模型的达到瓶颈,不能接受更复杂的参数特征?

  • 高阶树模型
    #构建模型
    clf = lgb.LGBMClassifier(
        max_depth=3, 
        n_estimators=4000, 
        n_jobs=-1, 
        verbose=-1,
        verbosity=-1,
        learning_rate=0.1,
    )
    
    #模型训练
    clf.fit(x_train,y_train)
    
    print(accuracy_score(y_test,clf.predict(x_test)))
    
    test_df['label'] = clf.predict(test_df[features])
    test_df.rename({'编号': 'uuid'}, axis=1)[['uuid', 'label']].to_csv('submit.csv', index=None)
    • 在验证集上准确度:95.95%,test上:

    • 调整超参数:具体代码不写了,参考了一位大神的代码:

      • 白话机器学习算法理论+实战番外篇之LightGBM_翻滚的小@强的博客-CSDN博客_互斥特征捆绑

      • 结果:

        • 看样子过拟合了

  • 多折训练与集成
    # 模型交叉验证
    def run_model_cv(model, kf, X_tr, y, X_te, cate_col=None):
        train_pred = np.zeros( (len(X_tr), len(np.unique(y))) )
        test_pred = np.zeros( (len(X_te), len(np.unique(y))) )
        cv_clf = []
        for tr_idx, val_idx in kf.split(X_tr, y):
            x_tr = X_tr.iloc[tr_idx]; y_tr = y.iloc[tr_idx]
    
            x_val = X_tr.iloc[val_idx]; y_val = y.iloc[val_idx]
    
            call_back = [
                lgb.early_stopping(50),
            ]
            eval_set = [(x_val, y_val)]
            model.fit(x_tr, y_tr, eval_set=eval_set, callbacks=call_back, verbose=-1)
    
            cv_clf.append(model)
    
            train_pred[val_idx] = model.predict_proba(x_val)
            test_pred += model.predict_proba(X_te)
            
    
        test_pred /= kf.n_splits
        return train_pred, test_pred, cv_clf
    
    #定义模型
    clf = lgb.LGBMClassifier(boosting_type='gbdt',objective='binary',metrics='binary_logloss',learning_rate=0.01, n_estimators=94, max_depth=3, num_leaves=10,max_bin=175,min_data_in_leaf=101,bagging_fraction=0.6,bagging_freq= 0, feature_fraction= 0.8,                             
    lambda_l1=0.7,lambda_l2=0.7,min_split_gain=0.1,num_iterations =10000)
    
    #训练KFold
    train_pred, test_pred, cv_clf = run_model_cv(
        clf, KFold(n_splits=5),
        x_train,
        y_train,
        x_test)
    
    test_pred_1 = [ i.argmax() for i in test_pred]
    accuracy_score(test_pred_1,y_test)
    
    #训练StratifiedKfold
    train_pred, test_pred, cv_clf = run_model_cv(
        clf, StratifiedKFold(n_splits=5),
        x_train,
        y_train,
        x_test)
    
    test_pred_2 = [ i.argmax() for i in test_pred]
    accuracy_score(test_pred_2,y_test)
    
    • 使用了KFold 和 StratifiedKFold,尝试3-5折,发现4折StratifiedKFold效果最好,在验证集上为95.85%,好像也没有优于单个的gbm模型。

    • test上结果:

    • 试一下stacking:

      • 参考代码:Introduction to Ensembling/Stacking in Python | Kaggle

      • 第一层选用了,gbdt,adaboost、rf、extratrees、svm;第二层lightgbm

      • 应该过拟合了,在我的验证集96.15%效果更好

      • test结果:

         

  • 后面再试试特征工程,调调参吧!就这样!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994163.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号