How to copy a 2D array into a 3rd dimension, N times?
Probably the cleanest way is to use np.repeat
:
a = np.array([[1, 2], [1, 2]])
print(a.shape)
# (2, 2)
# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the
# array along, (you can achieve the same effect by indexing with None, see below)
b = np.repeat(a[:, :, np.newaxis], 3, axis=2)
print(b.shape)
# (2, 2, 3)
print(b[:, :, 0])
# [[1 2]
# [1 2]]
print(b[:, :, 1])
# [[1 2]
# [1 2]]
print(b[:, :, 2])
# [[1 2]
# [1 2]]
Having said that, you can often avoid repeating your arrays altogether by using broadcasting. For example, let's say I wanted to add a (3,)
vector:
c = np.array([1, 2, 3])
to a
. I could copy the contents of a
3 times in the third dimension, then copy the contents of c
twice in both the first and second dimensions, so that both of my arrays were (2, 2, 3)
, then compute their sum. However, it's much simpler and quicker to do this:
d = a[..., None] + c[None, None, :]
Here, a[..., None]
has shape (2, 2, 1)
and c[None, None, :]
has shape (1, 1, 3)
*. When I compute the sum, the result gets 'broadcast' out along the dimensions of size 1, giving me a result of shape (2, 2, 3)
:
print(d.shape)
# (2, 2, 3)
print(d[..., 0]) # a + c[0]
# [[2 3]
# [2 3]]
print(d[..., 1]) # a + c[1]
# [[3 4]
# [3 4]]
print(d[..., 2]) # a + c[2]
# [[4 5]
# [4 5]]
Broadcasting is a very powerful technique because it avoids the additional overhead involved in creating repeated copies of your input arrays in memory.
* Although I included them for clarity, the None
indices into c
aren't actually necessary - you could also do a[..., None] + c
, i.e. broadcast a (2, 2, 1)
array against a (3,)
array. This is because if one of the arrays has fewer dimensions than the other then only the trailing dimensions of the two arrays need to be compatible. To give a more complicated example:
a = np.ones((6, 1, 4, 3, 1)) # 6 x 1 x 4 x 3 x 1
b = np.ones((5, 1, 3, 2)) # 5 x 1 x 3 x 2
result = a + b # 6 x 5 x 4 x 3 x 2
Create 3D array from a 2D array by replicating/repeating along the first axis
Introduce a new axis at the start with None/np.newaxis
and replicate along it with np.repeat
. This should work for extending any n
dim array to n+1
dim array. The implementation would be -
np.repeat(arr[None,...],k,axis=0)
Sample run -
In [143]: arr
Out[143]:
array([[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]])
In [144]: np.repeat(arr[None,...],3,axis=0)
Out[144]:
array([[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]],
[[ 1., 2., 3.],
[ 4., 5., 6.],
[ 7., 8., 9.]]])
View-output
for memory-efficiency
We can also generate a 3D
view and achieve virtually free runtime with np.broadcast_to
. More info - here
. Hence, simply do -
np.broadcast_to(arr,(3,)+arr.shape) # repeat 3 times
Python: Repeat a 2d array K number of times and transform
One way is using np.broadcast_to
, specifying the final shape (a
being the input array):
k = 2
out = np.broadcast_to(a, (k, *a.shape))
out.shape
# (2, 3, 5)
print(out)
[[[-0.49349673 -0.16749763 1.09365913 0.91916602 0.5942118 ]
[-1.1357679 -1.06851897 -0.72537699 0.06350472 0.1747241 ]
[-0.29972989 -0.3321334 -1.52296231 -1.41765091 -0.53735561]]
[[-0.49349673 -0.16749763 1.09365913 0.91916602 0.5942118 ]
[-1.1357679 -1.06851897 -0.72537699 0.06350472 0.1747241 ]
[-0.29972989 -0.3321334 -1.52296231 -1.41765091 -0.53735561]]]
I want to convert a 2D numpy array to a 3D array, but there's a catch
You can use numpy.tile
for this
>>> import numpy as np
>>> data = np.array([[0, 2, 6, 3],
[3, 7, 3, 9],
[0, 8, 3, 4],
[4, 6, 2, 1]])
>>> np.tile(data, (3,1,1))
array([[[0, 2, 6, 3],
[3, 7, 3, 9],
[0, 8, 3, 4],
[4, 6, 2, 1]],
[[0, 2, 6, 3],
[3, 7, 3, 9],
[0, 8, 3, 4],
[4, 6, 2, 1]],
[[0, 2, 6, 3],
[3, 7, 3, 9],
[0, 8, 3, 4],
[4, 6, 2, 1]]])
Python: Stretch 2D array into 3D based on corresponding array with 3rd-dimension index
You can use fancy indexing as this, assuming the largest value in b
is always less than c.shape[2]
:
n1, n2 = a.shape
c[np.arange(n1)[:,None], np.arange(n2), b] = a
c
#array([[[ nan, nan, 1.],
# [ nan, nan, 1.],
# [ nan, nan, 1.]],
# [[ nan, 1., nan],
# [ 1., nan, nan],
# [ nan, nan, 1.]],
# [[ nan, 1., nan],
# [ 1., nan, nan],
# [ 1., nan, nan]]])
Here we use integer arrays for all dimensions to trigger advanced indexing, and the three arrays are broadcasted against each other as follows (here we use numpy.broacast_arrays
to visualize this):
i, j, k = np.broadcast_arrays(np.arange(3)[:,None], np.arange(3), b)
print("first dimension index: ")
print(i)
print("second dimension index: ")
print(j)
print("third dimension index: ")
print(k)
first dimension index:
[[0 0 0]
[1 1 1]
[2 2 2]]
second dimension index:
[[0 1 2]
[0 1 2]
[0 1 2]]
third dimension index:
[[2 2 2]
[1 0 2]
[1 0 0]]
Now the advanced indexing goes as (0, 0, 2), (0, 1, 2), (0, 2, 2) ... ,i.e. pick one value from each array at the same positions to form an index for an element:
Some testing cases:
c[0,0,2]
#1.0
c[0,1,2]
#1.0
c[2,1,0]
#1.0
Repeat a 2D NumPy array N times
By my tests, np.repeat
is a little faster than np.tile
:
X = np.repeat(arr[None,:], 3, axis=0)
Alternatively, use np.concatenate
:
X = np.concatenate([[arr]] * 3, axis=0)
arr = np.arange(10000 * 1000).reshape(10000, 1000)
%timeit np.repeat(arr[None,:], 3, axis=0)
%timeit np.tile(arr, (3, 1, 1))
%timeit np.concatenate([[arr]] * 3, axis=0)
# Read-only, array cannot be modified.
%timeit np.broadcast_to(arr, (3, *arr.shape))
# Creating copy of the above.
%timeit np.broadcast_to(arr, (3, *arr.shape)).copy()
170 ms ± 3.82 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
187 ms ± 3.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
243 ms ± 3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
10.9 µs ± 218 ns per loop (mean ± std. dev. of 7 runs, 100000 loops
189 ms ± 2.45 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)each)
np.array_equals(np.repeat(arr[None,:], 3, axis=0),
np.tile(arr, (3, 1, 1))
True
Append 2D array to 3D array, extending third dimension
Use dstack
:
>>> np.dstack((A, B)).shape
(480, 640, 4)
This handles the cases where the arrays have different numbers of dimensions and stacks the arrays along the third axis.
Otherwise, to use append
or concatenate
, you'll have to make B
three dimensional yourself and specify the axis you want to join them on:
>>> np.append(A, np.atleast_3d(B), axis=2).shape
(480, 640, 4)
Creating a list repeated n times using an existing variable which is mutable
You can just use .copy()
:
import numpy as np
R = np.array([[2,3,0], [6,78,8],[1,2,3]])
U = [R.copy() for _ in range(3)]
U[1][2,2] = 0
print(U)
Gives:
[array([[ 2, 3, 0],
[ 6, 78, 8],
[ 1, 2, 3]]),
array([[ 2, 3, 0],
[ 6, 78, 8],
[ 1, 2, 0]]),
array([[ 2, 3, 0],
[ 6, 78, 8],
[ 1, 2, 3]])]
Related Topics
How to Convert a File into a Dictionary
How to Add a Background Thread to Flask
Check If String Ends with One of the Strings from a List
How to Override the Copy/Deepcopy Operations for a Python Object
Attributeerror: 'Module' Object Has No Attribute 'Urlopen'
Expand Python Search Path to Other Source
Dead Simple Example of Using Multiprocessing Queue, Pool and Locking
How to Convert a Dictionary into a List of Tuples
Get Protocol + Host Name from Url
Cosine Similarity Between 2 Number Lists
Call Python Function from Matlab
How to Take Partial Screenshot with Selenium Webdriver in Python
Display a 'Loading' Message While a Time Consuming Function Is Executed in Flask
Matplotlib (Equal Unit Length): with 'Equal' Aspect Ratio Z-Axis Is Not Equal to X- and Y-