KneighborsClassifier 给出与 linalg.norm 和 scipy.spatial.distance.euclidean 不同的欧几里得值
Posted
技术标签:
【中文标题】KneighborsClassifier 给出与 linalg.norm 和 scipy.spatial.distance.euclidean 不同的欧几里得值【英文标题】:KneighborsClassifier giving different euclidean value than linalg.norm and scipy.spatial.distance.euclidean 【发布时间】:2019-07-29 15:57:08 【问题描述】:我正在尝试在mnist dataset 上实现最近邻分类器。 我试图通过与 Scipy KNeighborsClassifier 比较来检查我的结果
为了验证,我使用训练集中的前 6 个样本,并找到训练集中第一个样本的 6 个最近邻。 我计算的距离与 KNeighborsClassifier 库给出的距离不匹配。 我无法弄清楚为什么我的价值观不同。
我参考了this question 来获取欧几里得距离。
我的代码:
from mlxtend.data import loadlocal_mnist
import numpy as np
from scipy.spatial import distance
train, train_label = loadlocal_mnist(
images_path='train-images.idx3-ubyte',
labels_path='train-labels.idx1-ubyte')
train_label = train_label.reshape(-1, 1)
train = train[:6, :]
train_label = train_label[:6, :]
# print(train_label)
test = train.copy()
test_label = train_label.copy()
test = test[:1, :]
test_label = test_label[:1, :]
for test_idx, test_row in enumerate(test):
for train_idx, train_row in enumerate(train):
d1 = np.linalg.norm(train_row - test_row)
d2 = distance.euclidean(train_row, test_row)
d3 = (((train_row - test_row)**2).sum())**0.5
d4 = np.dot(train_row - test_row, train_row - test_row)**0.5
print(train_idx, d1, d2, d3, d4)
测试集只是训练集的第一行
上面的输出是:
0 0.0 0.0 0.0 0.0
1 2618.6771469579826 2618.6771469579826 140.3923074815711 15.937377450509228
2 2372.0210791643485 2372.0210791643485 134.29817571359635 10.770329614269007
3 2139.966354875702 2139.966354875702 122.37646832622684 11.313708498984761
4 2485.1432554281455 2485.1432554281455 135.5322839769182 13.892443989449804
5 2582.292392429641 2582.292392429641 144.69968901141425 14.212670403551895
这是我比较的 KNeighborsClassifier 代码:
neigh = KNeighborsClassifier(n_neighbors=6)
neigh.fit(train, train_label)
closest = neigh.kneighbors(test[0].reshape(1, -1))
print(closest)
输出:
(array([[ 0. , 2387.11164381, 2554.81975881, 2582.29239243,
2672.46721215, 2773.14911247]]), array([[0, 1, 3, 5, 4, 2]], dtype=int64))
我正在尝试计算数据点之间的欧几里得距离以找到最近的邻居。 d1, d2, d3, d4
是我从上面链接的问题中找到的 4 种不同方法,输出是它们的具体值。
但是我从 KNeighborsClassifier 获得的距离值与所有这些都不同,它们也使用文档中给出的欧几里得距离。为什么会这样?
【问题讨论】:
请让您的问题可重现(MNIST 应该不会那么难);什么是train
和test
,它们是如何构建的?
@desertnaut 添加了用于训练和测试的代码。谢谢
好。 d3
& d4
和这个问题有什么关系?他们似乎无关紧要......
@desertnaut 添加了更多详细说明
【参考方案1】:
我不确定是什么原因造成的,但是将数据从 np.array 转换为列表,然后再转换回 np.array 显然解决了这个问题。
train = np.array(train.tolist())
test = np.array(test.tolist())
感谢@desertnaut 提出问题可能出在数据切片中的想法,但我仍然不能确定问题的原因是什么。
【讨论】:
【参考方案2】:好的,这里有一个提示(目前没有时间进一步查看,它可能会有所帮助):
在您计算距离的第一种方式中肯定有一些非常错误的地方(可能在您对初始数据进行切片的方式中);要看到这一点,让我们将循环修改为:
for test_idx, test_row in enumerate(test):
for train_idx, train_row in enumerate(train):
d1 = np.linalg.norm(train_row - test_row)
d2 = np.linalg.norm(test_row - train_row)
d3 = distance.euclidean(train_row, test_row)
d4 = distance.euclidean(test_row, train_row)
print(train_idx, d1, d2, d3, d4)
这里,显然我们应该有d1 = d2 = d3 = d4
;但结果是:
0 0.0 0.0 0.0 0.0
1 2618.6771469579826 2213.268623552053 2618.6771469579826 2213.268623552053
2 2372.0210791643485 2547.0901044132693 2372.0210791643485 2547.0901044132693
3 2139.966354875702 2374.7201940439213 2139.966354875702 2374.7201940439213
4 2485.1432554281455 2467.6727903026367 2485.1432554281455 2467.6727903026367
5 2582.292392429641 2449.1912951013032 2582.292392429641 2449.1912951013032
即是d1 = d3
和d2 = d4
,但是这两个量是不同的;这当然不应该发生,因为距离是一个对称函数,参数的顺序不应该起作用:
a = np.array((1, 2, 3))
b = np.array((4, 5, 6))
distance.euclidean(a, b)
# 5.196152422706632
distance.euclidean(b, a)
# 5.196152422706632
np.linalg.norm(a-b)
# 5.196152422706632
np.linalg.norm(b-a)
# 5.196152422706632
值得深思 - 希望对您有所帮助...
【讨论】:
是的,这是有道理的,但仍然无法找到此错误的来源以上是关于KneighborsClassifier 给出与 linalg.norm 和 scipy.spatial.distance.euclidean 不同的欧几里得值的主要内容,如果未能解决你的问题,请参考以下文章
当我将 IterativeImputer 与 KNeighborsClassifier 一起使用时出现错误“未知标签类型:'连续'”
KNeighborsClassifier' 对象没有属性 'append'
sklearn - KNeighborsClassifier - ValueError:未知标签类型:'连续'
KNeighborsClassifier .predict() 函数不起作用