I\'m trying to find a way to vectorize an operation where I take 1 numpy array and expand each element into 4 new points. I\'m currently doing it with Python loop. First l
For the first example, you can use 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])
For the second example, you can use np.repeat
and 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])
It seems you want to want to do elementwise operations between input_array
and the array that contains the extending elements. For these, you can use broadcasting.
For the first example, it seems you are performing elementwise multiplication
-
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])
For the second example, it seems you are performing elementwise addition
-
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])
For the first example, you can do an outer product of the input and the template and reshape the result:
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])
Similarly for your second example you can use 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])
See:
I'm not certain of the logic of your algorithm, but I think if you want each point to extend
around it, and then queue them all together, your best approach would be to increase the dimension, and then take the flattened version; for your first example:
>>> 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.])
How you then go about making that generic depends on your algorithm, which I'm not entirely sure to follow... But this should give you some pointers to get started.
Edit: As others have stated, you can actually do all that with outer products in a much more concise way, which will probably match your algorithm more closely, e.g., shamelessely making YXD answer a one-liner:
>>> (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])
However, the principle is still to go in a higher dimension (2) before expanding it in you original dimension (1)