前言
系列专栏:机器学习:高级应用与实践【项目实战100+】【2024】✨︎
在本专栏中不仅包含一些适合初学者的最新机器学习项目,每个项目都处理一组不同的问题,包括监督和无监督学习、分类、回归和聚类,而且涉及创建深度学习模型、处理非结构化数据以及指导复杂的模型,如卷积神经网络、门控递归单元、大型语言模型和强化学习模型
自闭症是一种神经系统疾病,会影响一个人与他人互动、与他人进行眼神交流、学习能力以及一个人的其他行为和社交能力的能力。但是自闭症的确诊多因患儿的表现较难确诊,需通过详细的生长发育史、病史、精神检查及排除其他广泛性发育障碍来协助诊断。运用一些筛查性的量表进行初步筛查,最后通过儿童精神科系统检查后才能确诊。但是,如果我们使用机器学习来预测一个人是否患有自闭症,会怎么样呢?这正是我们将在本文中讨论的内容。
目录
- 1. 相关库和数据集
- 1.1 相关库介绍
- 1.2 数据集介绍
- 1.3 组织并检查数据
- 1.4 数据清理
- 2. 探索性数据分析
- 2.1 检查数据的平衡
- 2.2 探索数据的地理位置
- 2.3 检查数据的偏度
- 3. 特征工程
- 3.1 探讨年龄组病例数
- 3.2 探讨临床评分病例数
- 3.3 消除数据的偏度
- 4. 模型训练
- 5. 模型评估
1. 相关库和数据集
1.1 相关库介绍
Python 库使我们能够非常轻松地处理数据并使用一行代码执行典型和复杂的任务。
Pandas
– 该库有助于以 2D 数组格式加载数据框,并具有多种功能,可一次性执行分析任务。Numpy
– Numpy 数组速度非常快,可以在很短的时间内执行大型计算。Matplotlib/Seaborn
– 此库用于绘制可视化效果。Sklearn
– 包含多个库,这些库具有预实现的功能,用于执行从数据预处理到模型开发和评估的任务。XGBoost
– 包含 eXtreme Gradient Boosting 机器学习算法,是帮助我们实现高精度预测的算法之一。Imblearn
– 此模块包含一个函数,可用于处理与数据不平衡相关的问题。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from scipy.io import arff
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn import metrics
from sklearn.svm import SVC
from xgboost import XGBClassifier
from sklearn.linear_model import LogisticRegression
from imblearn.over_sampling import RandomOverSampler
import warnings
warnings.filterwarnings('ignore')
1.2 数据集介绍
现在,让我们将数据集加载到 pandas 数据框中并打印其前五行。
df = pd.read_csv('train.csv')
print(df.head())
df.shape
(800, 22)
该数据集包含 800 个自闭症的实例或数据,包括 22 个属性或特征的数据。我们将使用这些功能来训练我们的模型。
1.3 组织并检查数据
df.info()
根据上述有关每列数据的信息,我们可以观察到没有空值。
df.describe().T
1.4 数据清理
从主要来源获得的数据被称为原始数据,需要大量的预处理,然后才能从中得出任何结论或对其进行一些建模。这些预处理步骤称为数据清理,它包括异常值删除、空值插补以及删除数据输入中的任何类型的差异。
df['ethnicity'].value_counts()
在上面的两个输出中,我们可以观察到一些歧义,即有“?”、“其他”和“其他”,它们都必须相同,因为它们是未知的,或者我们可以说空值已被一些指示符替换。
df['relation'].value_counts()
此列的情况也是如此,因此,让我们清理此数据,然后将“yes”和“no”转换为 0 和 1。
df = df.replace({'yes':1, 'no':0, '?':'Others', 'others':'Others'})
现在,我们已经对数据进行了一些清理,以便从中获取见解。
2. 探索性数据分析
EDA是一种使用视觉技术分析数据的方法。它用于发现趋势和模式,或借助统计摘要和图形表示来检查假设。在这里,我们将看到如何检查数据的不平衡和数据的偏度。
2.1 检查数据的平衡
plt.pie(df['Class/ASD'].value_counts().values, autopct='%1.1f%%')
plt.show()
我们拥有的数据集是高度不平衡的。如果我们使用这些数据来训练我们的模型,那么模型将面临很难预测阳性类别的问题,这是我们在这里的主要目标,即高精度地预测一个人是否患有自闭症。
ints = []
objects = []
floats = []
for col in df.columns:
if df[col].dtype == int:
ints.append(col)
elif df[col].dtype == object:
objects.append(col)
else:
floats.append(col)
现在,我们根据列包含的数据类型对列进行隔离,因此现在我们将能够根据数据类型执行适当的分析。
ints.remove('ID')
ints.remove('Class/ASD')
“ID”列将包含每行的唯一值,对于“Class/ASD”列,我们已经分析了它的分布,因此,这就是为什么在上面的代码中删除它们的原因。
plt.subplots(figsize=(15,15))
for i, col in enumerate(ints):
plt.subplot(4,3,i+1)
sb.countplot(df[col], hue=df['Class/ASD'])
plt.tight_layout()
plt.show()
从这些图中,我们可以得出结论,如果某个指标的分数为 0,那么该人没有自闭症的机会非常高,除非是A10_Score。
plt.subplots(figsize=(15, 30))
for i, col in enumerate(objects):
plt.subplot(5, 3, i+1)
sb.countplot(df[col], hue=df['Class/ASD'])
plt.xticks(rotation=60)
plt.tight_layout()
plt.show()
从上面的图中,我们可以得出以下观察结果:
- 所有数据点的Age_desc都是一样的。
- 这个used_app_before功能似乎没有用,否则它将成为数据泄漏的来源。
- 在这里,男性患自闭症的几率似乎高于女性,但事实并非如此,因为我们没有相同数量的男性和女性的例子。
2.2 探索数据的地理位置
plt.figure(figsize=(15,5))
sb.countplot(data=df, x='country_of_res', hue='Class/ASD')
plt.xticks(rotation=90)
plt.show()
在一些地方,该国大约50%的可用数据患有自闭症,而在某些地方,这一比例相当低。这意味着一个人的地理位置也给出了患有自闭症的想法。
2.3 检查数据的偏度
plt.subplots(figsize=(15,5))
for i, col in enumerate(floats):
plt.subplot(1,2,i+1)
sb.distplot(df[col])
plt.tight_layout()
plt.show()
两个连续数据都是偏斜的,左边一个是正的,右边的是一个负偏态。
plt.subplots(figsize=(15,5))
for i, col in enumerate(floats):
plt.subplot(1,2,i+1)
sb.boxplot(df[col])
plt.tight_layout()
plt.show()
df = df[df['result']>-5]
df.shape
(798, 22)
所以,在这里我们只丢失了两个数据点。
3. 特征工程
特征工程有助于从现有特征中派生出一些有价值的特征。这些额外的功能有时有助于显著提高模型的性能,当然也有助于更深入地了解数据。
3.1 探讨年龄组病例数
# This functions make groups by taking
# the age as a parameter
def convertAge(age):
if age < 4:
return 'Toddler'
elif age < 12:
return 'Kid'
elif age < 18:
return 'Teenager'
elif age < 40:
return 'Young'
else:
return 'Senior'
df['ageGroup'] = df['age'].apply(convertAge)
现在,让我们探讨每个年龄组的病例数。
sb.countplot(x=df['ageGroup'], hue=df['Class/ASD'])
plt.show()
在这里,我们可以得出结论,幼儿群体患自闭症的几率较低。
3.2 探讨临床评分病例数
def add_feature(data):
# Creating a column with all values zero
data['sum_score'] = 0
for col in data.loc[:,'A1_Score':'A10_Score'].columns:
# Updating the 'sum_score' value with scores
# from A1 to A10
data['sum_score'] += data[col]
# Creating a random data using the below three columns
data['ind'] = data['austim'] + data['used_app_before'] + data['jaundice']
return data
df = add_feature(df)
在上面的代码块中,我们刚刚总结了从 A1 到 A10 给出的临床评分。
sb.countplot(x=df['sum_score'], hue=df['Class/ASD'])
plt.show()
另一个惊人的观察结果:总分越高,患自闭症的几率也越高,同样,对于低于 5 分的总分较低,该人患有自闭症的情况很少见。
3.3 消除数据的偏度
# Applying log transformations to remove the skewness of the data.
df['age'] = df['age'].apply(lambda x: np.log(x))
提供给我们的年龄数据是正偏态的。我们知道偏斜数据会影响模型的性能,因此我们将应用对数转换来消除数据的偏斜。
sb.distplot(df['age'])
plt.show()
现在,已成功消除数据的偏度
def encode_labels(data):
for col in data.columns:
# Here we will check if datatype
# is object then we will encode it
if data[col].dtype == 'object':
le = LabelEncoder()
data[col] = le.fit_transform(data[col])
return data
df = encode_labels(df)
# Making a heatmap to visualize the correlation matrix
plt.figure(figsize=(10,10))
sb.heatmap(df.corr() > 0.8, annot=True, cbar=False)
plt.show()
从上面的热图中,我们可以看到,在基于此数据训练模型之前,我们将删除一个高度相关的特征,因为高度相关的特征无助于学习数据中的有用模式。
4. 模型训练
现在,我们将特征和目标变量分开,并将它们拆分为训练和测试数据,通过这些数据,我们将选择在验证数据上表现最好的模型。
removal = ['ID', 'age_desc', 'used_app_before', 'austim']
features = df.drop(removal + ['Class/ASD'], axis=1)
target = df['Class/ASD']
让我们将数据拆分为训练数据和验证数据。此外,数据之前是不平衡的,现在我们将使用随机采样器来平衡它,在这种方法中,我们从少数类中抽取一些点并重复多次,以便两个类获得平衡。
X_train, X_val, \
Y_train, Y_val = train_test_split(
features, target,
test_size = 0.2, random_state=10)
# As the data was highly imbalanced we will balance it by adding repetitive rows of minority class.
ros = RandomOverSampler(sampling_strategy='minority',random_state=0)
X, Y = ros.fit_resample(X_train,Y_train)
X.shape, Y.shape
输出
((1026, 20), (1026,))
现在,让我们对数据进行归一化,以获得稳定和快速的训练。
# Normalizing the features for stable and fast training.
scaler = StandardScaler()
X = scaler.fit_transform(X)
X_val = scaler.transform(X_val)
现在,让我们训练一些最先进的机器学习模型,并将它们与我们的数据进行比较。
models = [LogisticRegression(), XGBClassifier(), SVC(kernel='rbf')]
for model in models:
model.fit(X, Y)
print(f'{model} : ')
print('Training Accuracy : ', metrics.roc_auc_score(Y, model.predict(X)))
print('Validation Accuracy : ', metrics.roc_auc_score(Y_val, model.predict(X_val)))
print()
5. 模型评估
从上述精度来看,我们可以说 Logistic Regression
和 SVC()
分类器在验证数据上表现更好,验证数据和训练数据之间的差异较小。让我们使用 Logistic
回归模型绘制验证数据的混淆矩阵。
metrics.plot_confusion_matrix(models[0], X_val, Y_val)
plt.show()