KNN模型决策边界与缩放后散点图不匹配问题求助
解决KNN决策边界与散点图尺度不匹配问题
问题背景
基于标准化数据开发带决策边界的KNN模型,给iris数据集新增代表物种颜色的列并分组,尝试分离不同物种。遇到两个问题:
- 初始代码生成的决策边界未覆盖所有散点
- 将DecisionBoundaryDisplay输入替换为降维后的X_embedded后,Voronoi决策边界与缩放后的散点图尺度不匹配
核心原因
- 初始代码中,决策边界基于原始高维特征生成,而散点图用的是NCA降维后的低维数据,维度不匹配导致边界无法覆盖散点。
- 改用X_embedded后,手动对散点做了
xs*scalex和ys*scaley缩放,但决策边界仍基于未缩放的X_embedded生成,两者尺度脱节。
修复后的完整代码
样本数据代码
import matplotlib.pyplot as plt import numpy as np import pandas as pd from sklearn import datasets from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.pipeline import make_pipeline from sklearn.neighbors import NeighborhoodComponentsAnalysis from sklearn.neighbors import KNeighborsClassifier n_neighbors = 3 random_state = 0 iris = datasets.load_iris() # 生成额外颜色列并打乱 p = np.tile(np.array([1, 2, 3, 4, 5]), 30) np.random.shuffle(p) # 构造数据集并分组 ir = pd.DataFrame(iris.data) ir[4] = p ir[5] = iris.target # 按颜色列分组,X取前4个特征,y取target X = ir.iloc[:, 0:5].groupby(by=4).apply(lambda x: np.delete(x.values, 4, axis=1)) y = ir.iloc[:, 4:6].groupby(by=4).apply(lambda x: np.delete(x.values, 0, axis=1)) testData(X, y, size=[2, 2])
绘图算法代码
from sklearn.inspection import DecisionBoundaryDisplay from typing import List def testData(X, y, size: List[int]): f, axarr = plt.subplots(size[0], size[1], figsize=(8, 8)) # 构建降维管道:标准化 + NCA降维到2维 model = make_pipeline( StandardScaler(), NeighborhoodComponentsAnalysis(n_components=2, random_state=random_state), ) knn = KNeighborsClassifier(n_neighbors=n_neighbors) for axs, (k, v), (ks, vl) in zip(axarr.flat, X.items(), y.items()): # 分割训练测试集 X_train, X_test, y_train, y_test = train_test_split( v, vl, test_size=0.5, stratify=vl, random_state=random_state ) try: # 拟合降维模型 model.fit(X_train, y_train.ravel()) except Exception as e: print(f"分组{k}拟合失败: {e}") continue # 对训练数据降维后训练KNN X_train_embedded = model.transform(X_train) knn.fit(X_train_embedded, y_train.ravel()) # 计算测试集准确率 acc_knn = knn.score(model.transform(X_test), y_test) print(f"分组{k} KNN准确率: {acc_knn:.2f}") # 对全量数据降维 X_embedded = model.transform(v) xs = X_embedded[:, 0] ys = X_embedded[:, 1] # 基于降维后的X_embedded生成决策边界 DecisionBoundaryDisplay.from_estimator( knn, X_embedded, alpha=0.4, ax=axs, response_method="predict" ) # 直接用降维后的数据画散点,无需手动缩放 axs.scatter(xs, ys, c=vl, s=30, cmap="Set1", edgecolor='black') axs.set_title(f"Color Group {k}") plt.tight_layout() plt.show()
关键修改点
- 统一数据维度:决策边界和散点图都使用NCA降维后的
X_embedded,避免高维/低维数据不匹配的问题。 - 移除手动缩放:去掉
scalex和scaley的手动缩放逻辑,让决策边界和散点图共享同一尺度空间。 - 优化流程:提前计算
X_train_embedded,让代码逻辑更清晰;添加准确率打印和拟合异常提示,方便调试。
可选:若需缩放数据
如果确实需要对降维后的数据做缩放,可以在KNN前加StandardScaler,确保决策边界和散点用同一缩放后的数据:
# 修改KNN部分的代码 scaler = StandardScaler() X_train_embedded_scaled = scaler.fit_transform(X_train_embedded) knn.fit(X_train_embedded_scaled, y_train.ravel()) X_embedded_scaled = scaler.transform(X_embedded) # 决策边界用缩放后的X_embedded_scaled DecisionBoundaryDisplay.from_estimator( knn, X_embedded_scaled, alpha=0.4, ax=axs, response_method="predict" ) # 散点也用缩放后的数据 axs.scatter(X_embedded_scaled[:,0], X_embedded_scaled[:,1], c=vl, s=30, cmap="Set1", edgecolor='black')
内容的提问来源于stack exchange,提问作者joe_bill.dollar
相关产品推荐
相关产品推荐

