Reputation: 1026
Say I have a 2D numpy array of points with three columns, and I want to repeat these points in the x direction, producing a new array which has the original set of points, plus a number of 'repeated' points which are translated (1, 2, 3, ..., n) times in the x direction by some vector <c, 0, 0>.
To be clear, say I had the point [0.1, 2.0, 5.0] in the original array, and I wanted to 'repeat' it 5 times using a vector <2, 0, 0>, I would have the following in the final array:
new_array = [[0.1, 2.0, 5.0], [2.1, 2.0, 5.0], [4.1, 2.0, 5.0], [6.1, 2.0, 5.0], [8.1, 2.0, 5.0], [10.1, 2.0, 5.0]]
Is there a way of doing this efficiently using inbuilt numpy vectorisation?
Upvotes: 1
Views: 688
Reputation: 1026
My own answer, thanks to some prompting from the two answers already given. I have the answer for a structured array also - if anyone is interested I can edit this post and add it below.
Given a starting array: array = np.array([[1, 2, 3], ..., [10, 9, 8]])
, a vector: vector = np.array([1, 3, 5])
and a desired number of repetitions: repeat = 5
. You can use the following code:
new_array = np.repeat(array, repeat)
vector_shifts = np.array([vector*index for index in range(0, repeat)])
vector_shifts = vector_shifts[np.newaxis, :]
vector_shifts = np.repeat(vector_shifts, array.shape[0], axis=0)
np.newaxis
creates an extra axis which stops shifts grouping when repeated along, which is the standard np.repeat()
behaviour. For example np.repeat(np.array([[1, 2, 4], [2, 3, 5]], 2)
gives an output: np.array([[1, 2, 4], [1, 2, 4], [2, 3, 5], [2, 3, 5]]
.
vector_shifts = vector_shifts.reshape(vector_shifts.shape[0]*vector_shifts.shape[1], 3)
This removes the additional axis added for np.repeat()
to perform as desired. Finally, the vector shifts can be added to the new array to give an expanded array of repeated points.
new_array += vector_shift
Upvotes: 0
Reputation: 231355
A variation on the accepted answer:
In [33]: point = np.array([0.1, 2.0, 5.0])
In [34]: vector = np.array([2,0,0])
In [35]: np.arange(5)[:,None]*vector
Out[35]:
array([[0, 0, 0],
[2, 0, 0],
[4, 0, 0],
[6, 0, 0],
[8, 0, 0]])
In [36]: np.arange(5)[:,None]*vector + point
Out[36]:
array([[0.1, 2. , 5. ],
[2.1, 2. , 5. ],
[4.1, 2. , 5. ],
[6.1, 2. , 5. ],
[8.1, 2. , 5. ]])
Your comment mentions a structured array. For example if point
has 3 fields, and you want to modify the first:
In [37]: arr = np.array([(0.1, 2.0, 5.0)], dtype='f,f,f')
In [38]: arr
Out[38]: array([(0.1, 2., 5.)], dtype=[('f0', '<f4'), ('f1', '<f4'), ('f2', '<f4')])
In [41]: arr = arr.repeat(5)
In [42]: arr
Out[42]:
array([(0.1, 2., 5.), (0.1, 2., 5.), (0.1, 2., 5.), (0.1, 2., 5.),
(0.1, 2., 5.)], dtype=[('f0', '<f4'), ('f1', '<f4'), ('f2', '<f4')])
In [43]: arr['f0']
Out[43]: array([0.1, 0.1, 0.1, 0.1, 0.1], dtype=float32)
In [44]: arr['f0'] += np.arange(5)*2
In [45]: arr
Out[45]:
array([(0.1, 2., 5.), (2.1, 2., 5.), (4.1, 2., 5.), (6.1, 2., 5.),
(8.1, 2., 5.)], dtype=[('f0', '<f4'), ('f1', '<f4'), ('f2', '<f4')])
You can't modify all 3 fields at the same time. Math does not work across fields.
Upvotes: 1
Reputation: 9796
import numpy as np
point = [0.1, 2, 5]
vector = [2, 0, 0]
n = 5
a = np.zeros((n, len(vector)))
a[1:] = vector
a = np.cumsum(a, axis=0) + point
a[1:] = vector
will create the array
[[0. 0. 0.]
[2. 0. 0.]
[2. 0. 0.]
[2. 0. 0.]
[2. 0. 0.]]
which is the difference you want per row. You then cumulatively summate them and add the point as offset.
Upvotes: 1