I have a 1D numpy array X with the shape (1000,). I want to inject in random (uniform) places 10 random (normal) values and thus obtain the numpy array of shape (1010,). How to do it efficiently in numpy?
I have a 1D numpy array X with the shape (1000,). I want to inject in random (uniform) places 10 random (normal) values and thus obtain the numpy array of shape (1010,). How to do it efficiently in numpy?
You can use np.insert together with np.random.choice:
n = 10
np.insert(a, np.random.choice(len(a), size=n), np.random.normal(size=n))
Here's one based on masking -
def addrand(a, N):
n = len(a)
m = np.concatenate((np.ones(n, dtype=bool), np.zeros(N, dtype=bool)))
np.random.shuffle(m)
out = np.empty(len(a)+N, dtype=a.dtype)
out[m] = a
out[~m] = np.random.uniform(N)
return out
Sample run -
In [22]: a = 10+np.random.rand(20)
In [23]: a
Out[23]:
array([10.65458302, 10.18034826, 10.08652451, 10.03342622, 10.63930492,
10.48439184, 10.2859206 , 10.91419282, 10.56905636, 10.01595702,
10.21063965, 10.23080433, 10.90546147, 10.02823502, 10.67987108,
10.00583747, 10.24664158, 10.78030108, 10.33638157, 10.32471524])
In [24]: addrand(a, N=3) # adding 3 rand numbers
Out[24]:
array([10.65458302, 10.18034826, 10.08652451, 10.03342622, 0.79989563,
10.63930492, 10.48439184, 10.2859206 , 10.91419282, 10.56905636,
10.01595702, 0.23873077, 10.21063965, 10.23080433, 10.90546147,
10.02823502, 0.66857723, 10.67987108, 10.00583747, 10.24664158,
10.78030108, 10.33638157, 10.32471524])
Timings :
In [71]: a = np.random.rand(1000)
In [72]: %timeit addrand(a, N=10)
37.3 µs ± 273 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# @a_guest's soln
In [73]: %timeit np.insert(a, np.random.choice(len(a), size=10), np.random.normal(size=10))
63.3 µs ± 2.18 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Note: If you are working with bigger arrays, it seems np.insert one is doing better.
Not sure if this is the most efficient way, but it works, at least.
A = np.arange(1000)
for i in np.random.randint(low = 0, high = 1000, size = 10):
A = np.concatenate((A[:i], [np.random.normal(),], A[i:]))
Edit, checking performance:
def insert_random(A):
for i in np.random.randint(low = 0, high = len(A), size = 10):
A = np.concatenate((A[:i], [np.random.normal(),], A[i:]))
return A
A = np.arange(1000)
%timeit test(A)
83.2 µs ± 2.47 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
So definitely not the most efficient. np.insert seems to be the way to go.
You could use numpy.insert(arr, obj, values, axis=None).
import numpy as np
a = np.arange(1000)
a = np.insert(a, np.random.randint(low = 1, high = 999, size=10), np.random.normal(loc=0.0, scale=1.0, size=10))
Keep in mind that insert doesn't automatically change your original array, but it returns a modified copy.