Python 矢量化numpy阵列扩展

Python 矢量化numpy阵列扩展,python,arrays,numpy,vectorization,Python,Arrays,Numpy,Vectorization,我试图找到一种方法来矢量化一个操作,在这个操作中,我取1个numpy数组,并将每个元素展开成4个新点。我目前正在用Python循环来做这件事。首先让我解释一下算法 input_array = numpy.array([1, 2, 3, 4]) 我想将数组中的每个元素“扩展”或“扩展”到4个点。因此,元素0(值1)将扩展为以下4个点: [0, 1, 1, 0] 每一个元素最终都会出现以下情况: [0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0]

我试图找到一种方法来矢量化一个操作,在这个操作中,我取1个numpy数组,并将每个元素展开成4个新点。我目前正在用Python循环来做这件事。首先让我解释一下算法

input_array = numpy.array([1, 2, 3, 4])
我想将数组中的每个元素“扩展”或“扩展”到4个点。因此,元素0(值1)将扩展为以下4个点:

[0, 1, 1, 0]
每一个元素最终都会出现以下情况:

[0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0]
我想让代码稍微通用一些,这样我也可以用不同的方式执行这个“扩展”。例如:

input_array = numpy.array([1, 2, 3, 4])
这一次,通过向每个点添加+=.2来扩展每个点。因此,最终的数组将是:

[.8, .8, 1.2, 1.2, 1.8, 1.8, 2.2, 2.2, 2.8, 2.8, 3.2, 3.2, 3.8, 3.8, 4.2, 4.2]
我当前使用的代码如下所示。这是一种非常简单的方法,它可以工作,但似乎有一种方法可以加快大型阵列的速度:

output = []
for x in input_array:
    output.append(expandPoint(x))

output = numpy.concatenate(output)

def expandPoint(x):
    return numpy.array([0, x, x, 0])

def expandPointAlternativeStyle(x):
    return numpy.array([x - .2, x - .2, x + .2, x + .2])

对于第一个示例,您可以对输入和模板进行外积,并重塑结果:

input_array = np.array([1, 2, 3, 4])
template = np.array([0, 1, 1, 0])

np.multiply.outer(input_array, template)
# array([[0, 1, 1, 0],
#        [0, 2, 2, 0],
#        [0, 3, 3, 0],
#        [0, 4, 4, 0]])

result = np.multiply.outer(input_array, template).ravel()
# array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
同样,对于第二个示例,您可以使用
np.add.outer

np.add.outer(input_array, [-0.2, -0.2, 0.2, 0.2]).ravel()
# array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
        3.2,  3.8,  3.8,  4.2,  4.2])
见:


对于第一个示例,您可以使用
np.kron

>>> a = np.array([0, 1, 1, 0])
>>> np.kron(input_array, a)
array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
对于第二个示例,可以使用
np.repeat
np.tile

>>> b = np.array([-0.2, -0.2, 0.2, 0.2])
>>> np.repeat(input_array, b.size) + np.tile(b, input_array.size)
array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
        3.2,  3.8,  3.8,  4.2,  4.2])

我不确定你的算法的逻辑,但我认为如果你想让每个点在它周围扩展,然后把它们排在一起,你最好的方法是增加维度,然后采用扁平版本;第一个例子是:

>>> x = np.array([1,2,3,4])
>>> x
array([1, 2, 3, 4])
>>> y = np.empty((len(x), 4))
>>> y[:, [0, 3]] = 0
>>> y[:, 1:3] = x[:, None]
>>> y
array([[ 0.,  1.,  1.,  0.],
       [ 0.,  2.,  2.,  0.],
       [ 0.,  3.,  3.,  0.],
       [ 0.,  4.,  4.,  0.]])
>>> y.reshape((4*len(x),))  # Flatten it back
array([ 0.,  1.,  1.,  0.,  0.,  2.,  2.,  0.,  0.,  3.,  3.,  0.,  0.,
    4.,  4.,  0.])
然后,如何使其成为泛型取决于您的算法,我不完全确定是否会遵循该算法。。。但这应该给你一些开始的建议

编辑:正如其他人所说,实际上,您可以用更简洁的方式使用外部产品完成所有这些操作,这可能会更紧密地匹配您的算法,例如,无耻地让YXD回答一行:

>>> (x[:, None] * np.array([0,1,1,0])[None, :]).flatten()
array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])

但是,原则仍然是在原始维度(1)中展开之前先进入更高维度(2)

似乎您希望在
input\u array
和包含扩展元素的数组之间执行元素操作。对于这些,您可以使用

对于第一个示例,您似乎正在执行
elementwise乘法
-

In [424]: input_array = np.array([1, 2, 3, 4])
     ...: extend_array = np.array([0, 1, 1, 0])
     ...: 

In [425]: (input_array[:,None] * extend_array).ravel()
Out[425]: array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
In [422]: input_array = np.array([1, 2, 3, 4])
     ...: extend_array = np.array([-0.2, -0.2, 0.2, 0.2])
     ...: 

In [423]: (input_array[:,None] + extend_array).ravel()
Out[423]: 
array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
        3.2,  3.8,  3.8,  4.2,  4.2])
对于第二个示例,您似乎正在执行
elementwise加法
-

In [424]: input_array = np.array([1, 2, 3, 4])
     ...: extend_array = np.array([0, 1, 1, 0])
     ...: 

In [425]: (input_array[:,None] * extend_array).ravel()
Out[425]: array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0])
In [422]: input_array = np.array([1, 2, 3, 4])
     ...: extend_array = np.array([-0.2, -0.2, 0.2, 0.2])
     ...: 

In [423]: (input_array[:,None] + extend_array).ravel()
Out[423]: 
array([ 0.8,  0.8,  1.2,  1.2,  1.8,  1.8,  2.2,  2.2,  2.8,  2.8,  3.2,
        3.2,  3.8,  3.8,  4.2,  4.2])

很高兴知道这一点!但是,它在我的场景中不起作用,因为输入的数字到处都是。它们不是像1、2、3、4这样的“常规”。我只是举个例子。你说的“到处都是”是什么意思?我指的是不可预测的,糟糕的措辞选择。我查看了
熨斗
,因为我以前从未见过它,而且它似乎会起作用。我以前认为你的解决方案与数字0和1有关,我错了。这个解决方案可能不是最好的,但我认为这是一个可能的想法。感谢链接。这看起来会起作用,而且似乎是迄今为止最直接的方法。例如,本例看起来使用对outer的调用直接等同于下面从@divakar开始的广播方法。我想知道是否有一个惯例可以使用一个而不是另一个?是的,它们是等价的
np。乘法
np。加法
是可以为你处理广播的“UFUNC”-看啊,我从来没有想过使用乘法和加法。我现在明白了。谢谢这种方法和
ufunc
方法与
outer
方法似乎是等效的,但我将采用这种方法,因为它是第一种。我已经测试了这两个,它们在性能方面似乎是一样的。