Python

Slicing of a NumPy 2d array or how do I extract an mxm submatrix from an nxn array nm

27 September 2026 · 8 min read

Slicing of a NumPy 2d array or how do I extract an mxm submatrix from an nxn array nm

NumPy is an indispensable library in Python, forming the bedrock of scientific computing, data analysis, and machine learning. Its core strength lies in its efficient handling of large, multi-dimensional arrays and matrices. Among the most fundamental and powerful operations you’ll perform with NumPy is array slicing. This technique allows you to extract specific portions of an array, creating new arrays (or views) without explicitly looping through elements. Understanding the nuances of slicing of a NumPy 2d array, or how do I extract an mxm submatrix from an nxn array (n>m), is crucial for anyone working with numerical data, enabling precise data manipulation and efficient algorithm development. This guide will walk you through everything you need to know, from basic indexing to advanced submatrix extraction, complete with practical examples.

Understanding NumPy Arrays and Basic Indexing

NumPy arrays, specifically ndarray objects, are at the heart of numerical operations in Python. Unlike standard Python lists, NumPy arrays are homogeneous (all elements are of the same data type) and stored contiguously in memory, which significantly boosts performance. This efficiency is paramount when dealing with large datasets, making NumPy the go-to choice for tasks ranging from image processing to complex scientific simulations. When you create a 2D NumPy array, you’re essentially working with a matrix, where data is organized into rows and columns.

Basic indexing in NumPy allows you to access individual elements. For a 2D array, you specify both the row and column index, separated by a comma. For example, my_array[0, 1] would retrieve the element at the first row (index 0) and second column (index 1). This direct access is a cornerstone of effective data manipulation. Mastering basic indexing is the first step towards understanding more complex operations like slicing, which extends this concept to select entire ranges of elements rather than just single ones. The performance benefits of NumPy’s underlying C implementations for these operations are a key reason for its widespread adoption in the scientific community.

The structured nature of NumPy arrays also facilitates vectorized operations, meaning you can apply mathematical functions to entire arrays or array sections without explicit Python loops. This not only makes code more concise but also dramatically faster. For instance, adding two NumPy arrays simply involves array1 + array2, which performs element-wise addition. This powerful paradigm greatly simplifies complex mathematical tasks and is a major efficiency driver when performing operations on data subsets obtained through slicing. Learning to effectively use these tools is essential for any data professional.

Mastering 2D Array Slicing: The Fundamentals

Slicing in NumPy 2D arrays uses a powerful and intuitive syntax: array[row_slice, column_slice]. Each slice specifies a range using start:stop:step, similar to Python list slicing. If you omit start, it defaults to the beginning (0); if you omit stop, it defaults to the end of the dimension. Omitting step uses a default step of 1. This flexibility allows for precise selection of rows, columns, or continuous blocks of elements. For example, my_array[0:2, 1:3] would select elements from rows 0 and 1, and columns 1 and 2. This is the fundamental technique for slicing of a NumPy 2d array.

To extract a specific submatrix or subset of a NumPy 2D array, you use the slicing syntax array[row_start:row_end, col_start:col_end]. This allows you to define the exact boundaries for both rows and columns, effectively pulling out an m x m section from a larger n x n array. Remember that the stop index in slicing is exclusive, meaning it goes up to, but does not include, that index. This precision is vital for tasks like isolating regions of interest in image processing or focusing on specific data ranges in time-series analysis. The resulting slice is typically a “view” into the original array, meaning changes to the slice will also affect the original array, unless explicitly copied.

Understanding how to select entire rows or columns is also crucial. To select all columns for a specific row, you can use my_array[row_index, :], where the colon : indicates “all elements” along that dimension. Similarly, to select all rows for a specific column, you’d use my_array[:, col_index]. This shorthand is incredibly useful for common data manipulation tasks. For instance, if you need to perform an operation on a particular feature (column) across all samples (rows), this slicing method provides a direct and efficient way to access that data. According to the official NumPy documentation, “Slicing is a powerful tool for extracting data from arrays and creating new arrays or views.” NumPy Indexing Documentation is an excellent resource for further details.

Extracting an mxm Submatrix from an nxn Array

The core problem of extracting an mxm submatrix from an nxn array (where n > m) is a perfect application of 2D array slicing. This operation is common in many fields, such as creating smaller convolutional kernels in deep learning, isolating specific regions in scientific simulations, or analyzing local neighborhoods in grid-based data. The process involves defining the starting row and column and then specifying the number of rows and columns (m) you want to include in your submatrix. Given an nxn array, you simply define the slice for rows and columns to cover an m-sized window.

Let’s consider a practical example. Suppose you have a large 5x5 grid representing a game board, and you want to analyze a 3x3 sub-region starting at row 1, column 1. You would use slicing like this: grid[1:1+3, 1:1+3]. This Question & Answer :

I want to slice a NumPy nxn array. I want to extract an arbitrary selection of m rows and columns of that array (i.e. without any pattern in the numbers of rows/columns), making it a new, mxm array. For this example let us say the array is 4x4 and I want to extract a 2x2 array from it.

Here is our array:

from numpy import * x = range(16) x = reshape(x,(4,4)) print x [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11] [12 13 14 15]] 

The line and columns to remove are the same. The easiest case is when I want to extract a 2x2 submatrix that is at the beginning or at the end, i.e. :

In [33]: x[0:2,0:2] Out[33]: array([[0, 1], [4, 5]]) In [34]: x[2:,2:] Out[34]: array([[10, 11], [14, 15]]) 

But what if I need to remove another mixture of rows/columns? What if I need to remove the first and third lines/rows, thus extracting the submatrix [[5,7],[13,15]]? There can be any composition of rows/lines. I read somewhere that I just need to index my array using arrays/lists of indices for both rows and columns, but that doesn’t seem to work:

In [35]: x[[1,3],[1,3]] Out[35]: array([ 5, 15]) 

I found one way, which is:

In [61]: x[[1,3]][:,[1,3]] Out[61]: array([[ 5, 7], [13, 15]]) 

First issue with this is that it is hardly readable, although I can live with that. If someone has a better solution, I’d certainly like to hear it.

Other thing is I read on a forum that indexing arrays with arrays forces NumPy to make a copy of the desired array, thus when treating with large arrays this could become a problem. Why is that so / how does this mechanism work?

To answer this question, we have to look at how indexing a multidimensional array works in Numpy. Let’s first say you have the array x from your question. The buffer assigned to x will contain 16 ascending integers from 0 to 15. If you access one element, say x[i,j], NumPy has to figure out the memory location of this element relative to the beginning of the buffer. This is done by calculating in effect i*x.shape[1]+j (and multiplying with the size of an int to get an actual memory offset).

If you extract a subarray by basic slicing like y = x[0:2,0:2], the resulting object will share the underlying buffer with x. But what happens if you acces y[i,j]? NumPy can’t use i*y.shape[1]+j to calculate the offset into the array, because the data belonging to y is not consecutive in memory.

NumPy solves this problem by introducing strides. When calculating the memory offset for accessing x[i,j], what is actually calculated is i*x.strides[0]+j*x.strides[1] (and this already includes the factor for the size of an int):

x.strides (16, 4) 

When y is extracted like above, NumPy does not create a new buffer, but it does create a new array object referencing the same buffer (otherwise y would just be equal to x.) The new array object will have a different shape then x and maybe a different starting offset into the buffer, but will share the strides with x (in this case at least):

y.shape (2,2) y.strides (16, 4) 

This way, computing the memory offset for y[i,j] will yield the correct result.

But what should NumPy do for something like z=x[[1,3]]? The strides mechanism won’t allow correct indexing if the original buffer is used for z. NumPy theoretically could add some more sophisticated mechanism than the strides, but this would make element access relatively expensive, somehow defying the whole idea of an array. In addition, a view wouldn’t be a really lightweight object anymore.

This is covered in depth in the NumPy documentation on indexing.

Oh, and nearly forgot about your actual question: Here is how to make the indexing with multiple lists work as expected:

x[[[1],[3]],[1,3]] 

This is because the index arrays are broadcasted to a common shape. Of course, for this particular example, you can also make do with basic slicing:

x[1::2, 1::2]