你会如何使用numpy有效地矢量化这种操作?

时间:2013-12-03 16:39:06

标签: python numpy

输入数据

生成给定大小的n个矩阵(此处为3x2)。我也选择了n = 25,但我让n强调我们拥有的是一堆矩阵的事实。

import numpy as np
n = 25
data = np.random.rand(n, 3, 2)

这只是一个格式示例:我无法更改它。或者如果我这样做,就必须考虑到这种变化的计算成本。

当前实施

我想以原子方式实现的目标是:

output = []
for datum in data: # This outputs on (3x2) matrix after the other
    d0 = datum[0]
    dr = datum[1:]
    output.append(dr-d0)

或者,以更快的方式:

output = [dr-d0 for (dr, d0) in zip(datum[:,0], datum[:,1:])]

问题

这太慢了:

output = datum[:,1:] - datum[:,0]

不起作用,因为在这种情况下没有很好地定义减法运算的行为。另外,这种切片效率不高。

Cython / Nuitka / PyPy等可能的解决方案,但如果可能的话,我现在想坚持使用原始Numpy。也许某种函数可以非常快速地应用于numpy数组的外部循环元素,而不会产生python的开销......

np.vectorize功能不起作用:

def get_diff(mat):
    return mat[1:] - mat[0]

所以我召唤你们,Numpy的大祭司,Python的仆人来启发我可怜的灵魂!

修改

XY问题

(我不知道它有名字)

我真正想要做的是确定很多单纯形词的内容(读“音量”)(读作“四面体”)。最简单,最有效的方法是,AFAIK计算:

np.linalg.det(mat[:1]-mat[0])

然后让我重新解释一下我的问题:如何使用普通的python和numpy有效地计算维度k的任何简单集合的内容?

1 个答案:

答案 0 :(得分:3)

我建议data[:,1:] - data[:,0,None]None创建一个新轴(正式你应该使用np.newaxis,这使得你正在做的很清楚),然后减法将按照你想要的方式运行。< / p>

纠正我认为列表理解中的错误:

def loop(data):
    output = []
    for datum in data: # This outputs on (3x2) matrix after the other
        d0 = datum[0]
        dr = datum[1:]
        output.append(dr-d0)
    return output

def listcomp(data):
    output = [dr-d0 for (d0, dr) in zip(data[:,0], data[:,1:])]
    return output

def sub(data):
    output = data[:,1:] - data[:,0,None]
    return output

我们有

>>> import numpy as np
>>> n = 25
>>> data = np.random.rand(n, 3, 2)
>>> res_loop = loop(data)
>>> res_listcomp = listcomp(data)
>>> res_sub = sub(data)
>>> np.allclose(res_loop, res_listcomp)
True
>>> np.allclose(res_loop, res_sub)
True
>>> 
>>> %timeit loop(data)
10000 loops, best of 3: 184 µs per loop
>>> %timeit listcomp(data)
10000 loops, best of 3: 158 µs per loop
>>> %timeit sub(data)
100000 loops, best of 3: 12.8 µs per loop