How to insert zeros between elements in a numpy array?
Question:
I have an nd array, for example this:
x = np.array([[1,2,3],[4,5,6]])
I would like to double the size of the last dimension, and insert zeroes between the elements to fill the space. The result should look like this:
[[1,0,2,0,3,0],[4,0,5,0,6,0]]
I tried to solve it using expand_dims
and pad
. But the pad
function inserts zeroes not just after each value in the last dimension. The shape of it’s result is (3, 4, 2)
, but it should be (2,3,2)
y = np.expand_dims(x,-1)
z = np.pad(y, (0,1), 'constant', constant_values=0)
res = np.reshape(z,[-1,2*3]
Result of my code:
array([[1, 0, 2, 0, 3, 0],
[0, 0, 4, 0, 5, 0],
[6, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]])
How is it possible with pad
to insert zeroes in the last dimension after each element? Or is there any better way to solve the problem?
Answers:
Simply initialize output array and assign with slicing
–
m,n = x.shape
out = np.zeros((m,2*n),dtype=x.dtype)
out[:,::2] = x
Alternatively with stacking –
np.dstack((x,np.zeros_like(x))).reshape(x.shape[0],-1)
Along the lines of your expand_dims, we can use stack
:
In [742]: x=np.arange(1,7).reshape(2,-1)
In [743]: x
Out[743]:
array([[1, 2, 3],
[4, 5, 6]])
In [744]: np.stack([x,x*0],axis=-1).reshape(2,-1)
Out[744]:
array([[1, 0, 2, 0, 3, 0],
[4, 0, 5, 0, 6, 0]])
stack
uses expend_dims
to add a dimension; it’s like np.array
but with more control over how the new axis is added. Thus it is a handy way of interspersing arrays.
The stack produces a (2,4,2) array which we reshape to (2,8).
x*0
could be replaced with np.zeros_like(x)
, or anything that creates the same size of zero array.
np.stack([x,x*0],axis=1).reshape(4,-1)
to add 0 rows.
You can do it with the insert function:
np.insert(arr=x, obj=[1,2,3], values=0, axis=1)
array([[1, 0, 2, 0, 3, 0],
[4, 0, 5, 0, 6, 0]])
where obj
are indices before which values are inserted.
You needed to pad only one side of the new dimension:
x = np.array( [[1,2,3],[4,5,6]] )
y = np.expand_dims(x,-1)
z = np.pad( y, ((0, 0), (0, 0), (0, 1)) , 'constant', constant_values=0)
res = np.reshape(z, ( x.shape[0] , 2*x.shape[1] ) )
res
array([[1, 0, 2, 0, 3, 0],
[4, 0, 5, 0, 6, 0]])
Benchmarked some methods I’ve found:
(1) Sub-index assignment
(2) Stride trick
(3) Padding
(4) Concatenation
def dilation1(X, d):
Xd_shape = np.multiply(X.shape, d)
Xd = np.zeros(Xd_shape, dtype=X.dtype)
Xd[0:Xd_shape[0]:d[0], 0:Xd_shape[1]:d[1]] = X
return Xd
def dilation2(X, d):
Xd_shape = np.multiply(X.shape, d)
Xd = np.zeros(Xd_shape, dtype=X.dtype)
Xdn = np.lib.stride_tricks.as_strided(Xd, X.shape, np.multiply(Xd.strides, d))
Xdn[:] = X
return Xd
def dilation3(X, d):
Xd = X.reshape((X.shape[0],1,X.shape[1],1))
Xd = np.pad(Xd, ((0,0),(0,d[0]-1),(0,0),(0,d[1]-1)))
return Xd.reshape(np.multiply(X.shape,d))
def dilation4(X, d):
Xd = X.reshape((X.shape[0],1,X.shape[1],1))
mcol = np.zeros(Xd.shape[:3]+(d[1]-1,))
Xd = np.concatenate((Xd, mcol), 3)
mrow = np.zeros((Xd.shape[0],d[0]-1)+Xd.shape[2:])
Xd = np.concatenate((Xd, mrow), 1)
return Xd.reshape(np.multiply(X.shape,d))
#Example
b = np.arange(3*3).reshape((3,3))
b
# array([[0, 1, 2],
# [3, 4, 5],
# [6, 7, 8]])
dilation1(b, (3,2))
# array([[0, 0, 1, 0, 2, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [3, 0, 4, 0, 5, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [6, 0, 7, 0, 8, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]])
#Benchmark
a = np.random.randn(1024,1024)
%timeit -r 20 dilation1(a, (5,5))
#19.7 ms ± 890 µs per loop (mean ± std. dev. of 20 runs, 100 loops each)
%timeit -r 20 dilation2(a, (5,5))
#18.8 ms ± 526 µs per loop (mean ± std. dev. of 20 runs, 100 loops each)
%timeit -r 20 dilation3(a, (5,5))
#101 ms ± 2.32 ms per loop (mean ± std. dev. of 20 runs, 10 loops each)
%timeit -r 20 dilation4(a, (5,5))
#101 ms ± 1.59 ms per loop (mean ± std. dev. of 20 runs, 10 loops each)
So simply use the sub-index assignment.
I have an nd array, for example this:
x = np.array([[1,2,3],[4,5,6]])
I would like to double the size of the last dimension, and insert zeroes between the elements to fill the space. The result should look like this:
[[1,0,2,0,3,0],[4,0,5,0,6,0]]
I tried to solve it using expand_dims
and pad
. But the pad
function inserts zeroes not just after each value in the last dimension. The shape of it’s result is (3, 4, 2)
, but it should be (2,3,2)
y = np.expand_dims(x,-1)
z = np.pad(y, (0,1), 'constant', constant_values=0)
res = np.reshape(z,[-1,2*3]
Result of my code:
array([[1, 0, 2, 0, 3, 0],
[0, 0, 4, 0, 5, 0],
[6, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]])
How is it possible with pad
to insert zeroes in the last dimension after each element? Or is there any better way to solve the problem?
Simply initialize output array and assign with slicing
–
m,n = x.shape
out = np.zeros((m,2*n),dtype=x.dtype)
out[:,::2] = x
Alternatively with stacking –
np.dstack((x,np.zeros_like(x))).reshape(x.shape[0],-1)
Along the lines of your expand_dims, we can use stack
:
In [742]: x=np.arange(1,7).reshape(2,-1)
In [743]: x
Out[743]:
array([[1, 2, 3],
[4, 5, 6]])
In [744]: np.stack([x,x*0],axis=-1).reshape(2,-1)
Out[744]:
array([[1, 0, 2, 0, 3, 0],
[4, 0, 5, 0, 6, 0]])
stack
uses expend_dims
to add a dimension; it’s like np.array
but with more control over how the new axis is added. Thus it is a handy way of interspersing arrays.
The stack produces a (2,4,2) array which we reshape to (2,8).
x*0
could be replaced with np.zeros_like(x)
, or anything that creates the same size of zero array.
np.stack([x,x*0],axis=1).reshape(4,-1)
to add 0 rows.
You can do it with the insert function:
np.insert(arr=x, obj=[1,2,3], values=0, axis=1)
array([[1, 0, 2, 0, 3, 0],
[4, 0, 5, 0, 6, 0]])
where obj
are indices before which values are inserted.
You needed to pad only one side of the new dimension:
x = np.array( [[1,2,3],[4,5,6]] )
y = np.expand_dims(x,-1)
z = np.pad( y, ((0, 0), (0, 0), (0, 1)) , 'constant', constant_values=0)
res = np.reshape(z, ( x.shape[0] , 2*x.shape[1] ) )
res
array([[1, 0, 2, 0, 3, 0], [4, 0, 5, 0, 6, 0]])
Benchmarked some methods I’ve found:
(1) Sub-index assignment
(2) Stride trick
(3) Padding
(4) Concatenation
def dilation1(X, d):
Xd_shape = np.multiply(X.shape, d)
Xd = np.zeros(Xd_shape, dtype=X.dtype)
Xd[0:Xd_shape[0]:d[0], 0:Xd_shape[1]:d[1]] = X
return Xd
def dilation2(X, d):
Xd_shape = np.multiply(X.shape, d)
Xd = np.zeros(Xd_shape, dtype=X.dtype)
Xdn = np.lib.stride_tricks.as_strided(Xd, X.shape, np.multiply(Xd.strides, d))
Xdn[:] = X
return Xd
def dilation3(X, d):
Xd = X.reshape((X.shape[0],1,X.shape[1],1))
Xd = np.pad(Xd, ((0,0),(0,d[0]-1),(0,0),(0,d[1]-1)))
return Xd.reshape(np.multiply(X.shape,d))
def dilation4(X, d):
Xd = X.reshape((X.shape[0],1,X.shape[1],1))
mcol = np.zeros(Xd.shape[:3]+(d[1]-1,))
Xd = np.concatenate((Xd, mcol), 3)
mrow = np.zeros((Xd.shape[0],d[0]-1)+Xd.shape[2:])
Xd = np.concatenate((Xd, mrow), 1)
return Xd.reshape(np.multiply(X.shape,d))
#Example
b = np.arange(3*3).reshape((3,3))
b
# array([[0, 1, 2],
# [3, 4, 5],
# [6, 7, 8]])
dilation1(b, (3,2))
# array([[0, 0, 1, 0, 2, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [3, 0, 4, 0, 5, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0],
# [6, 0, 7, 0, 8, 0],
# [0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0]])
#Benchmark
a = np.random.randn(1024,1024)
%timeit -r 20 dilation1(a, (5,5))
#19.7 ms ± 890 µs per loop (mean ± std. dev. of 20 runs, 100 loops each)
%timeit -r 20 dilation2(a, (5,5))
#18.8 ms ± 526 µs per loop (mean ± std. dev. of 20 runs, 100 loops each)
%timeit -r 20 dilation3(a, (5,5))
#101 ms ± 2.32 ms per loop (mean ± std. dev. of 20 runs, 10 loops each)
%timeit -r 20 dilation4(a, (5,5))
#101 ms ± 1.59 ms per loop (mean ± std. dev. of 20 runs, 10 loops each)
So simply use the sub-index assignment.