# 第一个代码:KNN 鸢尾花分类
使用 sklearn
库
# 基础库 | |
import matplotlib.pyplot as plt | |
import matplotlib | |
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] | |
matplotlib.rcParams['axes.unicode_minus'] = False | |
# sklearn 模块 | |
from sklearn import datasets | |
from sklearn.model_selection import train_test_split | |
from sklearn.preprocessing import StandardScaler | |
from sklearn.neighbors import KNeighborsClassifier | |
from sklearn.metrics import accuracy_score, confusion_matrix | |
# 加载内置数据集(鸢尾花) | |
iris = datasets.load_iris() | |
X = iris.data # 特征 (150 个样本 x 4 个特征) | |
y = iris.target # 标签 (0,1,2 对应三种花) | |
# 查看数据 | |
print("特征名:", iris.feature_names) | |
print("标签名:", iris.target_names) | |
# 划分训练集 / 测试集 (70% 训练,30% 测试) | |
X_train, X_test, y_train, y_test = train_test_split( | |
X, y, test_size=0.3, random_state=42 | |
) | |
# 特征标准化(重要!) | |
scaler = StandardScaler() | |
X_train = scaler.fit_transform(X_train) | |
X_test = scaler.transform(X_test) # 注意:使用相同的 scaler 转换 | |
# 初始化 KNN 分类器(k=3) | |
model = KNeighborsClassifier(n_neighbors=3) | |
# 训练模型 | |
model.fit(X_train, y_train) | |
# 预测测试集 | |
y_pred = model.predict(X_test) | |
# 计算准确率 | |
accuracy = accuracy_score(y_test, y_pred) | |
print(f"模型准确率: {accuracy:.2%}") | |
# 混淆矩阵(可视化错误) | |
cm = confusion_matrix(y_test, y_pred) | |
print("混淆矩阵:\n", cm) | |
# 选择两个特征进行二维可视化(可选) | |
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_pred, cmap='viridis', s=50) | |
plt.xlabel(iris.feature_names[0]) | |
plt.ylabel(iris.feature_names[1]) | |
plt.title("鸢尾花分类结果 (KNN)") | |
plt.colorbar(ticks=[0,1,2], label='花种类') | |
plt.show() |
这个代码是 ds 写的。
# 简要流程
# 1. 数据集引入与划分
- 需要导入特征与标签。以本代码为例,特征有四个维度,标签有三类:
特征名: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] | |
标签名: ['setosa' 'versicolor' 'virginica'] |
- 此外,还需要进行训练集与测试集的划分。我们使用
train_test_split
函数random_state
:机器学习中控制随机性的关键参数。核心作用:保证结果可复现性- 就相当于一个种子,你固定了这个种子,那它后面划分训练集与测试集就只会以这种方式划分。
# 2. 特征标准化
scaler = StandardScaler() # 创建标准化器 | |
X_train = scaler.fit_transform(X_train) # 训练并转换训练集 | |
X_test = scaler.transform(X_test) # 转换测试集(使用训练集的参数) |
- 中心化处理(Centering):
- 将每个特征的均值变为 0
- 计算公式:
x_new = (x - μ)
- 其中 μ 是特征的均值
- 缩放处理(Scaling):
- 将每个特征的标准差变为 1
- 计算公式:
x_new = (x - μ) / σ
- 其中 σ 是特征的标准差
标准化后的特征满足:
- 均值 = 0
- 标准差 = 1
- 分布形状不变(只是平移和缩放)
为什么需要标准化?
- 解决特征尺度不一致问题:
- 例如鸢尾花数据集中:
- 萼片长度:4.3-7.9 cm
- 萼片宽度:2.0-4.4 cm
- 若不标准化,范围大的特征会主导距离计算
- 例如鸢尾花数据集中:
- 提高算法性能:
- 基于距离的算法(KNN、SVM):避免大范围特征主导距离计算
- 基于梯度的算法(线性回归、神经网络):加速收敛,避免振荡
- 正则化模型:使正则化项对所有特征公平作用
- 提高数值稳定性:
- 防止计算中出现极大或极小的数值
- 减少浮点数计算误差
步骤分解:
1. scaler = StandardScaler()
- 创建一个标准化转换器对象
- 此时尚未计算任何统计量
2.X_train = scaler.fit_transform(X_train)
- 两步操作合二为一:
fit()
:计算训练集的统计量- 计算每个特征的均值 (μ) 和标准差 (σ)
- 公式:
transform()
:应用转换- 对每个特征值:
- 转换后:每个特征的均值 = 0,标准差 = 1
3.X_test = scaler.transform(X_test)
- 仅使用训练集计算的参数:
- 使用训练集计算出的 μ 和 σ
- 不对测试集重新计算统计量(根本原因:防止数据泄露)
# 3. 模型训练
model = KNeighborsClassifier(n_neighbors=3) | |
model.fit(X_train, y_train) |
- 作用:创建 KNN 分类器并训练模型
- 对应环节:模型训练
- 关键点:
- KNN 算法原理:根据最近邻的 K 个样本投票决定分类
n_neighbors=3
是超参数(可调整)fit()
方法学习训练数据的特征模式
# 4. 模型评估
- 作用:评估模型在未知数据上的表现
- 对应环节:模型评估
- 关键点:
- 准确率 = 正确预测数 / 总样本数
- 混淆矩阵显示:
- 行:真实类别
- 列:预测类别
- 对角线:正确分类的样本
比如:
预测类别 | |
类0 类1 类2 | |
真 类0 [ 19, 0, 0 ] | |
实 类1 [ 0, 13, 0 ] | |
类 类2 [ 0, 0, 13 ] |
# 第二个代码:乳腺癌判断
还是 ds 写的代码。
# === 1. 导入库 ===import numpy as np | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
import matplotlib | |
# 设置中文字体 | |
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] | |
matplotlib.rcParams['axes.unicode_minus'] = False | |
from sklearn.datasets import load_breast_cancer | |
from sklearn.model_selection import train_test_split, cross_val_score | |
from sklearn.preprocessing import StandardScaler | |
from sklearn.svm import SVC | |
from sklearn.naive_bayes import GaussianNB # PGM 的代表(朴素贝叶斯) | |
from sklearn.tree import DecisionTreeClassifier, plot_tree | |
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report | |
from mlxtend.plotting import plot_decision_regions # 决策边界可视化 | |
# === 2. 加载和探索数据 ===data = load_breast_cancer () # 数据集 | |
X = data.data # 特征 | |
y = data.target # 标签 | |
feature_names = data.feature_names # 特征名 | |
target_names = data.target_names # 标签名 | |
print(f"数据集形状: {X.shape}") | |
print(f"特征数: {len(feature_names)}") | |
print(f"类别分布: {np.bincount(y)} (0={target_names[0]}, 1={target_names[1]})") | |
# 创建 DataFrame 便于分析 | |
df = pd.DataFrame(X, columns=feature_names) # | |
df['target'] = y | |
print("\n特征统计信息:") | |
print(df.describe()) | |
# === 3. 数据预处理 ===# 划分训练集 / 测试集 | |
# stratify=y 表示在划分数据时保持每个类别的比例与原数据集一致 | |
X_train, X_test, y_train, y_test = train_test_split( | |
X, y, test_size=0.2, random_state=42, stratify=y | |
) | |
# 特征标准化 | |
scaler = StandardScaler() | |
X_train_scaled = scaler.fit_transform(X_train) | |
X_test_scaled = scaler.transform(X_test) | |
# 选择两个主要特征进行可视化 (平均半径和平均纹理) | |
X_train_vis = X_train_scaled[:, :2] # 前两个特征 | |
X_test_vis = X_test_scaled[:, :2] | |
# === 4. 训练多种模型 ===# 向量机,朴素贝叶斯,决策树 | |
models = { | |
"SVM": SVC(kernel='rbf', C=1.0, gamma='scale', probability=True, random_state=42), | |
"Naive Bayes (PGM)": GaussianNB(), | |
"Decision Tree": DecisionTreeClassifier(max_depth=3, random_state=42) | |
} | |
# 训练并评估每个模型 | |
results = {} | |
for name, model in models.items(): | |
# 训练模型 | |
model.fit(X_train_scaled, y_train) | |
# 预测 | |
y_pred = model.predict(X_test_scaled) | |
# 评估 | |
accuracy = accuracy_score(y_test, y_pred) | |
cm = confusion_matrix(y_test, y_pred) | |
report = classification_report(y_test, y_pred, target_names=target_names) | |
# 存储结果 | |
results[name] = { | |
'model': model, | |
'accuracy': accuracy, | |
'confusion_matrix': cm, | |
'report': report | |
} | |
# 交叉验证 | |
cv_scores = cross_val_score(model, X_train_scaled, y_train, cv=5) | |
print(f"\n=== {name} ===") | |
print(f"测试集准确率: {accuracy:.2%}") | |
print(f"5折交叉验证平均准确率: {np.mean(cv_scores):.2%} ± {np.std(cv_scores):.2%}") | |
print("分类报告:\n", report) | |
# === 5. 可视化比较 ===plt.figure (figsize=(18, 12)) | |
# 绘制决策边界 | |
for i, (name, result) in enumerate(results.items(), 1): | |
model = result['model'] | |
# 为可视化重新训练只使用前 2 个特征的模型 | |
if name == "SVM": | |
model_vis = SVC(kernel='rbf', C=1.0, gamma='scale', probability=True, random_state=42) | |
model_vis.fit(X_train_vis, y_train) | |
elif name == "Naive Bayes (PGM)": | |
model_vis = GaussianNB() | |
model_vis.fit(X_train_vis, y_train) | |
elif name == "Decision Tree": | |
model_vis = DecisionTreeClassifier(max_depth=3, random_state=42) | |
model_vis.fit(X_train_vis, y_train) | |
plt.subplot(2, 3, i) | |
plot_decision_regions(X_train_vis, y_train, clf=model_vis, legend=2) | |
plt.title(f"{name} 决策边界") | |
plt.xlabel(feature_names[0]) | |
plt.ylabel(feature_names[1]) | |
# 添加测试集点 | |
plt.scatter(X_test_vis[:, 0], X_test_vis[:, 1], c=y_test, | |
edgecolors='k', alpha=0.7, marker='o', s=80, | |
cmap=plt.cm.coolwarm, label='测试集') | |
# 绘制决策树结构 | |
plt.subplot(2, 3, 4) | |
plot_tree(models["Decision Tree"], | |
feature_names=feature_names, | |
class_names=target_names, | |
filled=True, rounded=True, | |
fontsize=10) | |
plt.title("决策树结构") | |
# 绘制特征重要性 (决策树) | |
plt.subplot(2, 3, 5) | |
tree_model = models["Decision Tree"] | |
importances = tree_model.feature_importances_ | |
indices = np.argsort(importances)[::-1][:10] # 取前 10 个重要特征 | |
plt.barh(range(len(indices)), importances[indices], align='center') | |
plt.yticks(range(len(indices)), [feature_names[i] for i in indices]) | |
plt.xlabel('特征重要性') | |
plt.title('决策树 - 特征重要性 (Top 10)') | |
# 绘制 SVM 支持向量 | |
plt.subplot(2, 3, 6) | |
svm_model = models["SVM"] | |
plt.scatter(X_train_scaled[:, 0], X_train_scaled[:, 1], c=y_train, cmap=plt.cm.coolwarm, s=30) | |
plt.scatter(svm_model.support_vectors_[:, 0], svm_model.support_vectors_[:, 1], | |
s=100, facecolors='none', edgecolors='k', label='支持向量') | |
plt.title("SVM支持向量") | |
plt.xlabel(feature_names[0]) | |
plt.ylabel(feature_names[1]) | |
plt.legend() | |
plt.tight_layout() | |
plt.show() | |
# === 6. 模型比较总结 ===print ("\n=== 模型性能总结 ===") | |
for name, result in results.items(): | |
print(f"{name}: 准确率 = {result['accuracy']:.2%}") |
几个注意点:
# 数据集构成
print(f"数据集形状: {X.shape}") | |
print(f"特征数: {len(feature_names)}") | |
print(f"类别分布: {np.bincount(y)} (0={target_names[0]}, 1={target_names[1]})") |
数据集形状: (569, 30)
表示该数据集共有 569 条样本,每条样本有 30 个特征。类别分布: [212 357]
表示分类结果的分布情况:
0
(恶性肿瘤):212 例1
(良性肿瘤):357 例
# dataframe 表示
# 创建 DataFrame 便于分析 | |
df = pd.DataFrame(X, columns=feature_names) # | |
df['target'] = y | |
print("\n特征统计信息:") | |
print(df.describe()) |
DataFrame 结构
df = pd.DataFrame( | |
data=X, # 原始数据矩阵 | |
columns=feature_names # 列名称列表 | |
) |
- 结果:创建一个二维表格
- 行:每个样本(569 行)
- 列:每个特征(30 列)
df['target'] = y # y是标签向量
- 添加新列 'target'
- 包含每个样本的类别标签(0 = 恶性,1 = 良性)
结果 DataFrame 示例:
mean radius | mean texture | ... | worst fractal dimension | target |
---|---|---|---|---|
17.99 | 10.38 | ... | 0.1189 | 0 |
20.57 | 17.77 | ... | 0.0890 | 0 |
19.69 | 21.25 | ... | 0.0876 | 0 |
... | ... | ... | ... | ... |
7.76 | 24.54 | ... | 0.0703 | 1 |
统计分析功能: print(df.describe())
describe()
生成描述性统计信息,包括:
- count: 非缺失值数量
- mean: 平均值
- std: 标准差
- min: 最小值
- 25%: 第一四分位数
- 50%: 中位数
- 75%: 第三四分位数
- max: 最大值
describe () 输出示例:
mean radius mean texture ... worst fractal dimension target | |
count 569.000000 569.000000 ... 569.000000 569.0000 | |
mean 14.127292 19.289649 ... 0.083946 0.6274 | |
std 3.524049 4.301036 ... 0.018061 0.4839 | |
min 6.981000 9.710000 ... 0.055040 0.0000 | |
25% 11.700000 16.170000 ... 0.071460 0.0000 | |
50% 13.370000 18.840000 ... 0.080040 1.0000 | |
75% 15.780000 21.800000 ... 0.092080 1.0000 | |
max 28.110000 39.280000 ... 0.207500 1.0000 |
列是特征,行代表由 569 个样本算出来的各个指标。
# 数据预处理
# === 3. 数据预处理 ===# 划分训练集 / 测试集 | |
# stratify=y 表示在划分数据时保持每个类别的比例与原数据集一致 | |
X_train, X_test, y_train, y_test = train_test_split( | |
X, y, test_size=0.2, random_state=42, stratify=y | |
) | |
# 特征标准化 | |
scaler = StandardScaler() | |
X_train_scaled = scaler.fit_transform(X_train) | |
X_test_scaled = scaler.transform(X_test) | |
# 选择两个主要特征进行可视化 (平均半径和平均纹理) | |
X_train_vis = X_train_scaled[:, :2] # 前两个特征 | |
X_test_vis = X_test_scaled[:, :2] |
- stratify 是用于分层抽样的参数
- 使用 stratify=y 后,训练集和测试集中恶性 / 良性肿瘤的比例会保持与原始数据集相同
- 这有助于避免因随机划分导致的类别分布偏差,尤其适用于不平衡数据集
- 例如:如果原始数据集中有 60% 的良性样本,在测试集中也会保持大约 60% 的良性样本
X_train_vis = X_train_scaled[:, :2] # 前两个特征
X_test_vis = X_test_scaled[:, :2]
这两行代码的作用是: 从标准化后的训练集和测试集特征中,只选取前两个特征(即 “平均半径” 和 “平均纹理”),
用于后续的二维可视化(比如决策边界图)。 这样做可以让模型在二维空间中展示分类效果,便于直观观察和比较不同算法的决策边界。
# 模型训练
# 向量机,朴素贝叶斯,决策树 | |
models = { | |
"SVM": SVC(kernel='rbf', C=1.0, gamma='scale', probability=True, random_state=42), | |
"Naive Bayes (PGM)": GaussianNB(), | |
"Decision Tree": DecisionTreeClassifier(max_depth=3, random_state=42) | |
} |
这里定义了三个模型及其参数,具体解释如下:
SVC(kernel='rbf', C=1.0, gamma='scale', probability=True, random_state=42)
kernel='rbf'
:使用径向基函数(高斯核)作为核函数,适合非线性分类。C=1.0
:正则化参数,控制误差容忍度,值越大越倾向于拟合训练集。gamma='scale'
:核函数的系数,自动根据特征数和方差调整。probability=True
:支持概率输出(如predict_proba
方法)。random_state=42
:随机种子,保证结果可复现。
GaussianNB()
- 朴素贝叶斯分类器,假设特征服从高斯分布。无特殊参数,默认设置即可。
DecisionTreeClassifier(max_depth=3, random_state=42)
max_depth=3
:决策树最大深度,限制树的复杂度,防止过拟合。random_state=42
:随机种子,保证结果可复现。
# 模型评估
# 评估 | |
accuracy = accuracy_score(y_test, y_pred) | |
cm = confusion_matrix(y_test, y_pred) | |
report = classification_report(y_test, y_pred, target_names=target_names) | |
# 存储结果 | |
results[name] = { | |
'model': model, | |
'accuracy': accuracy, | |
'confusion_matrix': cm, | |
'report': report | |
} | |
# 交叉验证 | |
cv_scores = cross_val_score(model, X_train_scaled, y_train, cv=5) | |
print(f"\n=== {name} ===") | |
print(f"测试集准确率: {accuracy:.2%}") | |
print(f"5折交叉验证平均准确率: {np.mean(cv_scores):.2%} ± {np.std(cv_scores):.2%}") | |
print("分类报告:\n", report) |
# 准确率 (Accuracy)
accuracy = accuracy_score(y_test, y_pred)
- 公式:正确预测数 / 总样本数
- 含义:模型整体预测正确的比例
- 解读:
- 值范围:0.0(全错)~ 1.0(全对)
- 在乳腺癌数据集中,98.25% 准确率表示 100 个样本中有 98 个被正确分类
- 优点:直观易懂
- 局限:在类别不平衡数据中可能误导(如 99% 负样本,模型全预测负也有 99% 准确率)
# 混淆矩阵 (Confusion Matrix)
cm = confusion_matrix(y_test, y_pred)
上面讲过了,略
# 分类报告 (Classification Report)
report = classification_report(y_test, y_pred, target_names=target_names)
输出三个核心指标(按类别计算):
a) 精确率 (Precision)
- 公式:TP / (TP + FP)
- 含义:预测为正的样本中,实际为正的比例
- 业务意义:减少误报(如减少健康人被误诊为癌症)
b) 召回率 (Recall / 灵敏度)
- 公式:TP / (TP + FN)
- 含义:实际为正的样本中,被正确预测的比例
- 业务意义:减少漏诊(如确保癌症患者不被漏诊)
c) F1 分数
- 公式:2 × (Precision × Recall) / (Precision + Recall)
- 含义:精确率和召回率的调和平均
- 特点:综合衡量模型性能,特别适合不平衡数据
d) 分类报告示例输出
precision recall f1-score support | |
malignant 0.98 0.96 0.97 47 | |
benign 0.97 0.99 0.98 67 | |
accuracy 0.98 114 | |
macro avg 0.98 0.97 0.97 114 | |
weighted avg 0.98 0.98 0.98 114 |
解读
- 恶性类别 (malignant):
- 精确率 98%:预测为恶性的样本中 98% 确实恶性
- 召回率 96%:真实恶性样本有 96% 被正确识别
- F1 分数 97%:综合表现优秀
- 良性类别 (benign):
- 精确率 97%:预测良性的样本 97% 正确
- 召回率 99%:真实良性样本 99% 被正确识别
- 整体统计:
accuracy
:总体准确率 98%macro avg
:各类别指标的简单平均weighted avg
:按样本量加权的平均
support
这一列代表的是每个类别在测试集中实际的样本数量。accuracy
的 0.98 与列无关,展示的整体的准确率
# 交叉验证 (Cross Validation)
cv_scores = cross_val_score(model, X_train_scaled, y_train, cv=5)
print(f"5折交叉验证平均准确率: {np.mean(cv_scores):.2%} ± {np.std(cv_scores):.2%}")
- 原理:将训练集分成 5 份,轮流用 4 份训练,1 份验证,重复 5 次
- 输出:
- 平均准确率:模型性能的稳定估计
- 标准差:模型性能的波动范围
- 重要性:
- 减少因单次数据分割带来的随机性
- 检测模型是否过拟合
- 比单次测试集评估更可靠
- 解读示例:
- "97.59% ± 0.82%" 表示:
- 平均准确率 97.59%
- 波动范围在 ±0.82% 之间 → 模型稳定
- "97.59% ± 0.82%" 表示: