Python打卡第10天
2026/8/22 10:53:06 网站建设 项目流程

@浙大疏锦行

混淆矩阵对比:

指标对比:

特征贡献图:

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

importpandas as pd

importmath

importos

save_dir=r"D:\Desktop\Postgraduate\PythonStudy\Python打卡训练营\Python打卡训练营\day10 pic"

frompathlibimportPath

importmatplotlib.pyplot as plt

importnumpy as np

importseaborn as sns

fromsklearn.model_selectionimporttrain_test_split, cross_val_score

fromsklearn.preprocessingimportStandardScaler

fromsklearn.metricsimportconfusion_matrix, accuracy_score, precision_score, recall_score, f1_score

fromsklearn.svmimportSVC

fromsklearn.neighborsimportKNeighborsClassifier

fromsklearn.linear_modelimportLogisticRegression

fromsklearn.naive_bayesimportGaussianNB

fromsklearn.treeimportDecisionTreeClassifier

fromsklearn.ensembleimportRandomForestClassifier

fromxgboostimportXGBClassifier

fromlightgbmimportLGBMClassifier

importwarnings

warnings.filterwarnings("ignore")

plt.rcParams['font.sans-serif']=['SimHei','Microsoft YaHei']# 优先黑体,备选微软雅黑

plt.rcParams['axes.unicode_minus']=False# 解决坐标轴负号显示方框问题

data=pd.read_csv(r"D:\Desktop\Postgraduate\PythonStudy\Python打卡训练营\Python打卡训练营\python60-days-challenge-master\heart.csv")

print(data.info())

col_map={

"age":"年龄",

"sex":"性别",

"cp":"胸痛类型",

"trestbps":"静息血压",

"chol":"血清胆固醇",

"fbs":"空腹血糖是否>120mg/dl",

"restecg":"静息心电图结果",

"thalach":"最大心率",

"exang":"运动是否诱发心绞痛",

"oldpeak":"ST段压低程度",

"slope":"ST段峰值斜率",

"ca":"荧光染色血管数量",

"thal":"地中海贫血",

"target":"是否患心脏病"

}

data.rename(columns=col_map, inplace=True)

print(data.head())

discrete_cols=[

"性别",

"胸痛类型",

"空腹血糖是否>120mg/dl",

"静息心电图结果",

"运动是否诱发心绞痛",

"ST段峰值斜率",

"荧光染色血管数量",

"地中海贫血"

]

target_col=["是否患心脏病"]

continuous_cols=[]

continuous_cols=[colforcolindata.columnsifcolnotindiscrete_cols+target_col]

# ====================== 1. 划分特征标签 + 固定种子拆分数据集 ======================

# 提取特征与标签,标签转为一维数组避免API警告

X=data.drop(columns=target_col)

y=data[target_col].values.ravel()

# 固定随机种子42,分层抽样保证训练/测试集类别比例一致

X_train, X_test, y_train, y_test=train_test_split(

X, y, test_size=0.2, random_state=42, stratify=y

)

print(f"训练集样本量:{len(X_train)},测试集样本量:{len(X_test)}")

# ====================== 2. 连续特征IQR异常值处理(缩尾法,不丢失样本) ======================

# 仅用训练集统计分位数,再应用到测试集,杜绝数据泄露

defiqr_winsorize(train_df, test_df, cols_list):

train_df=train_df.copy()

test_df=test_df.copy()

forcolincols_list:

Q1=train_df[col].quantile(0.25)

Q3=train_df[col].quantile(0.75)

IQR=Q3-Q1

upper_bound=Q3+1.5*IQR

lower_bound=Q1-1.5*IQR

# 超出上下限的值截断到边界,即箱线图缩尾处理

train_df[col]=train_df[col].clip(lower=lower_bound, upper=upper_bound)

test_df[col]=test_df[col].clip(lower=lower_bound, upper=upper_bound)

returntrain_df, test_df

X_train, X_test=iqr_winsorize(X_train, X_test, continuous_cols)

print("连续特征IQR异常值缩尾处理完成")

# ====================== 3. 连续特征标准化(SVM/KNN/LR对量纲敏感,树模型无影响) ======================

scaler=StandardScaler()

# 仅对连续特征标准化,离散分类特征保持原值

X_train[continuous_cols]=scaler.fit_transform(X_train[continuous_cols])

X_test[continuous_cols]=scaler.transform(X_test[continuous_cols])

# ====================== 4. 定义8个对比模型 ======================

models={

"SVM": SVC(random_state=42),

"KNN": KNeighborsClassifier(),

"逻辑回归": LogisticRegression(random_state=42, max_iter=1000),

"朴素贝叶斯": GaussianNB(),

"决策树": DecisionTreeClassifier(random_state=42),

"随机森林": RandomForestClassifier(random_state=42),

"XGBoost": XGBClassifier(random_state=42, use_label_encoder=False, eval_metric="logloss"),

"LightGBM": LGBMClassifier(random_state=42, verbose=-1)

}

# ====================== 5. 交叉验证 + 模型训练 + 指标计算 ======================

result_list=[]# 存储评估指标

cm_dict={}# 存储混淆矩阵

label_names=["无心脏病","有心脏病"]# 0=无病,1=患病

print("\n"+"="*60)

print("各模型5折交叉验证(训练集加权F1)与测试集结果")

print("="*60)

formodel_name, modelinmodels.items():

# 训练集5折交叉验证,评估指标为加权F1

cv_f1=cross_val_score(model, X_train, y_train, cv=5, scoring="f1_weighted").mean()

# 全量训练集拟合模型

model.fit(X_train, y_train)

y_pred=model.predict(X_test)

# 计算测试集四大核心指标

acc=accuracy_score(y_test, y_pred)

precision=precision_score(y_test, y_pred, average="weighted")

recall=recall_score(y_test, y_pred, average="weighted")

f1=f1_score(y_test, y_pred, average="weighted")

# 保存结果

result_list.append({

"模型名称": model_name,

"交叉验证平均F1":round(cv_f1,4),

"测试集准确率":round(acc,4),

"测试集精确率":round(precision,4),

"测试集召回率":round(recall,4),

"测试集F1分数":round(f1,4)

})

cm_dict[model_name]=confusion_matrix(y_test, y_pred)

print(f"{model_name:8s} | 交叉验证F1: {cv_f1:.4f} | 测试集F1: {f1:.4f}")

# ====================== 6. 评估指标对比表格(按F1降序) ======================

result_df=pd.DataFrame(result_list).sort_values(by="测试集F1分数", ascending=False).reset_index(drop=True)

print("\n"+"="*80)

print("所有模型测试集评估指标汇总(按F1分数从高到低排序)")

print("="*80)

print(result_df.to_string(index=False))

# ====================== 7. 混淆矩阵总图(2行4列子图) ======================

fig, axes=plt.subplots(2,4, figsize=(22,10))

axes=axes.flatten()# 把二维数组展平,方便循环遍历

foridx, (name, cm)inenumerate(cm_dict.items()):

sns.heatmap(

cm, annot=True, fmt="d", cmap="Blues", ax=axes[idx],

xticklabels=label_names, yticklabels=label_names,

annot_kws={"size":14}

)

axes[idx].set_title(f"{name} 混淆矩阵", fontsize=14, pad=10)

axes[idx].set_xlabel("预测结果", fontsize=12)

axes[idx].set_ylabel("真实结果", fontsize=12)

plt.tight_layout()

plt.savefig(os.path.join(save_dir,"confusion_matrix_all.png"), dpi=300, bbox_inches="tight")

plt.show()

# ====================== 8. 输出F1分数最高的模型 ======================

best_row=result_df.iloc[0]

print("\n"+"="*60)

print(f"✅ 测试集F1分数最高的模型:{best_row['模型名称']}")

print(f" 对应F1得分为:{best_row['测试集F1分数']}")

print(f" 交叉验证平均F1:{best_row['交叉验证平均F1']}")

print("="*60)

# ====================== 补充:各模型特征重要性/系数对比 ======================

# 提取特征名称列表

feature_names=X_train.columns.tolist()

# 1. 可输出特征重要性的模型(树模型 + 逻辑回归)

importance_models={

"逻辑回归": models["逻辑回归"],

"决策树": models["决策树"],

"随机森林": models["随机森林"],

"XGBoost": models["XGBoost"],

"LightGBM": models["LightGBM"]

}

# 2. 绘制特征重要性对比图(2行3列)

fig, axes=plt.subplots(2,3, figsize=(24,14))

axes=axes.flatten()

foridx, (name, model)inenumerate(importance_models.items()):

ifname=="逻辑回归":

# 线性模型取系数绝对值作为重要性

importance=np.abs(model.coef_[0])

title_suffix="(系数绝对值)"

else:

# 树模型取feature_importances_

importance=model.feature_importances_

title_suffix="(特征重要性)"

# 按重要性降序排序

sorted_idx=np.argsort(importance)[::-1]

sorted_features=[feature_names[i]foriinsorted_idx]

sorted_values=importance[sorted_idx]

# 绘制横向柱状图

sns.barplot(x=sorted_values, y=sorted_features, ax=axes[idx], palette="viridis")

axes[idx].set_title(f"{name} 特征贡献度{title_suffix}", fontsize=14, pad=10)

axes[idx].set_xlabel("重要性数值", fontsize=12)

axes[idx].set_ylabel("特征名称", fontsize=12)

# 最后一个子图放SVM和KNN的说明(无直接特征重要性)

axes[-1].axis("off")

axes[-1].text(0.5,0.5,

"SVM / KNN / 朴素贝叶斯\n无原生特征重要性输出\nSVM可通过线性核系数查看\nKNN为距离投票无特征权重",

ha="center", va="center", fontsize=14, linespacing=2)

axes[-1].set_title("无特征重要性的模型", fontsize=14, pad=10)

plt.tight_layout()

plt.savefig(os.path.join(save_dir,"feature_importance_all.png"), dpi=300, bbox_inches="tight")

plt.show()

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询