Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 用两个numpy向量中元素对上的函数填充矩阵的最快方法?_Python_Performance_Numpy_Pandas - Fatal编程技术网

Python 用两个numpy向量中元素对上的函数填充矩阵的最快方法?

Python 用两个numpy向量中元素对上的函数填充矩阵的最快方法?,python,performance,numpy,pandas,Python,Performance,Numpy,Pandas,我有两个一维numpy向量va和vb,它们通过将所有对组合传递给函数来填充矩阵 na = len(va) nb = len(vb) D = np.zeros((na, nb)) for i in range(na): for j in range(nb): D[i, j] = foo(va[i], vb[j]) 目前,由于va和vb相对较大(4626和737),这段代码需要很长时间才能运行。然而,我希望这可以得到改进,因为使用scipy的cdist方法执行了一个类似的过

我有两个一维numpy向量
va
vb
,它们通过将所有对组合传递给函数来填充矩阵

na = len(va)
nb = len(vb)
D = np.zeros((na, nb))
for i in range(na):
    for j in range(nb):
        D[i, j] = foo(va[i], vb[j])
目前,由于va和vb相对较大(4626和737),这段代码需要很长时间才能运行。然而,我希望这可以得到改进,因为使用scipy的
cdist
方法执行了一个类似的过程,并且性能非常好

D = cdist(va, vb, metric)

很明显,我知道scipy有在C而不是python中运行这段代码的好处,但我希望有一些我不知道的numpy函数可以快速执行这段代码。

cdist
速度很快,因为它是用高度优化的C代码编写的(正如您已经指出的),它只支持一小部分预定义的
metric
s

由于您希望将该操作一般地应用于任何给定的
foo
函数,因此您别无选择,只能调用该函数
na
-times-
nb
times。这一部分不太可能进一步优化

剩下要优化的是循环和索引。一些可供尝试的建议:

  • 使用
    xrange
    而不是
    range
    (如果在python2.x中,在python3中,range已经是一个类似生成器的程序)
  • 使用
    枚举
    ,而不是使用范围+显式索引
  • 使用python速度“魔术”,例如
    cython
    numba
    ,来加速循环过程

  • 如果你能对
    foo
    做进一步的假设,就有可能进一步加速。

    就像@shx2所说的,这一切都取决于
    foo
    是什么。如果可以用numpy ufuncs表示,则使用
    outer
    方法:

    In [11]: N = 400
    
    In [12]: B = np.empty((N, N))
    
    In [13]: x = np.random.random(N)
    
    In [14]: y = np.random.random(N)
    
    In [15]: %%timeit
    for i in range(N):
       for j in range(N):
         B[i, j] = x[i] - y[j]
       ....: 
    10 loops, best of 3: 87.2 ms per loop
    
    In [16]: %timeit A = np.subtract.outer(x, y)   # <--- np.subtract is a ufunc
    1000 loops, best of 3: 294 µs per loop
    

    cython的例子故意过于简单化:实际上,您可能希望添加一些形状/步幅检查,在函数中分配内存等等。

    这是docs调用的最鲜为人知的numpy函数之一。这将从Python函数创建一个numpy ufunc。不是其他类似于numpy ufunc的对象,而是一个带有所有铃铛和口哨的合适的ufunc。虽然该行为在许多方面与
    np.vectorize
    非常相似,但它有一些明显的优点,希望下面的代码能够突出:

    In [2]: def f(a, b):
       ...:     return a + b
       ...:
    
    In [3]: f_vec = np.vectorize(f)
    
    In [4]: f_ufunc = np.frompyfunc(f, 2, 1)  # 2 inputs, 1 output
    
    In [5]: a = np.random.rand(1000)
    
    In [6]: b = np.random.rand(2000)
    
    In [7]: %timeit np.add.outer(a, b)  # a baseline for comparison
    100 loops, best of 3: 9.89 ms per loop
    
    In [8]: %timeit f_vec(a[:, None], b)  # 50x slower than np.add
    1 loops, best of 3: 488 ms per loop
    
    In [9]: %timeit f_ufunc(a[:, None], b)  # ~20% faster than np.vectorize...
    1 loops, best of 3: 425 ms per loop
    
    In [10]: %timeit f_ufunc.outer(a, b)  # ...and you get to use ufunc methods
    1 loops, best of 3: 427 ms per loop
    

    因此,尽管它显然还不如一个适当的矢量化实现,但它的速度要快一点(循环在C中,但仍然有Python函数调用开销)。

    使用矢量化函数,它将使用Numpy的
    外部
    函数同时处理va和vb的所有元素。。。或者传递一个va和vb的网格…问题是这个函数是自定义的,改变为矢量化是非常重要的。我尝试过使用
    np.meshgrid
    然后使用
    np.vectorize
    ,但是性能的改进非常小。
    vectorize
    foo的内部没有任何作用。它只是一个包装器,最后用每对标量调用
    foo(a,b)
    。这是一个方便的工具,而不是一个加速工具。我有两个例子,这段代码正在运行。一种是计算两个向量之间的距离。我知道scipy对此有作用,但在我们的案例中,行为略有不同。另一个是在字典中执行查找
    D[i,j]=a.get((va[i],vb[j]),1.0)
    好吧,这取决于您的特定设置,需要对其进行测量-
    %timeit
    是您的朋友。如果你在途中被困在某个地方,最好单独问一个问题,并详细说明。祝你好运这看起来正是我想要的,我明天会测试一下,让你知道它是怎么回事:)
    In [2]: def f(a, b):
       ...:     return a + b
       ...:
    
    In [3]: f_vec = np.vectorize(f)
    
    In [4]: f_ufunc = np.frompyfunc(f, 2, 1)  # 2 inputs, 1 output
    
    In [5]: a = np.random.rand(1000)
    
    In [6]: b = np.random.rand(2000)
    
    In [7]: %timeit np.add.outer(a, b)  # a baseline for comparison
    100 loops, best of 3: 9.89 ms per loop
    
    In [8]: %timeit f_vec(a[:, None], b)  # 50x slower than np.add
    1 loops, best of 3: 488 ms per loop
    
    In [9]: %timeit f_ufunc(a[:, None], b)  # ~20% faster than np.vectorize...
    1 loops, best of 3: 425 ms per loop
    
    In [10]: %timeit f_ufunc.outer(a, b)  # ...and you get to use ufunc methods
    1 loops, best of 3: 427 ms per loop