糖尿病遗传风险检测挑战赛

Posted 清浅岁月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了糖尿病遗传风险检测挑战赛相关的知识,希望对你有一定的参考价值。

糖尿病遗传风险检测挑战赛

加载数据

import pandas as pd
import lightgbm
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import numpy as np
from sklearn.model_selection import KFold

plt.style.use('ggplot')

np.random.seed(123)

pd.options.mode.chained_assignment = None

sns.set_style('whitegrid')
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS'] # mac 下使用 设置中文字体
data1=pd.read_csv('./data/train.csv',encoding='gbk')
data2=pd.read_csv('./data/test.csv',encoding='gbk')

查看数据

data1.head()

data2.head()

data1.info()

<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 5070 entries, 0 to 5069
Data columns (total 10 columns):
Column Non-Null Count Dtype


0 编号 5070 non-null int64
1 性别 5070 non-null int64
2 出生年份 5070 non-null int64
3 体重指数 5070 non-null float64
4 糖尿病家族史 5070 non-null object
5 舒张压 4823 non-null float64
6 口服耐糖量测试 5070 non-null float64
7 胰岛素释放实验 5070 non-null float64
8 肱三头肌皮褶厚度 5070 non-null float64
9 患有糖尿病标识 5070 non-null int64
dtypes: float64(5), int64(4), object(1)
memory usage: 396.2+ KB

data1.isnull().count()

编号 5070
性别 5070
出生年份 5070
体重指数 5070
糖尿病家族史 5070
舒张压 5070
口服耐糖量测试 5070
胰岛素释放实验 5070
肱三头肌皮褶厚度 5070
患有糖尿病标识 5070
dtype: int64

data1.shape

(5070, 10)

data1.describe()

data1.groupby('性别')['体重指数'].mean()

性别
0 37.197603
1 38.925216
Name: 体重指数, dtype: float64

data1['体重指数'] - data1['性别'].map(
    data1.groupby('性别')['体重指数'].mean()
)

0 -7.097603
1 -9.697603
2 -2.425216
3 -9.425216
4 4.802397

5065 -2.525216
5066 -1.825216
5067 -11.797603
5068 -8.697603
5069 12.702397
Length: 5070, dtype: float64

data1.head()

data1.groupby('性别')['体重指数'].transform('mean')

0 37.197603
1 37.197603
2 38.925216
3 38.925216
4 37.197603

5065 38.925216
5066 38.925216
5067 37.197603
5068 37.197603
5069 37.197603
Name: 体重指数, Length: 5070, dtype: float64

data1.head()

data1.isnull().sum()

编号 0
性别 0
出生年份 0
体重指数 0
糖尿病家族史 0
舒张压 247
口服耐糖量测试 0
胰岛素释放实验 0
肱三头肌皮褶厚度 0
患有糖尿病标识 0
dtype: int64

data2.isnull().sum()

编号 0
性别 0
出生年份 0
体重指数 0
糖尿病家族史 0
舒张压 49
口服耐糖量测试 0
胰岛素释放实验 0
肱三头肌皮褶厚度 0
dtype: int64

data1.dtypes

编号 int64
性别 int64
出生年份 int64
体重指数 float64
糖尿病家族史 object
舒张压 float64
口服耐糖量测试 float64
胰岛素释放实验 float64
肱三头肌皮褶厚度 float64
患有糖尿病标识 int64
dtype: object

对数据做可视化查看

data1['性别'].value_counts().plot(kind = 'bar')

data1['性别'].value_counts().plot(kind = 'barh')

data1.groupby('患有糖尿病标识')['性别'].value_counts()

sns.countplot(x = '患有糖尿病标识',hue='性别',data = data1)

sns.boxplot(x = '患有糖尿病标识',y ='出生年份',data=data1)

sns.boxplot(x = '患有糖尿病标识',y ='出生年份',hue='性别',data=data1)

sns.violinplot(x = '患有糖尿病标识',y ='体重指数',hue='性别',data=data1)

sns.scatterplot(x='体重指数',y='舒张压',hue='患有糖尿病标识',data =data1)

体重指数与舒张压有明显的分层,体重指数在50-60,舒张压在80-100,基本都是患有糖尿病的,这两数据应该可以做一下挖掘

sns.kdeplot(x='体重指数',y='舒张压',hue='患有糖尿病标识',data =data1)

sns.kdeplot(x='体重指数',y='舒张压',hue='患有糖尿病标识',data =data1,fill=True,alpha = 0.5)

data1.head()

sns.scatterplot(x='胰岛素释放实验',y='口服耐糖量测试',hue='患有糖尿病标识',data =data1)

胰岛素释放实验和口服耐糖量测试没看出有啥明显的特征或者关联吧

sns.scatterplot(x='舒张压',y='肱三头肌皮褶厚度',hue='患有糖尿病标识',data =data1)

舒张压和肱三头肌皮褶厚度 也是和体重指数有一定的明显分层,肱三头肌皮褶厚度查了一下和体重应该有关

sns.scatterplot(x='舒张压',y='胰岛素释放实验',hue='患有糖尿病标识',data =data1)

舒张压和胰岛素释放实验 看似有一些明显的分层,舒张压在80-100,胰岛素释放实验在20-40之间的患者较多,应该有一定的数据特征值的挖掘

sns.scatterplot(x='舒张压',y='口服耐糖量测试',hue='患有糖尿病标识',data =data1)

舒张压与口服耐糖量测试也有明显的分层特征,舒张压在80-100,口服耐糖量测试在8-10患病较多,还有舒张压超过100-105之间,但是口服耐糖量测试在我、全数据范围都有,应该是有一定的数据特征需要进一步挖掘。

train_data=data1.drop(['编号','患有糖尿病标识'],axis=1)
plt.figure(figsize = (30, 12))
sns.heatmap(train_data.corr(), 
            annot = True,
            fmt = '.2f',
            square = True,
            cmap = "Blues_r", 
            mask = np.triu(train_data.corr()))

mask = np.zeros_like(train_data.corr(), dtype=np.bool)
#mask[np.triu_indices_from(mask)] = True

plt.subplots(figsize = (15,12))
sns.heatmap(train_data.corr(), 
            annot=True,
#             mask = mask,
            cmap = 'RdBu', ## in order to reverse the bar replace "RdBu" with "RdBu_r"
            linewidths=.9, 
            linecolor='gray',
            fmt='.2g',
            center = 0,
            square=True)
plt.title("Correlations Among Features", y = 1.03,fontsize = 20, pad = 80) #相关性矩阵


处理空数据

使用上一条数据将确实数据补充上,我觉得不太合理,应该使用平均数据,回头改进一下,其实影响也不大吧

data1['舒张压'].fillna(method='ffill', inplace=True)
data2['舒张压'].fillna(method='ffill', inplace=True)
data1.isnull().sum()

编号 0
性别 0
出生年份 0
体重指数 0
糖尿病家族史 0
舒张压 0
口服耐糖量测试 0
胰岛素释放实验 0
肱三头肌皮褶厚度 0
患有糖尿病标识 0
dtype: int64

data2.isnull().sum()

编号 0
性别 0
出生年份 0
体重指数 0
糖尿病家族史 0
舒张压 0
口服耐糖量测试 0
胰岛素释放实验 0
肱三头肌皮褶厚度 0
dtype: int64


#label标记为-1
data2['患有糖尿病标识']=-1

#训练集和测试机合并
data=pd.concat([data1,data2],axis=0,ignore_index=True)

使用Baseline的一些特征构造,还有自己查了一下构造了一些特征

#特征工程
"""
人体的成人体重指数正常值是在18.5-24之间
低于18.5是体重指数过轻
在24-27之间是体重超重
27以上考虑是肥胖
高于32了就是非常的肥胖。
"""
def BMI(a):
    if a<18.5:
        return 0
    elif 18.5<=a<=24:
        return 1
    elif 24<a<=27:
        return 2
    elif 27<a<=32:
        return 3
    else:
        return 4
    
data['BMI']=data['体重指数'].apply(BMI)
data['出生年份']=2022-data['出生年份']  #换成年龄
#糖尿病家族史
"""
无记录
叔叔或者姑姑有一方患有糖尿病/叔叔或姑姑有一方患有糖尿病
父母有一方患有糖尿病
"""
def FHOD(a):
    if a=='无记录':
        return 0
    elif a=='叔叔或者姑姑有一方患有糖尿病' or a=='叔叔或姑姑有一方患有糖尿病':
        return 1
    else:
        return 2
    
data['糖尿病家族史']=data['糖尿病家族史'].apply(FHOD)
data['舒张压']=data['舒张压'].fillna(-1)
"""
舒张压范围为60-90
"""
def DBP(a):
    if a<60:
        return 0
    elif 60<=a<=90:
        return 1
    elif a>90:
        return 2
    else:
        return a
data['DBP']=data['舒张压'].apply(DBP)
data

区分性别,体重与平均体重指数的差值作为一个特征

data['TBI']=data['体重指数'] - data['性别'].map(
    data.groupby('性别')['体重指数'].mean()
)
data


口服耐糖量测试的一个不正常的区间的划分

# 口服耐糖量测试   大于11.1不正常

def KFT(a):
    if a<7.8:
        return 0
    elif 7.8<=a<=11.1:
        return 1
    elif a>11.1:
        return 2
    else:
        return 3
data['KFT']=data['口服耐糖量测试'].apply(KFT)
data


胰岛素释放实验的一个不正常的区间的划分

# 9.93-124.9
# 餐后2小时胰岛素的正常值

# 胰岛素正常值空腹4.03-23.46pmol/ml,半小时22.63-137.52pmol/ml,1小时21.73-143.85pmol/ml,两小时9.93-124.9 pmol/ml,三小时5.06-25 pmol/ml口服葡萄糖刺激后应增加5~20倍,高峰在30~60分钟,一般较多都是胰岛素高峰延迟或者无高峰。

def KYD(a):
    if a<7.8:
        return 0
    elif 9.93<=a<=124.9:
        return 1
    elif a>124.9:
        return 2 
    else:
        return 3
data['KYD']=data['胰岛素释放实验'].apply(KYD)
data


# 正常成年男性的腹部皮褶厚度为5~15mm,大于15mm 为肥胖,小于5mm为消瘦;
# 正常成年女性的腹部皮褶厚度为 12~20mm,大于20mm为肥胖,小于12mm为消瘦,尤其对40 岁以上妇女测量此部位更有意义。
# 我国男性成人的肱三头肌皮褶厚度大于10.4mm,女性大 于17.5mm属于肥胖水平。
# 正常成人肩胛皮褶厚度的平均值为12.4mm,超过14mm 就可诊断为肥胖

data.groupby('性别')['肱三头肌皮褶厚度'].mean()

性别
0 6.837553
1 7.202857
Name: 肱三头肌皮褶厚度, dtype: float64

根据性别对肱三头肌皮褶厚度做了一个分段划分


def HST(a):
    if a['性别']==0:
        
        if a['肱三头肌皮褶厚度']>10.4:
            
            return 1
    
        else:
        
            return 0
            
    elif a['性别']==1:
        if a['肱三头肌皮褶厚度']>11.4:
            
            return 1
    
        else:
        
            return 0
    
    
data['HST']=data.apply(HST,axis=1)
data

data['BMI'] = data['BMI'].astype('category')
data['DBP'] = data['DBP'].astype('category')
data['KFT'] = data['KFT'].astype('category')
data['KYD'] = data['KYD'].astype('category')
data['HST'] = data['HST'].astype('category')

data

train=data[data['患有糖尿病标识'] !=-1]
test=data[data['患有糖尿病标识'] ==-1]

train_label=train['患有糖尿病标识']

train=train.drop(['编号','患有糖尿病标识'],axis=1)
test=test.drop(['编号','患有糖尿病标识'],axis=1)

train.head()

K折交叉验证


def select_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=0
    result=[]
    for train_idx, val_idx in kfold.split(train_data):
        random_state+=1
        train_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=lightgbm
        train_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.05,
                '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+=1
    return result



test_data=select_by_lgb(train,train_label,test)
#test_data就是5折交叉验证中5次预测的结果
pre_y=pd.DataFrame(test_data).T
#将5次预测的结果求取平均值,当然也可以使用其他的方法
pre_y['averge']=pre_y[[i for i in range(5)]].mean(axis=1)
#因为竞赛需要你提交最后的预测判断,而模型给出的预测结果是概率,因此我们认为概率>0.5的即该患者有糖尿病,概率<=0.5的没有糖尿病
pre_y['label']=pre_y['averge'].apply(lambda x:1 if x>0.5 else 0)
pre_y
result=pd.read_csv('./data/提交示例.csv')
result['label']=pre_y['label']
result.to_csv('result5.csv',index=False)

使用贝叶斯调参

分布调参的,可以一次调参多个数据,但是时间要跑的很久,我是单个参数尝试的,感觉我这个单个调参和贪心算法调参有点类似了。

from sklearn.model_selection import GridSearchCV
parameters = 
    'max_depth': [3,5,10,15,20,40,55],
    'num_leaves': [3,5,10,15,20,40,55],



gbm = lightgbm.LGBMClassifier(
                boosting_type='gbdt',  
                objective= 'binary',
                learning_rate= 0.05,
                seed=2020,
                nthread=以上是关于糖尿病遗传风险检测挑战赛的主要内容,如果未能解决你的问题,请参考以下文章

糖尿病遗传风险检测挑战赛

糖尿病遗传风险检测挑战赛-权重融合

糖尿病遗传风险检测挑战赛-权重融合

糖尿病遗传风险检测挑战赛-权重融合

最新数据挖掘赛事方案梳理!

最新数据挖掘赛事方案梳理!