Introduction
Extracting specific columns from a NumPy array uses array indexing. For a 2D array, arr[:, col_index] extracts a single column, and arr[:, [col1, col2]] extracts multiple columns. The : selects all rows, and the second index selects columns. NumPy also supports boolean indexing and fancy indexing for more complex column selection patterns.
Single Column
1import numpy as np
2
3data = np.array([
4 [1, 2, 3, 4],
5 [5, 6, 7, 8],
6 [9, 10, 11, 12]
7])
8
9# Extract column 0 (first column)
10col0 = data[:, 0]
11print(col0) # [1 5 9]
12
13# Extract column 2 (third column)
14col2 = data[:, 2]
15print(col2) # [3 7 11]
16
17# Extract the last column
18last = data[:, -1]
19print(last) # [4 8 12]
Note: data[:, 0] returns a 1D array of shape (3,). To keep it as a column vector (2D), use data[:, [0]] or data[:, 0:1].
Multiple Columns
1# Extract columns 0 and 2
2cols = data[:, [0, 2]]
3print(cols)
4# [[ 1 3]
5# [ 5 7]
6# [ 9 11]]
7
8# Extract columns 1, 3
9cols = data[:, [1, 3]]
10print(cols)
11# [[ 2 4]
12# [ 6 8]
13# [10 12]]
14
15# Reorder columns
16reordered = data[:, [3, 1, 0, 2]]
17print(reordered)
18# [[ 4 2 1 3]
19# [ 8 6 5 7]
20# [12 10 9 11]]
Column Range (Slicing)
1# Columns 1 through 3 (exclusive)
2cols = data[:, 1:3]
3print(cols)
4# [[ 2 3]
5# [ 6 7]
6# [10 11]]
7
8# First two columns
9first_two = data[:, :2]
10print(first_two)
11# [[1 2]
12# [5 6]
13# [9 10]]
14
15# Every other column
16every_other = data[:, ::2]
17print(every_other)
18# [[ 1 3]
19# [ 5 7]
20# [ 9 11]]
Boolean Column Selection
1# Select columns where the first row value is > 2
2mask = data[0] > 2
3print(mask) # [False False True True]
4
5cols = data[:, mask]
6print(cols)
7# [[ 3 4]
8# [ 7 8]
9# [11 12]]
10
11# Select columns by name using a separate list
12col_names = ["age", "height", "weight", "score"]
13wanted = ["height", "score"]
14mask = np.isin(col_names, wanted)
15cols = data[:, mask]
Named Columns with Structured Arrays
1# Structured array with named fields
2dt = np.dtype([("name", "U10"), ("age", "i4"), ("score", "f4")])
3records = np.array([
4 ("Alice", 30, 95.5),
5 ("Bob", 25, 88.0),
6 ("Charlie", 35, 72.3)
7], dtype=dt)
8
9# Access by column name
10print(records["name"]) # ['Alice' 'Bob' 'Charlie']
11print(records["score"]) # [95.5 88. 72.3]
12
13# Multiple columns (returns structured array)
14subset = records[["name", "score"]]
Extracting Columns into Separate Variables
1data = np.array([
2 [1, 2, 3],
3 [4, 5, 6],
4 [7, 8, 9]
5])
6
7# Unpack columns
8col_a, col_b, col_c = data.T # Transpose then unpack rows
9print(col_a) # [1 4 7]
10print(col_b) # [2 5 8]
11print(col_c) # [3 6 9]
12
13# Or unpack specific columns
14x, y = data[:, 0], data[:, 1]
Views vs Copies
1data = np.array([[1, 2, 3], [4, 5, 6]])
2
3# Slicing returns a VIEW (shared memory)
4view = data[:, 1:3]
5view[0, 0] = 99
6print(data) # [[1 99 3] [4 5 6]] — original modified!
7
8# Fancy indexing returns a COPY
9copy = data[:, [0, 2]]
10copy[0, 0] = 99
11print(data) # [[1 99 3] [4 5 6]] — original unchanged
12
13# Force a copy from a slice
14safe = data[:, 1:3].copy()
15safe[0, 0] = 0
16print(data) # Original unchanged
1# For very large arrays, column access patterns matter
2large = np.random.randn(1000000, 100)
3
4# Row-major (C order, default): row access is fast, column access is slower
5# Column-major (Fortran order): column access is fast
6
7# If you mainly access columns, use Fortran order
8large_f = np.asfortranarray(large)
9col = large_f[:, 50] # Faster column access
Common Pitfalls
Confusing data[:, 0] (1D) with data[:, [0]] (2D): Single index [:, 0] returns a 1D array of shape (n,). List index [:, [0]] returns a 2D column of shape (n, 1). This matters for operations that require 2D input like matrix multiplication.
Modifying a view and changing the original: Slice-based column extraction (data[:, 1:3]) returns a view. Modifying the view modifies the original array. Use .copy() if you need an independent copy.
Fancy indexing returning a copy: Unlike slicing, data[:, [0, 2]] returns a copy, not a view. Modifying the result does not affect the original. This inconsistency catches many people.
Using negative indices incorrectly: data[:, -1] gets the last column, but data[:, -1:] gets a 2D array with one column. The results have different shapes (1D vs 2D), which affects downstream operations.
Index out of bounds: data[:, 5] on a 4-column array raises IndexError. Check data.shape[1] before accessing columns by index, especially with dynamic data.
Summary
Use arr[:, col] for a single column and arr[:, [col1, col2]] for multiple columns
Use slicing arr[:, start:end] for column ranges
Boolean arrays can select columns based on conditions
Slicing creates views (shared memory); fancy indexing creates copies
Use .T (transpose) to unpack columns into separate variables
Check arr.shape[1] for the number of columns before indexing