所以我正在为一些更大的数据集构建一个KNN,我需要运行Leave-one-out交叉验证才能选择正确的K,因此速度很重要。
我正在尝试通过广播进行距离计算。
情况是:X
是我的训练矩阵,是一个在行上有样本的二维矩阵。 Q
是我的查询矩阵或测试数据,也是行上的样本。
我需要运行类似于矩阵乘法的东西,其中我将Q的每一行与X.T
(x转置)的每一列匹配,并构建一个sample x sample
矩阵,其中每个条目[i ,j]是查询样本i与训练样本j的距离。然后我将从前k个样本中排序并选择类的模式。
无论如何,在矩阵乘法中,numpy就是这样......但是它不是距离计算,而是分段乘法和求和(点积)。如果我可以将我的距离函数插入到该位置,我想我的KNN距离计算与numpy矩阵乘法一样快。
有没有办法使用广播或其他一些numpy技术来做到这一点?
甚至可能是一种并行化的方法吗?
示例代码:
import numpy as np
x1 = np.asarray([1.0,10.0,100.0])
x2 = np.asarray([40.0,60.0,80.0])
x3 = np.asarray([20.,30.,40.])
x = np.concatenate((x1.reshape(3,1),x2.reshape(3,1),x3.reshape(3,1)),axis=1)
y1 = np.asarray([4.0,88.0,35.0])
y2 = np.asarray([7.0,65.0,99.0])
y3 = np.asarray([40.0,13.0,27.0])
y = np.concatenate((y1.reshape(3,1),y2.reshape(3,1),y3.reshape(3,1)),axis=1)
def euclidean_distance(p1,p2):
return np.sqrt(np.sum((p1-p2)**2.0))
所以,我可能会写:
distances = np.zeros((y.shape[0],x.shape[0]))
for i in range(y.shape[0]):
for j in range(x.shape[0]):
distances[i,j] = euclidean_distance(y[i,:],x[j,:])
这就是我要排序的东西。在上面的当前for循环中,我只选择我的k个最近邻居并在该内循环中找到该类...但它比计算向量化计算中的所有距离要慢得多。
答案 0 :(得分:2)
正如Divakar已经提到的,最简单的选择可能是scipy.spatial.distance.cdist
:
from scipy.spatial.distance import cdist
distances = cdist(y, x) # Euclidean
distances = cdist(y, x, 'mahalanobis') # Mahalanobis
这是单线程但速度很快。您也可以使用np.linalg.norm
:
distances = np.linalg.norm(y[:, None, :] - x[None, :, :], axis=2) # Euclidean
这会在x
和y
中的行对上广播差异计算,以创建形状(3, 3, 3)
的中间数组,然后计算最后一个轴上的欧几里德范数。这是多线程的,但是如果x
和y
有很多行(它也没有利用距离矩阵的对称性),则涉及构建一个可能非常大的中间数组。
将第二种方法概括为计算马哈拉诺比斯距离而不是欧几里德距离是相当简单的(我将留下这部分让你弄清楚......)。
答案 1 :(得分:1)
我会:
这对你有帮助吗?或者我会尝试更明确地写出来......
对第2步的评论:你不必采取sqrt来找到最小值,你也可以最小化正方形
答案 2 :(得分:1)
尝试广播以实现交叉差异:
d = np.sqrt(np.sum((y[:,None,:]-x[None,:,:])**2,axis=-1))
我的测试脚本
import numpy as np
x1 = np.asarray([1.0,10.0,100.0])
x2 = np.asarray([40.0,60.0,80.0])
x3 = np.asarray([20.,30.,40.])
x = np.concatenate([i.reshape(-1,1) for i in [x1,x2,x3]], axis=1)
# see also column_stack
y1 = np.asarray([4.0,88.0,35.0])
y2 = np.asarray([7.0,65.0,99.0])
y3 = np.asarray([40.0,13.0,27.0])
"""
y1 = np.asarray([4.0,88.0]) # test 2d y
y2 = np.asarray([7.0,99.0])
y3 = np.asarray([13.0,27.0])
"""
y = np.concatenate([i.reshape(-1,1) for i in [y1,y2,y3]], axis=1)
def euclidean_distance(p1,p2):
return np.sqrt(np.sum((p1-p2)**2.0))
distances = np.zeros((y.shape[0],x.shape[0]))
for i in range(y.shape[0]):
for j in range(x.shape[0]):
distances[i,j] = euclidean_distance(y[i,:],x[j,:])
print (distances)
d = np.sqrt(np.sum((y[:,None,:]-x[None,:,:])**2,axis=-1))
print(d)
制造
1230:~/mypy$ python2.7 stack35961972.py
[[ 38.70400496 54.2678542 120.60265337]
[ 90.79096871 79.98749902 33.13608305]
[ 68.45436436 46.42197755 68.95650803]]
[[ 38.70400496 54.2678542 120.60265337]
[ 90.79096871 79.98749902 33.13608305]
[ 68.45436436 46.42197755 68.95650803]]