1

There is a random 1D array m_0

np.array([0, 1, 2])

I need to generate two 1D arrays:

np.array([0, 1, 2, 0, 1, 2, 0, 1, 2])
np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])

Is there faster way to do it than this one:

import numpy as np
import time
N = 3
m_0 = np.arange(N)

t = time.time()
m_1 = np.tile(m_0, N)
m_2 = np.repeat(m_0, N)
t = time.time() - t

Size of m_0 is 10**3

bluesky
  • 243
  • 2
  • 12
  • `np.repeat` is compiled and pretty fast. `np.tile` is Python code (which you can read), using `repeat`. Compare that to: `m_`1=np.repeat([m_0], axis=0).ravel()` – hpaulj Jan 09 '21 at 17:47

3 Answers3

0

You could use itertools.product to form the Cartesian product of m_0 with itself, then take the result apart again to get your two arrays.

import numpy as np
from itertools import product

N = 3
m_0 = np.arange(N)

m_2, m_1 = map(np.array, zip(*product(m_0, m_0)))

# m_1 is now array([0, 1, 2, 0, 1, 2, 0, 1, 2])
# m_2 is now array([0, 0, 0, 1, 1, 1, 2, 2, 2])

However, for large N this is probably quite a bit less performant than your solution, as it probably can't use many of NumPy's SIMD optimizations.

For alternatives and comparisons, you'll probably want to look at the answers to Cartesian product of x and y array points into single array of 2D points.

das-g
  • 9,718
  • 4
  • 38
  • 80
0

I guess you could try reshape:

>>> np.reshape([m_0]*3, (-1,), order='C')
array([0, 1, 2, 0, 1, 2, 0, 1, 2])

>>> np.reshape([m_0]*3, (-1,), order='F')
array([0, 0, 0, 1, 1, 1, 2, 2, 2])

Should be tiny bit faster for larger arrays.

>>> m_0 = np.random.randint(0, 10**3, size=(10**3,))
>>> %timeit np.tile([m_0]*10**3, N)
5.85 ms ± 138 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit np.reshape([m_0]*10**3, (-1,), order='C')
1.94 ms ± 46.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Sayandip Dutta
  • 15,602
  • 4
  • 23
  • 52
0

You can slightly improve speed if you reuse your first variable to create the second.

N=1000
%timeit t = np.arange(N); a = np.tile(t, N); b = np.repeat(t, N)
%timeit t = np.arange(N); a = np.tile(t, N); b = np.reshape(a.reshape((N,N)),-1,'F')

7.55 ms ± 46.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

5.54 ms ± 23.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

If you insist on speeding it up further, you can specify the dtype of your array.

%timeit t = np.arange(N,dtype=np.uint16); a = np.tile(t, N); b = np.repeat(t, N)
%timeit t = np.arange(N,dtype=np.uint16); a = np.tile(t, N); b = np.reshape(a.reshape((N,N)),-1,'F')

6.03 ms ± 587 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

3.2 ms ± 37.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Be sure to keep the data type limit in mind.

Marc
  • 712
  • 4
  • 7