Python案例如何用Scikit-learn做KNN分类

wen python案例 2

本文目录导读:

Python案例如何用Scikit-learn做KNN分类

  1. 基础KNN分类示例(鸢尾花数据集)
  2. K值选择与评估
  3. 数据标准化与KNN
  4. 距离度量方式比较
  5. 权重策略比较
  6. 实战:手写数字识别
  7. 网格搜索调参
  8. 决策边界可视化

我来为你详细介绍如何使用Scikit-learn实现KNN(K-Nearest Neighbors)分类,包含多个实际案例。

基础KNN分类示例(鸢尾花数据集)

# 导入必要的库
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)
# 创建KNN分类器(k=3)
knn = KNeighborsClassifier(n_neighbors=3)
# 训练模型
knn.fit(X_train, y_train)
# 预测
y_pred = knn.predict(X_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print(f"准确率: {accuracy:.2f}")
# 详细分类报告
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=iris.target_names))
# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)
print("混淆矩阵:")
print(cm)
# 可视化混淆矩阵
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
            xticklabels=iris.target_names, 
            yticklabels=iris.target_names)'混淆矩阵 - KNN分类')
plt.ylabel('真实标签')
plt.xlabel('预测标签')
plt.show()

K值选择与评估

from sklearn.model_selection import cross_val_score
# 测试不同的K值
k_range = range(1, 31)
k_scores = []
k_scores_std = []
for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    # 使用交叉验证评估
    scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy')
    k_scores.append(scores.mean())
    k_scores_std.append(scores.std())
# 找到最优K值
optimal_k = k_range[np.argmax(k_scores)]
optimal_score = max(k_scores)
print(f"最优K值: {optimal_k}")
print(f"最优准确率: {optimal_score:.4f}")
# 可视化K值与准确率的关系
plt.figure(figsize=(10, 6))
plt.errorbar(k_range, k_scores, yerr=k_scores_std, marker='o')
plt.xlabel('K值')
plt.ylabel('交叉验证准确率')'K值对KNN分类性能的影响')
plt.grid(True, alpha=0.3)
plt.show()

数据标准化与KNN

from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# 创建包含标准化的Pipeline
knn_pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('knn', KNeighborsClassifier(n_neighbors=5))
])
# 训练和评估
knn_pipeline.fit(X_train, y_train)
y_pred_scaled = knn_pipeline.predict(X_test)
accuracy_scaled = accuracy_score(y_test, y_pred_scaled)
print(f"标准化后的准确率: {accuracy_scaled:.4f}")
# 对比有无标准化的效果
# 未标准化
knn_no_scale = KNeighborsClassifier(n_neighbors=5)
knn_no_scale.fit(X_train, y_train)
y_pred_no_scale = knn_no_scale.predict(X_test)
accuracy_no_scale = accuracy_score(y_test, y_pred_no_scale)
print(f"未标准化的准确率: {accuracy_no_scale:.4f}")

距离度量方式比较

# 测试不同的距离度量方式
distance_metrics = ['euclidean', 'manhattan', 'chebyshev', 'minkowski']
results = {}
for metric in distance_metrics:
    knn = KNeighborsClassifier(n_neighbors=5, metric=metric)
    if metric == 'minkowski':
        # Minkowski距离需要指定p参数
        for p in [1, 2, 3]:
            knn = KNeighborsClassifier(n_neighbors=5, metric='minkowski', p=p)
            scores = cross_val_score(knn, X, y, cv=5, scoring='accuracy')
            results[f'{metric}(p={p})'] = scores.mean()
    else:
        scores = cross_val_score(knn, X, y, cv=5, scoring='accuracy')
        results[metric] = scores.mean()
print("不同距离度量的性能比较:")
for metric, score in results.items():
    print(f"{metric}: {score:.4f}")

权重策略比较

# 测试不同的权重策略
weight_strategies = ['uniform', 'distance']
weight_results = {}
for weight in weight_strategies:
    knn = KNeighborsClassifier(n_neighbors=5, weights=weight)
    scores = cross_val_score(knn, X, y, cv=5, scoring='accuracy')
    weight_results[weight] = scores.mean()
    print(f"权重策略 '{weight}' 的平均准确率: {scores.mean():.4f}")
# 可视化比较
plt.figure(figsize=(8, 5))
plt.bar(weight_results.keys(), weight_results.values())
plt.ylabel('准确率')'不同权重策略的性能比较')
plt.show()

实战:手写数字识别

from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
# 加载手写数字数据集
digits = load_digits()
X_digits, y_digits = digits.data, digits.target
# 数据集信息
print(f"数据集大小: {X_digits.shape}")
print(f"类别数量: {len(np.unique(y_digits))}")
# 划分数据集
X_train_d, X_test_d, y_train_d, y_test_d = train_test_split(
    X_digits, y_digits, test_size=0.2, random_state=42
)
# 使用PCA降维(可选)
pca = PCA(n_components=30)
X_train_pca = pca.fit_transform(X_train_d)
X_test_pca = pca.transform(X_test_d)
# 训练KNN模型
knn_digits = KNeighborsClassifier(n_neighbors=3, weights='distance')
knn_digits.fit(X_train_pca, y_train_d)
# 预测
y_pred_digits = knn_digits.predict(X_test_pca)
accuracy_digits = accuracy_score(y_test_d, y_pred_digits)
print(f"手写数字识别准确率: {accuracy_digits:.4f}")
# 显示一些预测结果
fig, axes = plt.subplots(2, 5, figsize=(12, 6))
axes = axes.ravel()
for i in range(10):
    axes[i].imshow(X_test_d[i].reshape(8, 8), cmap='gray')
    axes[i].set_title(f'真实: {y_test_d[i]}\n预测: {y_pred_digits[i]}')
    axes[i].axis('off')
plt.tight_layout()
plt.show()

网格搜索调参

from sklearn.model_selection import GridSearchCV
# 定义参数网格
param_grid = {
    'n_neighbors': [3, 5, 7, 9, 11],
    'weights': ['uniform', 'distance'],
    'metric': ['euclidean', 'manhattan', 'minkowski'],
    'p': [1, 2, 3]  # Minkowski距离的参数
}
# 创建KNN分类器
knn_grid = KNeighborsClassifier()
# 网格搜索
grid_search = GridSearchCV(
    knn_grid, 
    param_grid, 
    cv=5, 
    scoring='accuracy',
    n_jobs=-1,
    verbose=1
)
# 执行搜索
grid_search.fit(X_train, y_train)
# 输出最佳参数
print("最佳参数组合:")
for param, value in grid_search.best_params_.items():
    print(f"{param}: {value}")
print(f"\n最佳交叉验证准确率: {grid_search.best_score_:.4f}")
# 使用最佳模型预测
best_knn = grid_search.best_estimator_
y_pred_best = best_knn.predict(X_test)
accuracy_best = accuracy_score(y_test, y_pred_best)
print(f"测试集准确率: {accuracy_best:.4f}")

决策边界可视化

# 使用前两个特征进行可视化(为了方便展示)
X_vis = X[:, :2]
X_train_vis, X_test_vis, y_train_vis, y_test_vis = train_test_split(
    X_vis, y, test_size=0.3, random_state=42
)
# 训练KNN
knn_vis = KNeighborsClassifier(n_neighbors=5)
knn_vis.fit(X_train_vis, y_train_vis)
# 创建网格
x_min, x_max = X_vis[:, 0].min() - 1, X_vis[:, 0].max() + 1
y_min, y_max = X_vis[:, 1].min() - 1, X_vis[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))
# 预测网格点
Z = knn_vis.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 可视化
plt.figure(figsize=(12, 5))
# 决策边界
plt.subplot(1, 2, 1)
plt.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
plt.scatter(X_train_vis[:, 0], X_train_vis[:, 1], 
           c=y_train_vis, cmap=plt.cm.RdYlBu, 
           edgecolor='black', s=50)
plt.xlabel('特征1')
plt.ylabel('特征2')'KNN决策边界(训练集)')
# 测试集结果
plt.subplot(1, 2, 2)
plt.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
plt.scatter(X_test_vis[:, 0], X_test_vis[:, 1], 
           c=y_test_vis, cmap=plt.cm.RdYlBu, 
           edgecolor='black', s=50)
plt.xlabel('特征1')
plt.ylabel('特征2')'KNN决策边界(测试集)')
plt.tight_layout()
plt.show()
  1. K值选择:使用交叉验证找到最优K值
  2. 数据标准化:KNN对特征尺度敏感,需要标准化
  3. 距离度量:根据数据特点选择合适的距离度量
  4. 权重策略:考虑使用距离权重提高预测准确性
  5. 超参数调优:使用GridSearchCV找到最佳参数组合

这些案例涵盖了KNN分类的主要应用场景和调优技巧,可以根据实际需求选择合适的方法。

抱歉,评论功能暂时关闭!