[Modélisation mathématique] Comment diagnostiquer la maladie d'Alzheimer à l'aide des caractéristiques structurelles du cerveau et des caractéristiques cognitivo-comportementales pour la question C de la compétition internationale de la Coupe Shuwei 2022


Sujet du concours : Comment diagnostiquer la maladie d'Alzheimer à l'aide des caractéristiques structurelles du cerveau et
des caractéristiques cognitivo-comportementales

1. Introduction

Ce document comprend principalement le processus de résolution du problème de la Shuwei Cup C 2022, y compris le code et l'explication des résultats de l'opération. La figure ci-dessous est le résumé en chinois de cet article.
insérer la description de l'image ici

2 reformulation de la question

  • Question 1 : Prétraitez les indicateurs de caractéristiques des données jointes et examinez la corrélation entre les caractéristiques des données et le diagnostic de la maladie d'Alzheimer.
  • Question 2 : À l'aide des caractéristiques de la structure cérébrale et des caractéristiques cognitivo-comportementales ci-jointes, concevez un diagnostic intelligent de la maladie d'Alzheimer.
  • Question 3 : Premièrement, regroupez CN, MCI et AD en trois catégories principales. Ensuite, pour les trois sous-classes (SMC, EMCI et LMCI) incluses dans le MCI, nous avons continué à affiner les clusters en trois sous-classes.
  • Question 4 : Le même échantillon dans la pièce jointe contient des caractéristiques collectées à différents moments. Veuillez analyser la relation entre elles et les moments pour révéler l'évolution des différents types de maladies au fil du temps.
  • Question 5 : Veuillez vous référer à la littérature pertinente pour décrire les critères d'intervention précoce et de diagnostic du CN, du SMC, de l'EMCI, du LMCI et de la MA.

Remarque : Dans cet article, la deuxième question est d'abord résolue, puis la première question est analysée à l'aide des résultats de la deuxième question.

3 Problème 1 Résolution

3.1 Prétraitement des données

df = pd.read_csv('./data/ADNIMERGE_New.csv')
df

insérer la description de l'image ici
L'ensemble de données donné contient 116 colonnes de données, avec un total de 16 222 échantillons. Dans ce problème, nous utilisons la colonne DX_bl comme colonne d'étiquette et les 155 colonnes restantes comme colonnes de fonctionnalités. La colonne d'étiquette contient un total de 5 catégories, à savoir : CN, SMC, LMCI, EMCI et AD. Comme le montre la figure ci-dessous, il existe 4 850 échantillons CN, 1 416 échantillons SMC, 5 236 échantillons LMCI, 2 968 échantillons EMCI et 1 738 échantillons AD. Parmi les 115 fonctionnalités, il existe 93 fonctionnalités numériques et 22 fonctionnalités catégorielles.
insérer la description de l'image ici
manquantno est une bibliothèque d'outils Python de visualisation des valeurs manquantes, utilisez-la pour afficher les valeurs manquantes de l'ensemble d'entraînement et de l'ensemble de test, comme le montre la figure ci-dessous.

# 查看数据缺失值分布概况
import missingno as msn
msn.matrix(df)

insérer la description de l'image ici
Dans la figure ci-dessus, la partie blanche représente la valeur manquante, et plus il y a de blancs, plus la valeur manquante est grave. Comme le montre la figure ci-dessus, il existe de sérieuses valeurs manquantes dans certaines fonctionnalités, et nous avons supprimé les fonctionnalités avec des valeurs manquantes supérieures à 30 % de la taille de l'échantillon. La répartition des valeurs manquantes des données après suppression est la suivante :

# 删除缺失值大于百分之30的数据
df_dropna = df.dropna(axis=1, thresh=11355)
df_dropna

insérer la description de l'image ici
Ensuite, supprimez les échantillons dont les colonnes DX_bl et PTMARRY sont vides et dont la forme des données restantes est : 16 207 lignes × 52 colonnes. De plus, grâce à une analyse plus approfondie du contenu des fonctionnalités, les fonctionnalités suivantes qui ne sont pas importantes pour les tâches de classification sont artificiellement supprimées : 'RID', 'COLPROT', 'ORIGPROT', 'SITE', 'VISCODE', 'EXAMDATE', 'DX ' , 'EXAMDATE_bl', 'FLDSTRENG_bl', 'FSVERSION_bl', 'IMAGEUID_bl', 'update_stamp'. À ce stade, la forme des données restantes est la suivante : 16 207 lignes × 40 colonnes.

# 删除DX_bl列为空的样本
df_dropna = df_dropna.dropna(subset=['DX_bl'])
# 删除PTMARRY列为空的样本
df_dropna = df_dropna.dropna(subset=['PTMARRY'])
# 手动删除部分特征
df_new = df_dropna.drop(columns=['RID','COLPROT','ORIGPROT','SITE','VISCODE',
'EXAMDATE','DX','EXAMDATE_bl','FLDSTRENG_bl','FSVERSION_bl','IMAGEUID_bl','update_stamp'], axis=1)
df_new

insérer la description de l'image ici
Tout d'abord, la fonctionnalité « PTID » est comptée et les données d'un total de 2 410 patients dans l'ensemble de données actuel sont calculées. Ensuite, effectuez le codage LabelEncoder sur la fonctionnalité « PTID » et effectuez le mappage suivant sur les fonctionnalités de catégorie restantes.

méthode de cartographie
'CN' : '0', 'SMC' : '1', 'EMCI' : '2', 'LMCI' : '3', 'AD' : '4'
'Femme' : '0', 'Homme' : '1'
« Pas Hisp/Latino » : « 0 », « Hisp/Latino » : « 1 », « Inconnu » : « 2
« Suis indien/Alaskan » : « 0 », « Asiatique » : « 1 », « Noir » : « 2 », « Hawaïen/Autre PI » : « 3 », « Plus d'un » : « 4 », « Inconnu » ':'5', 'Blanc':'6',
« Divorcé » : « 0 », « Marié » : « 1 », « Jamais marié » : « 2 », « Inconnu » : « 3 », « Veuf » : « 4 »
# 统计PTID的个数
df_new['PTID'].value_counts()

Nom : PTID, longueur : 2410, type : int64

# 对PTID进行labelEncode操作
from sklearn import preprocessing
lb = preprocessing.LabelEncoder()
lb =lb.fit(df_new['PTID'])  #训练LabelEncoder
df_new['PTID']=lb.transform(df_new['PTID']) 
df_new
# 对类别特征进行编码映射
dict = {
    
    
    'CN':'0', 'SMC':'1', 'EMCI':'2', 'LMCI':'3', 'AD':'4',
    'Female':'0', 'Male':'1',
    'Not Hisp/Latino':'0', 'Hisp/Latino':'1', 'Unknown':'2', 
    'Am Indian/Alaskan':'0', 'Asian':'1', 'Black':'2', 'Hawaiian/Other PI':'3', 'More than one':'4', 'Unknown':'5', 'White':'6',
    'Divorced':'0', 'Married':'1', 'Never married':'2', 'Unknown':'3', 'Widowed':'4'
}
df_new['DX_bl'] = df_new.DX_bl.map(dict)
df_new['PTGENDER'] = df_new.PTGENDER.map(dict)
df_new['PTETHCAT'] = df_new.PTETHCAT.map(dict)
df_new['PTRACCAT'] = df_new.PTMARRY.map(dict)
df_new['PTMARRY'] = df_new.PTMARRY.map(dict)

Regardez à nouveau la répartition des valeurs manquantes dans les données

msn.matrix(df_new)

insérer la description de l'image ici
La moyenne de chaque entité est utilisée pour combler les données manquantes.

# 缺失值填充
from sklearn.impute import SimpleImputer
df_new= SimpleImputer().fit_transform(df_new)
df_new = pd.DataFrame(df_new)
df_new

Comme le montre la figure ci-dessous, le nombre de maladies dans chaque catégorie à l'heure actuelle est : LMCI : 5236, CN : 4850, EMCI : 2967, AD : 1738, SMC : 1416. , enregistrez les données, enregistrées sous df_new_PTID.csv

df_new.to_csv('./data/df_new.csv', index=False)

insérer la description de l'image ici

3.2 Formation sur modèle

df = pd.read_csv('./data/df_new_PTID.csv')
df

Il convient de noter que l'ensemble de données contient plusieurs échantillons du même patient. Afin d'éviter le croisement des données, les données sont divisées selon les règles suivantes, comme le montre la figure ci-dessous.

# PTID小于1687的70%的病人划分到训练集
train = df[df['PTID'] < 1687]
test = df[df['PTID'] >= 1687]

Ensemble de formation : ID de patients inférieurs à 1 687. 11425 échantillons.
Ensemble de test : 4 782 échantillons avec un identifiant de patient supérieur ou égal à 1 687.

insérer la description de l'image ici
Le code ci-dessous est la division des données et des étiquettes de l'ensemble d'entraînement et de l'ensemble de test. De plus, dans les expériences de cet article, les modèles utilisés utilisent des paramètres par défaut.

train_data = train.drop(['DX_bl','PTID'],axis=1)
train_target = train['DX_bl']
test_data = test.drop(['DX_bl','PTID'],axis=1)
test_target = test['DX_bl']

3.2.1 Régression logistique

# 逻辑回归
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(train_data, train_target)
test_pred = clf.predict(test_data)


measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici

3.2.2 SVM

# 线性可分支持向量机
from sklearn.svm import LinearSVC
clf = LinearSVC(random_state=0, tol=1e-5)


clf.fit(train_data, train_target)
test_pred = clf.predict(test_data)


measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici

3.2.3 KNN

# KNN分类
from sklearn.neighbors import KNeighborsClassifier
# clf = KNeighborsClassifier(n_neighbors=10)
clf = KNeighborsClassifier()
clf.fit(train_data, train_target)
test_pred = clf.predict(test_data)
measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici

3.2.4 Arbre de décision

# 决策树分类
from sklearn.tree import DecisionTreeClassifier 
clf = DecisionTreeClassifier()
clf.fit(train_data, train_target) 
test_pred = clf.predict(test_data)

measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici

3.2.5 XGB

# xgb
params = {
    
    
    'objective': 'multi:softmax', 'num_class' : 5
}


dtrain = xgb.DMatrix(train_data, train_target)
num_rounds = 500
model_xgb = xgb.train(params, dtrain, num_rounds)
dtest = xgb.DMatrix(test_data)
test_pred = model_xgb.predict(dtest)


measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici
Voir l'importance des fonctionnalités du modèle

xgb_feature_importance = pd.DataFrame(list(model_xgb.get_fscore().items()))
xgb_feature_importance.columns = ['Feature', 'Feature importrance']

#设置绘图风格
plt.style.use('ggplot')
#处理中文乱码
#对读入的数据做降序排序
xgb_feature_importance.sort_values(by='Feature importrance', inplace=True, ascending=False)
#取前15行的数据
xgb_feature_importance = xgb_feature_importance.iloc[:15, :]  # 取前15行数据
#对读入的数据做升序排序
xgb_feature_importance.sort_values(by='Feature importrance', inplace=True, ascending=True)

#绘制条形图
plt.barh(y = range(xgb_feature_importance.shape[0]),  #指定条形图y轴的刻度值
         width = xgb_feature_importance['Feature importrance'],  #指定条形图x轴的数值
         tick_label = xgb_feature_importance['Feature'],  #指定条形图y轴的刻度标签
         color = 'lightblue',  #指定条形图的填充色
         )
#添加x轴的标签
plt.xlabel('Feature importrance')
#添加条形图的标题
plt.title('XGB Feature importrance')
#为每个条形图添加数值标签
for y,x in enumerate(xgb_feature_importance['Feature importrance']):
    plt.text(x+0.1,y,"%s"%round(x,1),va='center')  #round(y,1)是将y值四舍五入到一个小数位
#显示图形
plt.show()

insérer la description de l'image ici

3.2.6 LGB

# lgb
from numpy import true_divide
params = {
    
    
    'objective': 'multiclass', 'num_class' : 5
}
dtrain = lgb.Dataset(train_data, label=train_target)
cate_features_name = ['PTGENDER','PTETHCAT','PTRACCAT','PTMARRY']
model_lgb = lgb.train(params, dtrain, categorical_feature= cate_features_name)
test_pred = model_lgb.predict(test_data)
preds = test_pred
test_pred = []
for x in preds:
    test_pred.append(np.argmax(x))
measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici
Comme ci-dessus, regardez l'importance des fonctionnalités du modèle LGB

feature_name = pd.DataFrame(model_lgb.feature_name())
feature_importance = pd.DataFrame(model_lgb.feature_importance())
lgb_model_importance = pd.concat([feature_name, feature_importance], axis=1)
lgb_model_importance.columns = ['Feature', 'Feature importrance']

insérer la description de l'image ici

3.2.7 CB

# 因为catboost的类别变量得是整形或者字符型
# 报错信息:cat_features must be integer or string, real number values and NaN values should be converted to str
train_data = train.drop(['DX_bl','PTID'],axis=1)
train_target = train['DX_bl']
test_data = test.drop(['DX_bl','PTID'],axis=1)
test_target = test['DX_bl']
train_data[['PTGENDER','PTETHCAT','PTRACCAT','PTMARRY']] = train_data[['PTGENDER','PTETHCAT','PTRACCAT','PTMARRY']].astype(str)
test_data[['PTGENDER','PTETHCAT','PTRACCAT','PTMARRY']] = test_data[['PTGENDER','PTETHCAT','PTRACCAT','PTMARRY']].astype(str)
# cb
cat_features_index = [1,3,4,5]
model_cb = cb.CatBoostClassifier()
model_cb.fit(train_data, train_target, cat_features=cat_features_index)
test_pred = model_cb.predict(test_data)
measure_result = classification_report(test_target, test_pred)
print('measure_result = \n', measure_result)

insérer la description de l'image ici
De même, vérifiez l’importance des fonctionnalités du modèle CB

fea_ = model_cb.feature_importances_
fea_name = model_cb.feature_names_
cb_value = pd.DataFrame(fea_)
cb_name = pd.DataFrame(fea_name)
cb_feature_importrance = pd.concat([cb_name,cb_value], axis=1)
cb_feature_importrance.columns = ['Feature', 'Feature importrance']

insérer la description de l'image ici

3.3 Comparaison de différents modèles

Pour les indicateurs d'évaluation des modèles, veuillez vous référer à l'article suivant
[Modélisation mathématique] Plusieurs indicateurs courants pour les problèmes de classification (1) - taux de précision, taux de rappel, valeur F1

Nous utiliserons la précision, la moyenne macro et la moyenne pondérée des 7 modèles Le f1 -score in est visualisé et analysé, comme le montre la figure ci-dessous.

insérer la description de l'image iciOn peut constater que les modèles basés sur l'apprentissage intégré ont obtenu des résultats satisfaisants et la précision a atteint plus de 83 %. Mais l’effet de classement en catégorie 1 n’est toujours pas idéal. Il se peut que le modèle ignore les caractéristiques de cette catégorie de SMC. En réalité, il peut s'avérer difficile de détecter de tels symptômes, mais on constate que la prévention précoce de la maladie d'Alzheimer présente encore d'énormes défis.

4 Résoudre le deuxième problème

Notez que cette question omet certaines étapes intermédiaires

4.1 Traitement des données

Sélectionnez l'union des 15 fonctionnalités les plus importantes de XGB, LGB et CB ci-dessus + 'PTID' comme nouvel ensemble de données
et enregistrez le nouvel ensemble de données sous : df_cluster_18F.csv

# 选中其中的18个特征+1个label
df_cluster = df[['AGE','mPACCtrailsB_bl','ICV_bl','LDELTOTAL_BL','WholeBrain_bl',
'CDRSB_bl','MidTemp_bl','TRABSCOR_bl','Entorhinal_bl','mPACCdigit_bl','Fusiform_bl','Ventricles_bl','Hippocampus_bl',
'PTEDUCAT','RAVLT_immediate_bl','FAQ_bl','MMSE_bl','ADAS11_bl','DX_bl']]
df_cluster.to_csv('./data/df_cluster_18F.csv', index=False)

Enregistrez les 5 catégories d'étiquettes dans l'ensemble de données sous forme de 3 catégories.
À savoir CN-CN, SMC, EMCI, LMCI-MCI, AD-AD

# 将5类标签转换为3类标签
dict = {
    
    
    0:0, 1:1, 2:1, 3:1, 4:2
}
df_cluster['DX_bl'] = df_cluster.DX_bl.map(dict)
df_cluster['DX_bl'].value_counts()

insérer la description de l'image ici
Enregistrez cet ensemble de données sous : df_3cluster_18F.csv

df_cluster.to_csv('./data/df_3cluster_18F.csv', index=False)

4.2 Exploration des données

Lisez les données df_3cluster_18F.csv selon la méthode ci-dessus et divisez les données de la manière suivante

# PTID小于1687的70%的病人划分到训练集
train = df[df['PTID'] < 1687]
test = df[df['PTID'] >= 1687]
train_data = train.drop(['DX_bl','PTID'],axis=1)
train_target = train['DX_bl']
test_data = test.drop(['DX_bl','PTID'],axis=1)
test_target = test['DX_bl']

Dessinez des boîtes à moustaches de ces variables pour afficher les valeurs aberrantes.
insérer la description de l'image ici
Dessinez des histogrammes et des tracés QQ pour tester si ces caractéristiques sont conformes à la distribution normale, qui est liée aux paramètres sélectionnés pour l'analyse de corrélation ultérieure.
insérer la description de l'image ici
Vérifiez la distribution de l'ensemble d'entraînement et de l'ensemble de test. Si la distribution est incohérente, les fonctionnalités doivent être supprimées.
insérer la description de l'image ici

4.3 Analyse de corrélation

Dessiner une carte thermique de corrélation

data_train1 = train.drop(['PTID'],axis=1)
train_corr = data_train1.corr()
train_corr
# 画出相关性热力图
ax = plt.subplots(figsize=(20, 16))#调整画布大小
ax = sns.heatmap(train_corr, vmax=.8, square=True, annot=True)#画热力图   annot=True 显示系数

insérer la description de l'image ici
insérer la description de l'image ici
Tracez les 10 informations sur les fonctionnalités les plus pertinentes

#寻找K个最相关的特征信息
k = 10 # number of variables for heatmap
cols = train_corr.nlargest(k, 'DX_bl')['DX_bl'].index

cm = np.corrcoef(data_train1[cols].values.T)
hm = plt.subplots(figsize=(10, 10))#调整画布大小
#hm = sns.heatmap(cm, cbar=True, annot=True, square=True)
#g = sns.heatmap(train_data[cols].corr(),annot=True,square=True,cmap="RdYlGn")
hm = sns.heatmap(data_train1[cols].corr(),annot=True,square=True)
plt.show()

insérer la description de l'image ici
De même, dessinez des informations sur les caractéristiques avec une corrélation supérieure à 0,5.
insérer la description de l'image ici
Selon les informations ci-dessus, les facteurs pertinents affectant la maladie d'Alzheimer peuvent être analysés.

5 Résoudre le troisième problème

Ce problème est un problème de clustering, lisez d'abord l'ensemble de données df_3cluster_18F.csv

5.1 Sélection de la valeur K

Dessinez le diagramme du coude

data = np.array(train_data)
Scores = []  # 存放轮廓系数
SSE = []  # 存放每次结果的误差平方和
for k in range(2, 9):
    estimator = KMeans(n_clusters=k)  # 构造聚类器
    estimator.fit(data)
    Scores.append(silhouette_score(
        np.array(df), estimator.labels_, metric='euclidean'))
    SSE.append(estimator.inertia_) # estimator.inertia_获取聚类准则的总和
X = range(2, 9)
plt.figure(figsize=(15,5))
plt.subplot(121)
plt.xlabel('k', fontsize=15)
plt.ylabel('SSE', fontsize=15)
plt.plot(X, SSE, 'o-')
plt.subplot(122)
plt.xlabel('k值', fontsize=15)
plt.ylabel('轮廓系数', fontsize=15)
plt.plot(X, Scores, 'o-')
plt.savefig('./img/手肘法.png',dpi=300)
plt.show()

insérer la description de l'image ici

5.2 Sélection aléatoire des graines

Je n'ai pas non plus compris pourquoi ce sujet devrait d'abord être regroupé en 3 catégories. Ici, la valeur k est sélectionnée sur 3 et la plage de valeurs de départ aléatoire est définie sur 2000-2025. Dessinez la figure suivante

Scores = []  # 存放轮廓系数
for i in range(2000,2025):
    estimator = KMeans(n_clusters=3, random_state=i)  # 构造聚类器
    estimator.fit(data)
    Scores.append(silhouette_score(np.array(df), estimator.labels_, metric='euclidean'))
X = range(2000, 2025)
plt.figure(figsize=(7,5))
plt.xlabel('random_state', fontsize=15)
plt.ylabel('silhouette coefficient', fontsize=15)
plt.plot(X, Scores, 'o-')
plt.xlim(2000, 2025)
plt.savefig('./img/随机种子的确定.png',dpi=300)
plt.show()

insérer la description de l'image ici
La sélection aléatoire finale des graines est 2009 (choisissez le point le plus élevé)

5.3 K signifie regroupement

Utilisez ensuite k=3, random_state=2009 et effectuez un clustering kmeans (d'autres méthodes de clustering peuvent également être essayées)

# Kmens 聚类
from sklearn.cluster import KMeans
# 实例化K-Means算法模型,先使用3个簇尝试聚类
cluster = KMeans(n_clusters=3, random_state=2009)
# 使用数据集train_data进行训练
cluster = cluster.fit(train_data)
# 调用属性labels_,查看聚类结果
cluster.labels_
labels_pred = cluster.labels_
import collections
data_count2=collections.Counter(labels_pred)
data_count2

Les résultats du regroupement sont les suivants :
insérer la description de l'image ici
 L'indice ARI à ce moment est calculé comme suit : 0,012940512409904181.
La PCA est utilisée pour réduire la dimensionnalité des données et le regroupement est effectué de la même manière. Les résultats visualisés sont les
insérer la description de l'image ici
suivants. Les résultats de la deuxième question est la même que ci-dessus, et les résultats s'affichent directement :
insérer la description de l'image ici
insérer la description de l'image ici

6 Solution aux questions 4 et 5

6.1 Question 4

J'ai utilisé une méthode visuelle pour analyser ce problème. Je peux d'abord dessiner les changements de chaque caractéristique au fil du temps, puis décrire moi-même la tendance sur l'image.
Quatre types de patients ont été sélectionnés pour l'analyse, parmi lesquels le PTID de SMC était 135_S_5113, le PTID d'EMCI était 007_S_2394, le PTID de LMCI était 021_S_0178 et le PTID d'AD était 027_S_4938. Ici, 9 fonctionnalités sont sélectionnées : CDRSB, ADAS11, ADAS13, ADASQ4, MMSE, RAVLT_immediate, RAVLT_learning, RAVLT_forgetting et RAVLT_perc_forgetting pour l'analyse, et visualisez les changements de fonctionnalités des quatre échantillons de recherche, comme le montre la figure ci-dessous.
insérer la description de l'image ici
insérer la description de l'image ici
insérer la description de l'image ici
insérer la description de l'image ici
Quant à la cinquième question, vérifions les informations.

résumé

Cela donne seulement une idée pour résoudre le problème, et il y a des endroits déraisonnables, et vous devez le faire vous-même pour trouver une solution spécifique.

annexe

à trier~

Je suppose que tu aimes

Origine blog.csdn.net/qq_44319167/article/details/127954066
conseillé
Classement