我一直在玩python sklearn k近邻分类器,我认为它不能正常工作-k大于1的结果是错误的。我试着想象不同的k-nn方法是如何随着我的示例代码而变化的。
代码有点长,但不是很复杂。去吧,自己跑去拍照片。我以大约10个点的列的形式生成示例2D数据。大多数代码都是关于以动画的方式在图形上很好地绘制它。所有分类都发生在为循环调用">main"中的构造库对象KNeighborsClassifier之后。
我尝试了不同的算法方法,怀疑这是kd树问题,但我得到了相同的结果(将算法="kdtree"替换为"暴力"或球树)
以下是我得到的结果:
k=3和均匀权重的分类器的结果,kdtrees
图片评论:正如您在第三列中看到的,例如,在x=2周围,红色点周围的所有区域都应该是红色,在x=-4周围,区域应该是蓝色,因为下一个最近的红色点在相邻列中。我认为这不是分类器的行为方式,我也不确定是我做得不对,还是库方法错误。我试着查看它的代码,但同时决定问这个问题。此外,我不熟悉C-Python,它是用编写的
源代码和版本:我使用scikit学习文档和mathplotlib示例编写了代码。我运行了python 3.6.1和sklearn的0.18.1版本。
附加问题:使用kd树的k-neighbors答案是近似的还是确定的?根据我的理解,它可以很容易地完美地适用于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()
此外,我决定在发布之前设置种子,这样我们都会得到相同的结果,可以随意设置随机种子。
您的输出似乎很好。
从图中可能不明显的是,点之间的水平距离实际上比垂直距离短。即使两个相邻列之间的最远水平间隔也是4左右,而任何两个相邻行之间的垂直间隔都是5。
对于分类为红色的点,它们在训练集中的3个最近邻居中的大多数确实是红色的。如果接下来的两个邻居是红色的,那么它们是否非常接近蓝色点并不重要。在红色点附近分类为蓝色的点也是如此。