【问题标题】:how to vectorize an operation on a 1 dimensionsal array to produce 2 dimensional matrix in numpy如何对一维数组上的操作进行矢量化以在 numpy 中生成二维矩阵
【发布时间】:2013-01-08 14:31:44
【问题描述】:

我有一个一维数组

i = np.arange(0,7,1)

还有一个函数

# Returns a column matrix
def fn(i):
    return np.matrix([[i*2,i*3]]).T


fnv = np.vectorize(fn) 

然后写

fnv(i)

给我一​​个错误

  File "<stdin>", line 1, in <module>
  File "c:\Python33\lib\site-packages\numpy\lib\function_base.py", 
        line 1872, in __call__
    return self._vectorize_call(func=func, args=vargs)
  File "c:\Python33\lib\site-packages\numpy\lib\function_base.py", 
        line 1942, in _vectorize_call
        copy=False, subok=True, dtype=otypes[0])
  ValueError: setting an array element with a sequence.

我正在寻找的结果是一个具有两行和与输入数组一样多的列的矩阵。 numpy 中实现此目的的最佳表示法是什么?

例如 i 等于

[1,2,3,4,5,6]

输出等于

[[2,4,6,8,10,12],
 [3,6,9,12,15,18]]

【问题讨论】:

  • 你不应该使用 'input' 作为变量名,你能否展示一个预期输出的例子?
  • 添加了一个示例输出,只是为了显示结构。这些值无关紧要,可以用 fn 内计算的任何值替换
  • 你的函数和你的输出不匹配...
  • 是的。 f(1) -> [2,3]' f(2) -> [4,6]' 等
  • 有这么复杂吗?生成一系列列并以最快的方式将它们连接在一起以形成矩阵

标签: numpy vectorization


【解决方案1】:

编辑 你应该尽量避免使用vectorize,因为它给人一种 numpy 效率的错觉,但里面全是 python 循环。

如果您真的必须处理用户提供的函数,这些函数采用ints 并返回形状为(2, 1)matrix,那么您可能无能为力。但这似乎是一个非常奇怪的用例。如果您可以将其替换为采用int 并返回int 并在需要时使用ufuncs(即np.sin 而不是math.sin)的函数列表,您可以执行以下操作

def vectorize2(funcs) :
    def fnv(arr) :
        return np.vstack([f(arr) for f in funcs])
    return fnv

f2 = vectorize2((lambda x : 2 * x, lambda x : 3 * x))

>>> f2(np.arange(10))
array([[ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18],
       [ 0,  3,  6,  9, 12, 15, 18, 21, 24, 27]])

仅供您参考,我已根据您提出的矢量化进行计时:

f = vectorize(fn)


>>> timeit.timeit('f(np.arange(10))', 'from __main__ import np, f', number=1000)
0.28073329263679625
>>> timeit.timeit('f2(np.arange(10))', 'from __main__ import np, f2', number=1000)
0.023139129945661807


>>> timeit.timeit('f(np.arange(10000))', 'from __main__ import np, f', number=10)
2.3620706288432984
>>> timeit.timeit('f2(np.arange(10000))', 'from __main__ import np, f2', number=10)
0.002757072593169596

因此,即使对于小型阵列,速度也有一个数量级,对于较大的阵列,速度会增长到 1000 倍,几乎免费提供。

原始答案

除非没有办法,否则不要使用vectorize,它很慢。请参阅以下示例

>>> a = np.array(range(7))
>>> a
array([0, 1, 2, 3, 4, 5, 6])
>>> np.vstack((a, a+1))
array([[0, 1, 2, 3, 4, 5, 6],
       [1, 2, 3, 4, 5, 6, 7]])
>>> np.vstack((a, a**2))
array([[ 0,  1,  2,  3,  4,  5,  6],
       [ 0,  1,  4,  9, 16, 25, 36]])

无论你的函数是什么,如果它可以用 numpy 的 ufuncs 构造,你可以做类似np.vstack((a, f(a))) 的事情并得到你想要的

【讨论】:

  • 不,这只是展示原理的退化示例。 fn 内的转换可以是任何东西,但输出为 (2,1) 列矩阵
  • @bradgonesurfing 完全重做,基本思路依旧
  • 还是不行。 f(a) 返回一列,每一列都应连接起来形成一个 (2,N) 矩阵。 fn 可以是任何东西
  • 感谢 ufuncs 的澄清。作为一个旧的 Matlab hack,我应该知道寻找这种东西。
【解决方案2】:

vectorize 的简单重新实现给了我想要的东西

def vectorize( fn):
    def do_it (array):
        return np.column_stack((fn(p) for p in array))
    return do_it

如果这不起作用或有更好的方法,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-17
    • 2018-01-09
    • 2014-07-29
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多