在numpy中执行交叉差异

时间:2014-07-02 17:06:02

标签: python numpy

我想表现出一种“跨界差异”的感觉。如下:

cross_diff([a,b],[c,d])= [[a - c,a - d],[b - c,b - d]]

我有一个例程在python中执行此操作,如下所示:

def crossdiff(a,b):
    c = []
    for a1 in range(len(a)):
        for b1 in range(len(b)):
            c.append (a[a1]-b[b1])
    x = numpy.array(c)
    x.reshape(len(a),len(b))
    return x

问题是我必须创建一个python数组并将结果填入其中,然后转换回numpy数组。我希望能够获取numpy向量a和b并获得包含所有差异的numpy数组c,因为对于大型向量大小,上面代码的性能很差。

是否可以执行上述计算,因为"纯" numpy operations?

编辑测试结果:

我通过Python分析器运行了此线程中列出的所有四个实现以进行比较。我必须在工作站上运行它们,因为最初的实现使用了大约4GB的RAM和10k元素。

import numpy
import cProfile

def cross_diff(A, B):
    return A[:,None] - B[None,:]

def crossdiff2 (a,b):
    ap = numpy.tile (a, (numpy.shape(b)[0],1))
    bp = numpy.tile (b, (numpy.shape(a)[0],1))

    return ap - bp.transpose()

def crossdiff(a,b):
    c = []
    for a1 in range(len(a)):
        for b1 in range(len(b)):
            c.append (a[a1]-b[b1])
    x = numpy.array(c)
    x.reshape(len(a),len(b))
    return x

a = numpy.array(range(10000))
b = numpy.array(range(10000))

cProfile.run('crossdiff (a,b)')
cProfile.run('crossdiff2 (a,b)')
cProfile.run('cross_diff (a,b)')
cProfile.run('numpy.subtract.outer (a,b)')

结果:   原始python是74.147秒,我的版本是1.656秒,第三个实现0.296和第四个0.288。

3 个答案:

答案 0 :(得分:4)

尝试:

import numpy as np

np.array([a,b])[:,None] - np.array([c,d,e])[None,:]

一点解释:索引中的None会根据需要扩展维度。所以,实际上计算将是:

a a a     c d e     a-c  a-d  a-e
       -         =  
b b b     c d e     b-c  b-d  b-e

令人惊讶的是,索引中的None

又一个例子:

import numpy as np

def cross_diff(A, B):
    return A[:,None] - B[None,:]

vec_a = np.array([1,2,3,4])
vec_b = np.array([3,2,1])

print cross_diff(vec_a, vec_b)

答案 1 :(得分:3)

使用ufunc的.outer方法,无需为广播添加显式维度,即可获得相同的结果。例如:

>>> np.subtract.outer([1, 2], [3, 4, 5])
array([[-2, -3, -4],
       [-1, -2, -3]])

它具有接受任何可迭代输入的额外好处,您不需要首先将它们转换为数组。

答案 2 :(得分:0)

基于@DrV概述的技术,我提出了这个:

def crossdiff2 (a,b):
    ap = numpy.tile (a, (numpy.shape(b)[0],1))
    bp = numpy.tile (b, (numpy.shape(a)[0],1))

    print ap.transpose()

    return ap - bp.transpose()

它给出了与上面相同的答案,但将所有数据操作保持在numpy。