Slice 2d array into smaller 2d arrays
There was another question a couple of months ago which clued me in to the idea of using reshape
and swapaxes
. The h//nrows
makes sense since this keeps the first block's rows together. It also makes sense that you'll need nrows
and ncols
to be part of the shape. -1
tells reshape to fill in whatever number is necessary to make the reshape valid. Armed with the form of the solution, I just tried things until I found the formula that works.
You should be able to break your array into "blocks" using some combination of reshape
and swapaxes
:
def blockshaped(arr, nrows, ncols):
"""
Return an array of shape (n, nrows, ncols) where
n * nrows * ncols = arr.size
If arr is a 2D array, the returned array should look like n subblocks with
each subblock preserving the "physical" layout of arr.
"""
h, w = arr.shape
assert h % nrows == 0, f"{h} rows is not evenly divisible by {nrows}"
assert w % ncols == 0, f"{w} cols is not evenly divisible by {ncols}"
return (arr.reshape(h//nrows, nrows, -1, ncols)
.swapaxes(1,2)
.reshape(-1, nrows, ncols))
turns c
np.random.seed(365)
c = np.arange(24).reshape((4, 6))
print(c)
[out]:
[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]]
into
print(blockshaped(c, 2, 3))
[out]:
[[[ 0 1 2]
[ 6 7 8]]
[[ 3 4 5]
[ 9 10 11]]
[[12 13 14]
[18 19 20]]
[[15 16 17]
[21 22 23]]]
I've posted an inverse function, unblockshaped
, here, and an N-dimensional generalization here. The generalization gives a little more insight into the reasoning behind this algorithm.
Note that there is also superbatfish'sblockwise_view
. It arranges the
blocks in a different format (using more axes) but it has the advantage of (1)
always returning a view and (2) being capable of handling arrays of any
dimension.
How do I split a 2D array into smaller 2D arrays, of variable size?
This builds the generator you need.
from itertools import product
import numpy as np
n, m = 70, 85
a = np.arange(n * m).reshape(n, m)
def igen(a, n, m):
i_ = np.arange(a.shape[0]) // n
j_ = np.arange(a.shape[1]) // m
for i, j in product(np.unique(i_), np.unique(j_)):
yield (i, j), a[i_ == i][:, j_ == j]
dict_of_arrays = dict(igen(a, 16, 16))
another alternative
pad with np.nan
and reshape
+ transpose
def cover_multiple(current_length, multiple):
return ((current_length - 1) // multiple + 1) * multiple
def slicer(a, chunk_i, chunk_j, two_d=True):
n = cover_multiple(a.shape[0], chunk_i)
m = cover_multiple(a.shape[1], chunk_j)
c = np.empty((n, m))
c.fill(np.nan)
c[:a.shape[0], :a.shape[1]] = a
c = c.reshape(n // chunk_i, chunk_i, m // chunk_j, chunk_j)
c = c.transpose(0, 2, 1, 3)
if not two_d:
c = c.reshape(-1, chunk_i, chunk_j)
return c
demo
a = np.arange(64).reshape(8, 8)
a
[[ 0 1 2 3 4 5 6 7]
[ 8 9 10 11 12 13 14 15]
[16 17 18 19 20 21 22 23]
[24 25 26 27 28 29 30 31]
[32 33 34 35 36 37 38 39]
[40 41 42 43 44 45 46 47]
[48 49 50 51 52 53 54 55]
[56 57 58 59 60 61 62 63]]
print(slicer(a, 3, 5))
[[[[ 0. 1. 2. 3. 4.]
[ 8. 9. 10. 11. 12.]
[ 16. 17. 18. 19. 20.]]
[[ 5. 6. 7. nan nan]
[ 13. 14. 15. nan nan]
[ 21. 22. 23. nan nan]]]
[[[ 24. 25. 26. 27. 28.]
[ 32. 33. 34. 35. 36.]
[ 40. 41. 42. 43. 44.]]
[[ 29. 30. 31. nan nan]
[ 37. 38. 39. nan nan]
[ 45. 46. 47. nan nan]]]
[[[ 48. 49. 50. 51. 52.]
[ 56. 57. 58. 59. 60.]
[ nan nan nan nan nan]]
[[ 53. 54. 55. nan nan]
[ 61. 62. 63. nan nan]
[ nan nan nan nan nan]]]]
Slice a 2D array into an array of smaller 'blocks' or 'chunks'
arr = [ [ 'A', 'B', 1, 2, 'α', 'β' ],
[ 'C', 'D', 3, 4, 'θ', 'μ' ],
[ 'E', 'F', 5, 6, 'ω', 'ξ' ] ], l = console.log, j = JSON.stringify
l(j( arr[0].slice(2, 4) )) // "[1,2]" - slice can be used to get part of array
l(j( arr.map(a => a.slice(2, 4)) )) // "[[1,2],[3,4],[5,6]]" - map + slice to get part of each sub-array
result = [0, 2, 4].map(i => arr.map(a => a.slice(i, i+2))) // map over the indexes to split by to get the parts
l(j( arr )), l(j( result ))
Numpy: How to slice or split 2D subsections of 2D array
In [2]: ary = np.arange(24).reshape(6,4)
In [3]: ary
Out[3]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
While I recommended moving-windows based on as_strided
, we can also divide the array into 'blocks' with reshape and transpose:
In [4]: ary.reshape(3,2,2,2).transpose(0,2,1,3)
Out[4]:
array([[[[ 0, 1],
[ 4, 5]],
[[ 2, 3],
[ 6, 7]]],
[[[ 8, 9],
[12, 13]],
[[10, 11],
[14, 15]]],
[[[16, 17],
[20, 21]],
[[18, 19],
[22, 23]]]])
In [5]: np.sqrt(_.sum(axis=(2,3)))
Out[5]:
array([[3.16227766, 4.24264069],
[6.4807407 , 7.07106781],
[8.60232527, 9.05538514]])
While the transpose makes it easier to visual the blocks that need to be summed, it isn't necessary:
In [7]: np.sqrt(ary.reshape(3,2,2,2).sum(axis=(1,3)))
Out[7]:
array([[3.16227766, 4.24264069],
[6.4807407 , 7.07106781],
[8.60232527, 9.05538514]])
np.lib.stride_tricks.sliding_window
doesn't give us as much direct control as I thought, but
np.lib.stride_tricks.sliding_window_view(ary,(2,2))[::2,::2]
gives the same result as Out[4]
.
In [13]: np.sqrt(np.lib.stride_tricks.sliding_window_view(ary,(2,2))[::2,::2].sum(axis=(2,3)))
Out[13]:
array([[3.16227766, 4.24264069],
[6.4807407 , 7.07106781],
[8.60232527, 9.05538514]])
[7] is faster.
In general, it can be done like this:
a_height = 15
a_width = 16
a_area = a_height * a_width
a = np.arange(a_are).reshape(a_height, a_width)
window_height = 3 # must evenly divide a_height
window_width = 4 # must evenly divide a_width
b_height = a_height // window_height
b_width = a_width // window_width
b = a.reshape(b_height, window_height, b_width, window_width).transpose(0,2,1,3)
# or, assuming you want sum or another function that takes `axis` argument
b = a.reshape(b_height, window_height, b_width, window_width).sum(axis=(1,3))
c# How do i split a 2D array into a list of smaller 2D arrays (chunks)?
you can achieve this using Buffer.BlockCopy and little logic.
Check the below code
static void Main(string[] args)
{
int p = 1;
int[,] array = new int[9, 9];
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
array[i, j] = p++;
}
}
GetChunkUsingBlockCopy(array, 3, 3);
}
static List<int[,]> GetChunkUsingBlockCopy(int[,] array, int row, int column)
{
int chunkcount = (array.GetLength(0) * array.GetLength(1)) / (row * column);
List<int[,]> chunkList = new List<int[,]>();
int[,] chunk = new int[row, column];
var byteLength = sizeof(int) * chunk.Length;
for (int i = 0; i < chunkcount; i++)
{
chunk = new int[row, column];
Buffer.BlockCopy(array, byteLength * i, chunk, 0, byteLength);
chunkList.Add(chunk);
}
return chunkList;
}
Hope this helps !
Please do not forget to mark this as Answer if found suitable.
Chunk 2D array into smaller arrays, get the chunk means, and plot a heatmap
Main Array
- Remove
linewidth
- Add
set_xticklabels
andset_yticklabels
# test data
np.random.seed(365)
data = np.random.random((1080,1920))
ax = sns.heatmap(data, cmap='jet')
ax.set_xticks(xticks) # this is only the tick location, not the label
ax.set_xticklabels(xticks) # this adds the labels, after setting the ticks
ax.set_yticks(yticks)
ax.set_yticklabels(yticks)
ax.invert_yaxis() # use if desired to swap the direction of the y-axis values
ax.grid(color='k')
plt.show()
Divide the Array
- I used the function in this answer to chunk the data into an array
(288, 90, 80)
# using function from other answer
chunked = blockshaped(data, 90, 80)
# get the means of each chunk and then reshape
means = np.array([v.mean() for v in chunked]).reshape(12, 24)
# plot the chunks
fig, ax = plt.subplots(figsize= (16,9))
p = sns.heatmap(means, cmap='jet', ax=ax)
p.set_xticks(range(25))
p.set_xticklabels([0] + xticks)
p.set_yticks(range(13))
p.set_yticklabels([0] + yticks)
p.invert_yaxis()
p.grid(color='k')
plt.show()
blockshaped
- Here's the function from the other answer for reshapeding the array
def blockshaped(arr, nrows, ncols):
"""
Return an array of shape (n, nrows, ncols) where
n * nrows * ncols = arr.size
If arr is a 2D array, the returned array should look like n subblocks with
each subblock preserving the "physical" layout of arr.
"""
h, w = arr.shape
assert h % nrows == 0, f"{h} rows is not evenly divisible by {nrows}"
assert w % ncols == 0, f"{w} cols is not evenly divisible by {ncols}"
return (arr.reshape(h//nrows, nrows, -1, ncols)
.swapaxes(1,2)
.reshape(-1, nrows, ncols))
Related Topics
Problem Running Python from Crontab - "Invalid Python Installation"
Problems Adding Path and Calling External Program from Python
What Does "The Following Packages Will Be Superseded by a Higher Priority Channel" Mean
Set Bash Variable from Python Script
Unicodedecodeerror Reading Binary Input
Module Not Found After Building Python Project by Using Pysinstaller
Passing Variable from Python Script to Bash Script
Python Script Not Working via Cron
Why Does Loading the Libc Shared Library Have "'Libraryloader' Object Is Not Callable" Error
Using Python Subprocess.Call() to Launch an Ncurses Process
Detect and Exclude Outliers in a Pandas Dataframe
Clang Error: Unknown Argument: '-Mno-Fused-Madd' (Python Package Installation Failure)
How to Use Expect on Windows Without Installing Cygwin
Beyond Top Level Package Error in Relative Import