1、引言
本文涵盖主题:变量分析、数据分析、数据准备与特征工程、KNN-随机森林-SVM三种算法默认参数与网格搜索优化超参数6种方法进行对分类、总结六个部分。
本实验所使用数据包含影响预测的各种信息,如年龄、性别、血压、胆固醇水平、钠钾比和最后的药物类型。
本文主要结果汇总仪表板:
本期内容『数据+代码』已上传百度网盘。有需要的朋友可以关注公众号【小Z的科研日常】,后台回复关键词[多分类]获取。
2、变量分析
特征Age
对Age变量进行统计分析,观察Age变量在数据集中的最大最小值:
print("Max Age:", df.Age.max()) print("Min Age:", df.Age.min())
可观察到:
-
Max Age: 74
-
Min Age: 15
对年龄分布进行可视化:
# 设置绘图风格和颜色方案
sns.set_style('whitegrid')
colors = ['#FFB6C1', '#87CEFA', '#FFE4E1'] # 粉红色、天蓝色、粉色
sns.set_palette(colors)
# 创建画布并设置大小
fig, ax = plt.subplots(figsize=(8, 6))
# 绘制数据分布图,并设置透明度和线宽
sns.kdeplot(df['Age'], alpha=0.8, lw=3, shade=True, ax=ax)
# 配置坐标轴标签和标题,并设置字体大小和样式
ax.set_xlabel('Age', fontsize=20, fontweight='bold', color='k')
ax.set_ylabel('Density ', fontsize=20, fontweight='bold', color='k')
ax.set_title('Distribution of Age', fontsize=24, fontweight='bold', color='k')
# 调整刻度尺的字体大小和样式
for tick in ax.xaxis.get_major_ticks():
tick.label.set_fontsize(16)
tick.label.set_fontweight('bold')
tick.label.set_color('k')
for tick in ax.yaxis.get_major_ticks():
tick.label.set_fontsize(16)
tick.label.set_fontweight('bold')
tick.label.set_color('k')
# 显示图像
plt.show()
由上图可知,年龄分布主要集中在15-74之间。
特征Drug
Drug共由5个类别特征,对其进行分类统计,并进行可视化:
print(df.Drug.value_counts())
# 统计每个 Drug 类别出现的频率
counts = df['Drug'].value_counts()
# 选择颜色
custom_palette = sns.color_palette('pastel', n_colors=5)
# 设置调色板
sns.set_palette(custom_palette)
# 绘制条形图
plt.figure(figsize=(9,5))
sns.barplot(x=counts.index, y=counts.values)
plt.xlabel('Drug')
plt.ylabel('Count')
plt.title('Distribution of Drug in the Dataset')
plt.show()
药物是目标列,可以观察到该特征数据分布不均。为了获得可靠的模型训练结果,可使用K折交叉验证以使模型更可靠。
其余变量分析同理,本文不在赘述。
3、数据分析(部分展示)
由于篇幅原因,此章节只展示部分内容,若需完整资料可通过公众号获取。
Age—-Drug
对不同年龄、Drug类型进行可视化分析:
plt.figure(figsize = (9,5))
sns.swarmplot(x = "Drug", y = "Age",data = df)
plt.legend(df.Drug.value_counts().index)
plt.title("Age -- Drug")
plt.show()
print("Minimum Age of DrugB",df.Age[df.Drug == "drugB"].min())
print("Maximum Age of DrugA",df.Age[df.Drug == "drugA"].max())
根据上图:药物B仅由51岁以上的人服用;药物A仅由50岁以下的人服用。
Sex—-Drug
统计不同药物中,男性、女性的分布,并对其进行可视化观察:
df_Sex_Drug = df.groupby(["Drug","Sex"]).size().reset_index(name = "Count")
print(df_Sex_Drug)
plt.figure(figsize = (9,5))
sns.barplot(x = "Drug",y="Count", hue = "Sex",data = df_Sex_Drug)
plt.title("Sex -- Drug")
plt.show()
添加图片注释,不超过 140 字(可选)
上图可知:男性得到药物A、B和药物C的机会比女性多。女性得到的DrugY比男性多,药物X对男性和女性来说似乎是一样的。根据上述图表,性别特征不是一个重要的分类特征。
BP—-Drug
与上述同理,先进行统计分析,其次进行可视化分析:
df_BP_Drug = df.groupby(["Drug","BP"]).size().reset_index(name = "Count")
plt.figure(figsize = (9,5))
sns.barplot(x = "Drug",y="Count", hue = "BP",data = df_BP_Drug)
plt.title("BP -- Drug")
plt.show()
上述分析表明,药物A和药物B只有高血压患者才能得到。血压低的人可以得到药物C。药物X是由高血压患者得到的。血压是分类的一个重要特征。
4、数据准备与特征工程
特征工程
经过上一章节的数据分析,如果Na_to_K数值大于15,则认定给予的药物是药物Y:
df['Na_to_K_Bigger_Than_15'] = [1 if i >=15.015 else 0 for i in df.Na_to_K]
df_NaK15 = df.groupby(["Drug","Na_to_K_Bigger_Than_15"]).size().reset_index(name = "Count")
plt.figure(figsize = (9,5))
sns.barplot(x = "Drug",y="Count", hue = "Na_to_K_Bigger_Than_15",data = df_NaK15)
plt.title("Na_to_K_Bigger_Than_15 -- Drug")
plt.show()
Na_to_K_Bigger_Than_15特征将是药物Y分类的重要特征。
标签编码
我们将非数值特征从对象转换为int64类型,以便后续进行模型训练:
from sklearn.preprocessing import LabelEncoder
def label_encoder(y):
le = LabelEncoder()
df[y] = le.fit_transform(df[y])
label_list = ["Sex","BP","Cholesterol","Na_to_K","Na_to_K_Bigger_Than_15","Drug"]
for l in label_list:
label_encoder(l)
训练、测试集划分
from sklearn.model_selection import train_test_split
x = df.drop(["Drug"],axis=1)
y = df.Drug
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size = 0.2, random_state = 42, shuffle = True)
y_train = y_train.values.reshape(-1,1)
y_test = y_test.values.reshape(-1,1)
print("x_train shape:",x_train.shape)
print("x_test shape:",x_test.shape)
print("y_train shape:",y_train.shape)
print("y_test shape:",y_test.shape)
5、模型建立
实验将尝试三种模型并比较它们的结果。对于所有的模型,采用GridSearchCV方法来寻找最佳分数。此外,为了确保模型性能是随机的,使用5折交叉验证方法。
KNN默认参数
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
accuracies = cross_val_score(knn, x_train, y_train, cv=5)
knn.fit(x_train,y_train)
print("Train Score:",np.mean(accuracies))
print("Test Score:",knn.score(x_test,y_test))
-
Train Score: 0.59375
-
Test Score: 0.65
GridSearchCV优化KNN
为了找到KNN模型的最佳得分,将尝试不同的n_neighbors、p和weights参数值:
grid = {'n_neighbors':np.arange(1,120),
'p':np.arange(1,3),
'weights':['uniform','distance']
}
knn = KNeighborsClassifier(algorithm = "auto")
knn_cv = GridSearchCV(knn,grid,cv=5)
knn_cv.fit(x_train,y_train)
print("Hyperparameters:",knn_cv.best_params_)
print("Train Score:",knn_cv.best_score_)
print("Test Score:",knn_cv.score(x_test,y_test))
-
Hyperparameters:{‘n_neighbors’:10, ‘p’: 1, ‘weights’: ‘distance’}
-
Train Score: 0.75625
-
Test Score: 0.7
随机森林默认参数
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(random_state = 42)
accuracies = cross_val_score(rfc, x_train, y_train, cv=5)
rfc.fit(x_train,y_train)
print("Train Score:",np.mean(accuracies))
print("Test Score:",rfc.score(x_test,y_test))
-
Train Score: 0.98125
-
Test Score: 0.975
GridSearchCV优化随机森林
为了找到随机森林模型的最佳得分,将尝试不同的n_estimators和标准参数的值。
grid = {'n_estimators':np.arange(100,1000,100),
'criterion':['gini','entropy']
}
rf = RandomForestClassifier(random_state = 42)
rf_cv = GridSearchCV(rf,grid,cv=5)
rf_cv.fit(x_train,y_train)
print("Hyperparameters:",rf_cv.best_params_)
print("Train Score:",rf_cv.best_score_)
print("Test Score:",rf_cv.score(x_test,y_test))
-
Hyperparameters:{‘criterion’:’entropy’,’n_estimators’: 100}
-
Train Score: 0.9875
-
Test Score: 0.975
SVM默认参数
from sklearn.svm import SVC
svc = SVC(random_state = 42)
accuracies = cross_val_score(svc, x_train, y_train, cv=5)
svc.fit(x_train,y_train)
print("Train Score:",np.mean(accuracies))
print("Test Score:",svc.score(x_test,y_test))
-
Train Score: 0.7125
-
Test Score: 0.65
GridSearchCV优化SVM
grid = {
'C':[0.01,0.1,1,10],
'kernel' : ["linear","poly","rbf","sigmoid"],
'degree' : [1,3,5,7],
'gamma' : [0.01,1]
}
svm = SVC ();
svm_cv = GridSearchCV(svm, grid, cv = 5)
svm_cv.fit(x_train,y_train)
print("Best Parameters:",svm_cv.best_params_)
print("Train Score:",svm_cv.best_score_)
print("Test Score:",svm_cv.score(x_test,y_test))
-
Best Parameters: {‘C’: 1, ‘degree’: 1, ‘gamma’: 0.01, ‘kernel’: ‘linear’}
-
Train Score: 0.9875
-
Test Score: 0.975
6、总结
对上述六种方法得分进行总结与可视化:
经上述分析与图表观察,随机森林算法和SVM算法(经过超参数调整)分类效果最佳。