Python 我是刚刚在sklearn KNN分类器中发现了一个bug,还是一切都按预期工作?

Python 我是刚刚在sklearn KNN分类器中发现了一个bug,还是一切都按预期工作?,python,scikit-learn,knn,kdtree,Python,Scikit Learn,Knn,Kdtree,我一直在玩弄python SKK近邻分类器,我相信它不会正常工作——k大于1的结果是错误的。我试着用我的示例代码来可视化不同的k-nn方法是如何变化的 代码有点长,但不是很复杂。去吧,你自己跑去拍照片。我以大约10个点的列的形式生成示例2D数据。大部分代码都是关于以动画的方式在图形上很好地绘制它。所有分类都是在for循环中的“main”中调用构造库对象KNeighborsClassifier后进行的 我尝试了不同的算法方法,怀疑这是kd树的问题,但我得到了相同的结果(swap algorithm

我一直在玩弄python SKK近邻分类器,我相信它不会正常工作——k大于1的结果是错误的。我试着用我的示例代码来可视化不同的k-nn方法是如何变化的

代码有点长,但不是很复杂。去吧,你自己跑去拍照片。我以大约10个点的列的形式生成示例2D数据。大部分代码都是关于以动画的方式在图形上很好地绘制它。所有分类都是在for循环中的“main”中调用构造库对象KNeighborsClassifier后进行的

我尝试了不同的算法方法,怀疑这是kd树的问题,但我得到了相同的结果(swap algorithm=“kdtree”表示“brute”或ball树)

以下是我得到的结果的说明:

图片评论: 正如您在第3列中看到的,例如,在x=2周围,所有红点周围的区域都应为红色,在x=-4周围,区域应为蓝色,因为下一个最近的红点位于相邻列中。我相信这不是分类器应该如何工作,我不确定我是否做得不对,还是库方法出错。我试着复习代码,但同时决定问这个问题。我也不熟悉C-Python,它是用C-Python编写的

源代码和版本:我使用、和mathplotlib示例编写了代码。我运行Python3.6.1和sklearn的0.18.1版

奖金问题:k-邻域使用kd树的答案是近似的还是确定的?从我的理解来看,它可以很容易地适用于k=1,但我不确定当k大于1时,答案是否总是正确的

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import neighbors
import random


random.seed(905) # 905
# interesting seed 2293
def generate_points(sizex, sizey):
    # sizex = 4
    # sizey = 10
    apart = 5
    # generating at which X coordinate my data column will be
    columns_x = [random.normalvariate(0, 5) for i in range(sizex)]
    columns_y = list()
    # randomising for each column the Y coordinate at which it starts
    for i in range(sizex):
        y_column = [random.normalvariate(-50, 100) for j in range(sizey)]
        y_column.sort()
        columns_y.append(y_column)

    # preparing lists of datapoints with classification
    datapoints = np.ndarray((sizex * sizey, 2))
    dataclass = list()

    # genenerating random split for each column
    for i in range(sizex):
        division = random.randint(0, sizey)
        for j in range(sizey):
            datapoints[i * sizey + j][0] = columns_x[i]
            datapoints[i * sizey + j][1] = -j * apart
            dataclass.append(j < division)

    return datapoints, dataclass


if __name__ == "__main__":
    datapoints, dataclass = generate_points(4, 10)

    #### VISUALISATION PART ####
    x_min, y_min = np.argmin(datapoints, axis=0)
    x_min, y_min = datapoints[x_min][0], datapoints[y_min][1]
    x_max, y_max = np.argmax(datapoints, axis=0)
    x_max, y_max = datapoints[x_max][0], datapoints[y_max][1]
    x_range = x_max - x_min
    y_range = y_max - y_min
    x_min -= 0.15*x_range
    x_max += 0.15*x_range
    y_min -= 0.15*y_range
    y_max += 0.15*y_range

    mesh_step_size = .1

    # Create color maps
    cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF']) # for meshgrid
    cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF']) # for points

    plt.ion() # plot interactive mode
    for weights in ['uniform', 'distance']: # two types of algorithm
        for k in range(1, 13, 2): # few k choices
            # we create an instance of Neighbours Classifier and fit the data.
            clf = neighbors.KNeighborsClassifier(k, weights=weights, algorithm="kd_tree")
            clf.fit(datapoints, dataclass)

            # Plot the decision boundary. For that, we will assign a color to each
            # point in the mesh [x_min, x_max]x[y_min, y_max].
            xx, yy = np.meshgrid(np.arange(x_min, x_max, mesh_step_size),
                                 np.arange(y_min, y_max, mesh_step_size))
            Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

            # Put the result into a color plot
            Z = Z.reshape(xx.shape)

            plt.figure(1)
            plt.pcolormesh(xx, yy, Z, cmap=cmap_light)

            # Plot also the training points
            plt.scatter(datapoints[:, 0], datapoints[:, 1], c=dataclass, cmap=cmap_bold, marker='.')
            plt.xlim(xx.min(), xx.max())
            plt.ylim(yy.min(), yy.max())
            plt.title("K-NN classifier (k = %i, weights = '%s')"
                      % (k, weights))

            plt.draw()
            input("Press Enter to continue...")
            plt.clf()
将numpy导入为np
将matplotlib.pyplot作为plt导入
从matplotlib.colors导入ListedColormap
向邻居学习
随机输入
随机种子(905)#905
#有趣的种子2293
def生成_点(sizex、sizey):
#sizex=4
#sizey=10
间隔=5
#生成我的数据列的X坐标
列_x=[random.normalvariate(0,5)表示范围内的i(sizex)]
列_y=list()
#为每列随机化其开始的Y坐标
对于范围内的i(sizex):
y_列=[random.normalvariate(-50100)表示范围内的j(sizey)]
y_column.sort()
列_y.追加(y列)
#准备具有分类的数据点列表
datapoints=np.ndarray((sizex*sizey,2))
dataclass=list()
#为每列生成随机拆分
对于范围内的i(sizex):
除法=random.randint(0,sizey)
对于范围内的j(尺寸):
数据点[i*sizey+j][0]=列x[i]
数据点[i*sizey+j][1]=-j*
dataclass.append(j

另外,我决定在发布之前设置种子,这样我们都会得到相同的结果,请随意设置随机种子。

您的输出似乎很好

从图表中可能不明显的是,点之间的水平距离实际上比垂直距离短。即使是两个相邻列之间最远的水平间距也是4.5左右,而任何两个相邻行之间的垂直间距都是5


对于分类为红色的点,它们在训练集中的3个最近邻中的大多数实际上是红色的。如果接下来的两个邻居是红色的,他们是否非常接近蓝点并不重要。对于分类为蓝色接近红色点的点也是如此。

看起来它可以非常好地工作。将X轴和Y轴设置为相同的比例可能会使事情更清楚-当轴处于如此不同的比例时,很难判断距离。添加plt.axis('equal')来修正我的直觉。你完全正确,似乎我欺骗了自己,谢谢!