让我们训练一个只包含一个样本的最近邻模型:
In [48]: nn = NearestNeighbors().fit([[0, 1, 0, 0]])
所以这个样本只有一个显着特征。查询具有相同样本的模型按预期返回第一个数组中的 0 距离:
In [50]: nn.kneighbors([[0, 1, 0, 0]], 1)
Out[50]: (array([[0.]]), array([[0]]))
但是样本为 [0,2,0,0] 和 [0,1,1,0] 的查询都返回相同的距离值 1:
In [51]: nn.kneighbors([[0, 2, 0, 0]], 1)
Out[51]: (array([[1.]]), array([[0]]))
In [52]: nn.kneighbors([[0, 1, 1, 0]], 1)
Out[52]: (array([[1.]]), array([[0]]))
这是违反直觉的,因为人们会期望 [0,2,0,0] 与 [0,1,0,0] 比 [0,1,1,0] 更相似。使用 Jaccard 度量可以稍微改善这个问题:
In [56]: nn = NearestNeighbors(metric=scipy.spatial.distance.jaccard).fit([[0, 1, 0, 0]])
In [57]: nn.kneighbors([[0, 1, 0, 0]], 1)
Out[57]: (array([[0.]]), array([[0]]))
In [58]: nn.kneighbors([[0, 2, 0, 0]], 1)
Out[58]: (array([[1.]]), array([[0]]))
In [59]: nn.kneighbors([[0, 1, 1, 0]], 1)
Out[59]: (array([[0.5]]), array([[0]]))
但是对于我的数据集,Jaccard 度量使得 kNN 查询需要很长时间,也许它更适合二进制特征。我有一组来自每行 52 个传感器的读数,用零均值很好地标准化。当我将这个集合安装到 sklearn.neighbors.NearestNeighbors 并查询将训练集的第一行作为样本并且 K=2 时,我偶然发现了这个问题,因此它返回了预期距离为 0 处的第 0 个索引和其他一些 0.02 的索引距离。当我检查另一个时,我看不到任何相似之处,实际上大多数功能在值和/或符号方面非常不同。我可以从训练集中的第一行的组成样本中获得相同的距离,其中任何一个特征都增加了 0.02。
我现在想知道如何克服这个问题,以及是否有一种简单的方法(即通过调整 NearestNeighbors 的参数)或一种 hacky 方法(即自定义指标、特征权重等)或者我应该使用不同的模型?例如,KMeans 可以非常快地从我的数据集中聚合集群,但它在内部使用 NN,由于 init 中的随机性,我并不完全喜欢它。