You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KNN模型决策边界与缩放后散点图不匹配问题求助

解决KNN决策边界与散点图尺度不匹配问题

问题背景

基于标准化数据开发带决策边界的KNN模型,给iris数据集新增代表物种颜色的列并分组,尝试分离不同物种。遇到两个问题:

  • 初始代码生成的决策边界未覆盖所有散点
  • 将DecisionBoundaryDisplay输入替换为降维后的X_embedded后,Voronoi决策边界与缩放后的散点图尺度不匹配

核心原因

  1. 初始代码中,决策边界基于原始高维特征生成,而散点图用的是NCA降维后的低维数据,维度不匹配导致边界无法覆盖散点。
  2. 改用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()

关键修改点

  1. 统一数据维度:决策边界和散点图都使用NCA降维后的X_embedded,避免高维/低维数据不匹配的问题。
  2. 移除手动缩放:去掉scalex和scaley的手动缩放逻辑,让决策边界和散点图共享同一尺度空间。
  3. 优化流程:提前计算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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 12:55:16