Python 与无for循环的numpy的成对相似性
我试图使用Python 与无for循环的numpy的成对相似性,python,numpy,Python,Numpy,我试图使用numpy计算每行之间的相似性。请您建议如何在没有for循环的情况下完成此操作 import numpy as np x = np.array([[1, 2, 3], [4, 5, 6]]) # input: 2 x 3 matrix similarity_matrix = np.zeros([2, 2]) # output: 2 x 2 matrix for i, row1 in enumerate(x): for j, row2 in enumera
numpy
计算每行之间的相似性。请您建议如何在没有for循环的情况下完成此操作
import numpy as np
x = np.array([[1, 2, 3], [4, 5, 6]]) # input: 2 x 3 matrix
similarity_matrix = np.zeros([2, 2]) # output: 2 x 2 matrix
for i, row1 in enumerate(x):
for j, row2 in enumerate(x):
similarity_matrix[i, j] = my_similarity_func(row1, row2) # this func returns a scalar
如果我的输入是nx1矩阵,那么这就行了。当输入为n x m矩阵时,有没有办法实现这一点
x = np.array([1, 2, 3])
similarity_matrix = my_similarity_func(*np.meshgrid(x, x))
*我知道有一些库可以计算相似性,例如
sklearn
或scipy
。还有一种奇特的线性代数方法。但在这里,我只是想知道是否有可能替换这个for循环。您可以使用itertools
替换for循环,这可能更有效(我假设效率是您的实际目标):
您可以使用
itertools
替换for循环,这可能更有效(我假设效率是您的实际目标):
已经给出了几个选项来删除for循环的
。
假设这是出于对效率的考虑,我提供了一些基准。
分析这类事情非常依赖于被调用函数的功能以及数组的大小。
对这里给出的几种方法进行计时(使用np.dot
作为相似性函数)会得到非常相似的结果,for循环具有惊人的竞争力
%timeit tmp=test_using_for_loop(x)
5.88 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit array([[my_similarity_func(r1, r2) for r1 in x] for r2 in x])
6.54 µs ± 101 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit it = starmap(my_similarity_func, product(x, x)); similarity_matrix = np.fromiter(it, float).reshape((len(x), len(x)))
5.34 µs ± 364 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit dist.cdist(x,x,metric=my_similarity_func)
15 µs ± 136 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
另一方面,给出的数据相当小。
在许多应用中,典型的做法是对数百或数千个样本计算相似性度量。
毕竟,为什么要优化一个2乘3的矩阵?
使用较大的数据
x = np.random.randn(3000, 150)
结果是
%timeit tmp=test_using_for_loop(x)
5.69 s ± 54.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit array([[my_similarity_func(r1, r2) for r1 in x] for r2 in x])
5.17 s ± 29.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit it = starmap(my_similarity_func, product(x, x)); similarity_matrix = np.fromiter(it, float).reshape((len(x), len(x)))
3.74 s ± 20.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit dist.cdist(x,x,metric=my_similarity_func)
8.08 s ± 156 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
coldspeed和其他几位评论者也提出了一个问题——优化相似性函数是否比优化它的调用方式更好?
自定义相似性函数不会像np.dot
那样优化。
所以,使用一个有目的的最坏情况(绝对无用)相似性函数
def my_similarity_func(a,b):
calc1 = a.dot(b)
calc2 = sqrt(abs(sum(a)+sum(b)))
calc3 = calc1**2 / calc2 + 1
return calc3
在性能上有相当大的差异的东西几乎消失了。itertools方法和基本循环之间的百分比差异约为5%或6%(仍然比预期的大,但不多)
总之,有几种方法可以删除for循环,但在性能方面,它们可能都是相似的。
如果性能很重要,最好以可以利用广播或其他优化的方式重新编写相似性函数。
在这里对最坏情况下的相似性函数执行此操作将运行时间减少到几百毫秒
%timeit x.dot(x.T)**2 / sqrt(abs(sum(x, 1)[:,None] + sum(x.T, 0))) + 1
128 ms ± 3.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
已经给出了几个选项来删除
for循环的。
假设这是出于对效率的考虑,我提供了一些基准。
分析这类事情非常依赖于被调用函数的功能以及数组的大小。
对这里给出的几种方法进行计时(使用np.dot
作为相似性函数)会得到非常相似的结果,for循环具有惊人的竞争力
%timeit tmp=test_using_for_loop(x)
5.88 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit array([[my_similarity_func(r1, r2) for r1 in x] for r2 in x])
6.54 µs ± 101 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit it = starmap(my_similarity_func, product(x, x)); similarity_matrix = np.fromiter(it, float).reshape((len(x), len(x)))
5.34 µs ± 364 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit dist.cdist(x,x,metric=my_similarity_func)
15 µs ± 136 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
另一方面,给出的数据相当小。
在许多应用中,典型的做法是对数百或数千个样本计算相似性度量。
毕竟,为什么要优化一个2乘3的矩阵?
使用较大的数据
x = np.random.randn(3000, 150)
结果是
%timeit tmp=test_using_for_loop(x)
5.69 s ± 54.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit array([[my_similarity_func(r1, r2) for r1 in x] for r2 in x])
5.17 s ± 29.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit it = starmap(my_similarity_func, product(x, x)); similarity_matrix = np.fromiter(it, float).reshape((len(x), len(x)))
3.74 s ± 20.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit dist.cdist(x,x,metric=my_similarity_func)
8.08 s ± 156 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
coldspeed和其他几位评论者也提出了一个问题——优化相似性函数是否比优化它的调用方式更好?
自定义相似性函数不会像np.dot
那样优化。
所以,使用一个有目的的最坏情况(绝对无用)相似性函数
def my_similarity_func(a,b):
calc1 = a.dot(b)
calc2 = sqrt(abs(sum(a)+sum(b)))
calc3 = calc1**2 / calc2 + 1
return calc3
在性能上有相当大的差异的东西几乎消失了。itertools方法和基本循环之间的百分比差异约为5%或6%(仍然比预期的大,但不多)
总之,有几种方法可以删除for循环,但在性能方面,它们可能都是相似的。
如果性能很重要,最好以可以利用广播或其他优化的方式重新编写相似性函数。
在这里对最坏情况下的相似性函数执行此操作将运行时间减少到几百毫秒
%timeit x.dot(x.T)**2 / sqrt(abs(sum(x, 1)[:,None] + sum(x.T, 0))) + 1
128 ms ± 3.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
?您不同意这取决于所使用的相似性度量吗?另外,在scipy.spatial.distance
中有许多距离度量。是的,我知道scipy
可以做到这一点。我需要实现我自己的相似性函数。我的问题不是关于距离的计算。我只是想知道,如果没有for循环,这是否可能。。。。。您可以在C中编写for循环的地方实现自己的ufunc
。但是如果不知道我的相似性函数,那么就没有办法解决这个问题loop@juanpa.arrivillaga或者,更好,在Cython中。你不同意这取决于所使用的相似性度量吗?另外,在scipy.spatial.distance
中有许多距离度量。是的,我知道scipy
可以做到这一点。我需要实现我自己的相似性函数。我的问题不是关于距离的计算。我只是想知道,如果没有for循环,这是否可能。。。。。您可以在C中编写for循环的地方实现自己的ufunc
。但是如果不知道我的相似性函数,那么就没有办法解决这个问题loop@juanpa.arrivillaga或者,更好的是,在Cython中。这可能是你用numpy提高效率所能做的最糟糕的事情…@COLDSPEED提高效率是相对于起点的-即上面的两个for循环。而且OP还没有实际说明他们的目标。@cᴏʟᴅsᴘᴇᴇᴅ, 您是否对此进行了基准测试,或者这是基于经验的最佳猜测?@user2699在我(公认有限)的经验中,优化您调用的函数比优化调用它的代码要远得多,因为这就是瓶颈所在。@cᴏʟᴅsᴘᴇᴇᴅ, 这是一个很好的观点。我只考虑了循环的开销,这在a上可能不算多