Array Indexing and Slicing
In this chapter, we'll dive deep into NumPy array indexing and slicing operations, which are fundamental skills for data manipulation and analysis.
1D Array Indexing
Basic Indexing
python
import numpy as np
# Create 1D array
array = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
print("Original array:", array)
print("Array length:", len(array))
print()
# Forward indexing (starting from 0)
print("First element array[0]:", array[0])
print("Third element array[2]:", array[2])
print("Fifth element array[4]:", array[4])
print()
# Reverse indexing (starting from -1)
print("Last element array[-1]:", array[-1])
print("Second to last array[-2]:", array[-2])
print("Fifth from last array[-5]:", array[-5])Output:
Original array: [ 10 20 30 40 50 60 70 80 90 100]
Array length: 10
First element array[0]: 10
Third element array[2]: 30
Fifth element array[4]: 50
Last element array[-1]: 100
Second to last array[-2]: 90
Fifth from last array[-5]: 601D Array Slicing
python
import numpy as np
array = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print("Original array:", array)
print()
# Basic slice syntax: array[start:stop:step]
print("First 5 elements array[:5]:", array[:5])
print("Last 5 elements array[5:]:", array[5:])
print("Middle elements array[2:8]:", array[2:8])
print("All elements array[:]:", array[:])
print()
# Using step
print("Every other element array[::2]:", array[::2])
print("Every third element array[::3]:", array[::3])
print("Every other from index 1 array[1::2]:", array[1::2])
print()
# Reverse slicing
print("Reversed array[::-1]:", array[::-1])
print("Reversed every other array[::-2]:", array[::-2])
print("Last 5 elements array[-5:]:", array[-5:])
print("Middle from end array[-8:-2]:", array[-8:-2])Output:
Original array: [0 1 2 3 4 5 6 7 8 9]
First 5 elements array[:5]: [0 1 2 3 4]
Last 5 elements array[5:]: [5 6 7 8 9]
Middle elements array[2:8]: [2 3 4 5 6 7]
All elements array[:]: [0 1 2 3 4 5 6 7 8 9]
Every other element array[::2]: [0 2 4 6 8]
Every third element array[::3]: [0 3 6 9]
Every other from index 1 array[1::2]: [1 3 5 7 9]
Reversed array[::-1]: [9 8 7 6 5 4 3 2 1 0]
Reversed every other array[::-2]: [9 7 5 3 1]
Last 5 elements array[-5:]: [5 6 7 8 9]
Middle from end array[-8:-2]: [2 3 4 5 6 7]2D Array Indexing
Basic 2D Indexing
python
import numpy as np
# Create 2D array
array_2d = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
])
print("2D array:")
print(array_2d)
print(f"Array shape: {array_2d.shape}")
print()
# Access single element
print("Row 1, Col 1 array_2d[0, 0]:", array_2d[0, 0])
print("Row 2, Col 3 array_2d[1, 2]:", array_2d[1, 2])
print("Last row, last col array_2d[-1, -1]:", array_2d[-1, -1])
print("Row 3, Col 2 array_2d[2, 1]:", array_2d[2, 1])
print()
# Access entire row
print("First row array_2d[0, :]:", array_2d[0, :])
print("Third row array_2d[2, :]:", array_2d[2, :])
print("Last row array_2d[-1, :]:", array_2d[-1, :])
print()
# Access entire column
print("First column array_2d[:, 0]:", array_2d[:, 0])
print("Third column array_2d[:, 2]:", array_2d[:, 2])
print("Last column array_2d[:, -1]:", array_2d[:, -1])Output:
2D array:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
Array shape: (4, 4)
Row 1, Col 1 array_2d[0, 0]: 1
Row 2, Col 3 array_2d[1, 2]: 7
Last row, last col array_2d[-1, -1]: 16
Row 3, Col 2 array_2d[2, 1]: 10
First row array_2d[0, :]: [1 2 3 4]
Third row array_2d[2, :]: [ 9 10 11 12]
Last row array_2d[-1, :]: [13 14 15 16]
First column array_2d[:, 0]: [ 1 5 9 13]
Third column array_2d[:, 2]: [ 3 7 11 15]
Last column array_2d[:, -1]: [ 4 8 12 16]2D Array Slicing
python
import numpy as np
array_2d = np.arange(20).reshape(4, 5)
print("Original array:")
print(array_2d)
print()
# Row slicing
print("First two rows array_2d[:2, :]:")
print(array_2d[:2, :])
print()
print("Last two rows array_2d[2:, :]:")
print(array_2d[2:, :])
print()
# Column slicing
print("First three columns array_2d[:, :3]:")
print(array_2d[:, :3])
print()
print("Last two columns array_2d[:, -2:]:")
print(array_2d[:, -2:])
print()
# Row and column slicing together
print("Middle 2x3 subarray array_2d[1:3, 1:4]:")
print(array_2d[1:3, 1:4])
print()
# Using step
print("Every other row array_2d[::2, :]:")
print(array_2d[::2, :])
print()
print("Every other column array_2d[:, ::2]:")
print(array_2d[:, ::2])
print()
# Complex slicing
print("Every other row and column array_2d[::2, ::2]:")
print(array_2d[::2, ::2])Output:
Original array:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
First two rows array_2d[:2, :]:
[[0 1 2 3 4]
[5 6 7 8 9]]
Last two rows array_2d[2:, :]:
[[10 11 12 13 14]
[15 16 17 18 19]]
First three columns array_2d[:, :3]:
[[ 0 1 2]
[ 5 6 7]
[10 11 12]
[15 16 17]]
Last two columns array_2d[:, -2:]:
[[ 3 4]
[ 8 9]
[13 14]
[18 19]]
Middle 2x3 subarray array_2d[1:3, 1:4]:
[[ 6 7 8]
[11 12 13]]
Every other row array_2d[::2, :]:
[[ 0 1 2 3 4]
[10 11 12 13 14]]
Every other column array_2d[:, ::2]:
[[ 0 2 4]
[ 5 7 9]
[10 12 14]
[15 17 19]]
Every other row and column array_2d[::2, ::2]:
[[ 0 2 4]
[10 12 14]]Advanced Indexing
Integer Array Indexing
python
import numpy as np
# 1D array integer array indexing
array = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
print("Original array:", array)
# Using index array
indices = np.array([0, 2, 4, 6])
print("Index array:", indices)
print("Selected elements:", array[indices])
print()
# Can repeat indices
repeated_indices = np.array([1, 1, 3, 3, 5])
print("Repeated indices:", repeated_indices)
print("Selected elements:", array[repeated_indices])
print()
# 2D array integer array indexing
array_2d = np.arange(12).reshape(3, 4)
print("2D array:")
print(array_2d)
print()
# Select specific rows
row_indices = np.array([0, 2])
print("Select rows 0 and 2:")
print(array_2d[row_indices])
print()
# Select specific position elements
row_idx = np.array([0, 1, 2])
col_idx = np.array([1, 2, 3])
print("Select positions (0,1), (1,2), (2,3):")
print(array_2d[row_idx, col_idx])Output:
Original array: [ 10 20 30 40 50 60 70 80 90 100]
Index array: [0 2 4 6]
Selected elements: [10 30 50 70]
Repeated indices: [1 1 3 3 5]
Selected elements: [20 20 40 40 60]
2D array:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
Select rows 0 and 2:
[[ 0 1 2 3]
[ 8 9 10 11]]
Select positions (0,1), (1,2), (2,3):
[ 1 6 11]Boolean Indexing
python
import numpy as np
# Create array
array = np.array([1, 5, 3, 8, 2, 9, 4, 7, 6])
print("Original array:", array)
print()
# Create boolean condition
condition = array > 5
print("Condition array > 5:", condition)
print("Elements satisfying condition:", array[condition])
print()
# Multiple conditions
condition_and = (array > 3) & (array < 8)
print("Condition (array > 3) & (array < 8):", condition_and)
print("Elements satisfying condition:", array[condition_and])
print()
condition_or = (array < 3) | (array > 7)
print("Condition (array < 3) | (array > 7):", condition_or)
print("Elements satisfying condition:", array[condition_or])
print()
# 2D array boolean indexing
array_2d = np.random.randint(1, 10, (4, 4))
print("2D random array:")
print(array_2d)
print()
# Find elements greater than 5
mask = array_2d > 5
print("Positions of elements > 5:")
print(mask)
print("Values of elements > 5:", array_2d[mask])
print()
# Find max value position in each row
max_in_rows = array_2d == array_2d.max(axis=1, keepdims=True)
print("Max value positions in each row:")
print(max_in_rows)
print("Max values in each row:", array_2d[max_in_rows])Output:
Original array: [1 5 3 8 2 9 4 7 6]
Condition array > 5: [False False False True False True False True True]
Elements satisfying condition: [8 9 7 6]
Condition (array > 3) & (array < 8): [False True False False False False True True True]
Elements satisfying condition: [5 4 7 6]
Condition (array < 3) | (array > 7): [ True False False True True True False False False]
Elements satisfying condition: [1 8 2 9]
2D random array:
[[6 1 4 4]
[8 4 6 3]
[5 8 7 9]
[2 6 3 1]]
Positions of elements > 5:
[[ True False False False]
[ True False True False]
[False True True True]
[False True False False]]
Values of elements > 5: [6 8 6 8 7 9 6]
Max value positions in each row:
[[ True False False False]
[ True False False False]
[False False False True]
[False True False False]]
Max values in each row: [6 8 9 6]Fancy Indexing
Using Index Arrays
python
import numpy as np
# Create 2D array
array_2d = np.arange(24).reshape(6, 4)
print("Original array:")
print(array_2d)
print()
# Select specific rows (in order)
row_indices = [1, 3, 5]
print(f"Select rows {row_indices}:")
print(array_2d[row_indices])
print()
# Select specific rows (reordered)
row_indices_reorder = [5, 1, 3]
print(f"Select rows {row_indices_reorder} (reordered):")
print(array_2d[row_indices_reorder])
print()
# Select rows and columns together
row_idx = [0, 2, 4]
col_idx = [1, 3, 2]
print(f"Select positions {list(zip(row_idx, col_idx))}:")
print(array_2d[row_idx, col_idx])
print()
# Use grid indexing to select submatrix
rows = np.array([1, 3])
cols = np.array([0, 2])
print("Select intersection of rows 1,3 and cols 0,2:")
print(array_2d[np.ix_(rows, cols)])Output:
Original 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]]
Select rows [1, 3, 5]:
[[ 4 5 6 7]
[12 13 14 15]
[20 21 22 23]]
Select rows [5, 1, 3] (reordered):
[[20 21 22 23]
[ 4 5 6 7]
[12 13 14 15]]
Select positions [(0, 1), (2, 3), (4, 2)]:
[ 1 11 18]
Select intersection of rows 1,3 and cols 0,2:
[[ 4 6]
[12 14]]Combining Different Index Types
python
import numpy as np
array_2d = np.arange(20).reshape(4, 5)
print("Original array:")
print(array_2d)
print()
# Combine integer index and slice
print("Row 2, first 3 columns array_2d[2, :3]:")
print(array_2d[2, :3])
print()
# Combine boolean index and slice
row_mask = np.array([True, False, True, False])
print("Select rows 1 and 3, last 3 columns:")
print(array_2d[row_mask, -3:])
print()
# Combine integer array index and slice
row_indices = [0, 2]
print("Select rows 0 and 2, middle 3 columns:")
print(array_2d[row_indices, 1:4])
print()
# Complex combined indexing
print("Select rows satisfying condition, specific columns:")
row_condition = array_2d[:, 0] % 2 == 0 # Rows where first column is even
col_indices = [1, 3, 4] # Select columns 1, 3, 4
result = array_2d[row_condition][:, col_indices]
print(f"Row condition: {row_condition}")
print(f"Column indices: {col_indices}")
print("Result:")
print(result)Output:
Original array:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
Row 2, first 3 columns array_2d[2, :3]:
[10 11 12]
Select rows 1 and 3, last 3 columns:
[[ 2 3 4]
[12 13 14]]
Select rows 0 and 2, middle 3 columns:
[[ 1 2 3]
[11 12 13]]
Select rows satisfying condition, specific columns:
Row condition: [ True False True False]
Column indices: [1, 3, 4]
Result:
[[ 1 3 4]
[11 13 14]]Modifying Array Elements
Modifying Elements via Indexing
python
import numpy as np
# 1D array modification
array_1d = np.array([1, 2, 3, 4, 5])
print("Original 1D array:", array_1d)
# Modify single element
array_1d[2] = 99
print("After modifying index 2:", array_1d)
# Modify multiple elements
array_1d[[0, 4]] = [88, 77]
print("After modifying indices 0 and 4:", array_1d)
print()
# 2D array modification
array_2d = np.arange(12).reshape(3, 4)
print("Original 2D array:")
print(array_2d)
# Modify single element
array_2d[1, 2] = 999
print("After modifying position (1,2):")
print(array_2d)
# Modify entire row
array_2d[0, :] = [100, 101, 102, 103]
print("After modifying row 0:")
print(array_2d)
# Modify entire column
array_2d[:, 1] = [200, 201, 202]
print("After modifying column 1:")
print(array_2d)Output:
Original 1D array: [1 2 3 4 5]
After modifying index 2: [ 1 2 99 4 5]
After modifying indices 0 and 4: [88 2 99 4 77]
Original 2D array:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
After modifying position (1,2):
[[ 0 1 2 3]
[ 4 5 999 7]
[ 8 9 10 11]]
After modifying row 0:
[[100 101 102 103]
[ 4 5 999 7]
[ 8 9 10 11]]
After modifying column 1:
[[100 200 102 103]
[ 4 201 999 7]
[ 8 202 10 11]]Modifying Elements via Boolean Indexing
python
import numpy as np
array = np.array([1, 5, 3, 8, 2, 9, 4, 7, 6])
print("Original array:", array)
# Set elements > 5 to 0
array[array > 5] = 0
print("After setting elements > 5 to 0:", array)
# Recreate array
array = np.array([1, 5, 3, 8, 2, 9, 4, 7, 6])
print("\nRecreated array:", array)
# Multiply even elements by 10
array[array % 2 == 0] *= 10
print("After multiplying even elements by 10:", array)
# Conditional replacement
array = np.array([1, 5, 3, 8, 2, 9, 4, 7, 6])
print("\nRecreated array:", array)
# Use np.where for conditional replacement
result = np.where(array > 5, array, 0) # Keep values > 5, else 0
print("Using np.where conditional replacement:", result)
# Complex conditional replacement
result = np.where((array > 3) & (array < 8), array * 2, array)
print("Elements 3<x<8 multiplied by 2:", result)Output:
Original array: [1 5 3 8 2 9 4 7 6]
After setting elements > 5 to 0: [1 5 3 0 2 0 4 0 0]
Recreated array: [1 5 3 8 2 9 4 7 6]
After multiplying even elements by 10: [ 1 5 3 80 20 9 40 7 60]
Recreated array: [1 5 3 8 2 9 4 7 6]
Using np.where conditional replacement: [0 0 0 8 0 9 0 7 6]
Elements 3<x<8 multiplied by 2: [ 1 10 3 8 2 9 8 14 12]Practical Examples
Example 1: Data Cleaning
python
import numpy as np
# Simulate data with outliers
np.random.seed(42)
data = np.random.normal(50, 10, 20) # Normal data
data[5] = 200 # Outlier
data[15] = -50 # Outlier
print("Original data:")
print(data)
print(f"Data statistics: mean={np.mean(data):.2f}, std={np.std(data):.2f}")
print()
# Identify outliers (beyond 3 standard deviations)
mean_val = np.mean(data)
std_val = np.std(data)
threshold = 3 * std_val
outliers_mask = np.abs(data - mean_val) > threshold
print("Outlier positions:", np.where(outliers_mask)[0])
print("Outlier values:", data[outliers_mask])
print()
# Clean data: remove outliers
clean_data = data[~outliers_mask]
print("Cleaned data:")
print(clean_data)
print(f"Cleaned statistics: mean={np.mean(clean_data):.2f}, std={np.std(clean_data):.2f}")
print()
# Or replace outliers with median
data_replaced = data.copy()
median_val = np.median(data[~outliers_mask])
data_replaced[outliers_mask] = median_val
print("After replacing outliers with median:")
print(data_replaced)
print(f"Replaced statistics: mean={np.mean(data_replaced):.2f}, std={np.std(data_replaced):.2f}")Example 2: Image Processing
python
import numpy as np
# Create a simple "image" (8x8 grayscale)
np.random.seed(42)
image = np.random.randint(0, 256, (8, 8), dtype=np.uint8)
print("Original image:")
print(image)
print()
# Extract region of interest (ROI)
roi = image[2:6, 2:6] # Extract center 4x4 region
print("Region of Interest (ROI):")
print(roi)
print()
# Image thresholding
threshold = 128
binary_image = (image > threshold).astype(np.uint8) * 255
print(f"Binary image (threshold={threshold}):")
print(binary_image)
print()
# Image masking
# Create circular mask
y, x = np.ogrid[:8, :8]
center_y, center_x = 4, 4
radius = 3
circle_mask = (x - center_x)**2 + (y - center_y)**2 <= radius**2
print("Circular mask:")
print(circle_mask.astype(int))
print()
# Apply mask
masked_image = image.copy()
masked_image[~circle_mask] = 0 # Set pixels outside circle to 0
print("Image with circular mask applied:")
print(masked_image)Example 3: Data Analysis
python
import numpy as np
# Simulate student grade data
np.random.seed(42)
students = 100
subjects = 5
scores = np.random.normal(75, 15, (students, subjects)) # Mean 75, std 15
scores = np.clip(scores, 0, 100) # Limit to 0-100 range
print(f"Score data shape: {scores.shape}")
print(f"Score range: {scores.min():.1f} - {scores.max():.1f}")
print()
# Find excellent students (average > 85)
average_scores = np.mean(scores, axis=1)
excellent_students = average_scores > 85
print(f"Number of excellent students: {np.sum(excellent_students)}")
print(f"Excellent student averages: {average_scores[excellent_students][:5]}")
print()
# Find students needing help (any subject < 60)
failing_mask = scores < 60
students_need_help = np.any(failing_mask, axis=1)
print(f"Students needing help: {np.sum(students_need_help)}")
print()
# Analyze each subject
subject_names = ['Math', 'Language', 'English', 'Physics', 'Chemistry']
for i, subject in enumerate(subject_names):
subject_scores = scores[:, i]
print(f"{subject}: mean={np.mean(subject_scores):.1f}, "
f"max={np.max(subject_scores):.1f}, "
f"min={np.min(subject_scores):.1f}, "
f"pass rate={np.sum(subject_scores >= 60)/len(subject_scores)*100:.1f}%")
print()
# Find each student's best and worst subjects
best_subjects = np.argmax(scores, axis=1)
worst_subjects = np.argmin(scores, axis=1)
print("Best/worst subjects for first 5 students:")
for i in range(5):
print(f"Student {i+1}: Best-{subject_names[best_subjects[i]]}, "
f"Worst-{subject_names[worst_subjects[i]]}")Performance Considerations
View vs Copy
python
import numpy as np
array = np.arange(10)
print("Original array:", array)
# Slicing creates view (shared memory)
slice_view = array[2:8]
print("Slice view:", slice_view)
print("Shares memory:", np.shares_memory(array, slice_view))
# Modifying view affects original
slice_view[0] = 999
print("After modifying view, original:", array)
print()
# Fancy indexing creates copy (independent memory)
array = np.arange(10) # Recreate
fancy_copy = array[[1, 3, 5, 7]]
print("Fancy index result:", fancy_copy)
print("Shares memory:", np.shares_memory(array, fancy_copy))
# Modifying copy doesn't affect original
fancy_copy[0] = 888
print("After modifying copy, original:", array)
print("Modified copy:", fancy_copy)Output:
Original array: [0 1 2 3 4 5 6 7 8 9]
Slice view: [2 3 4 5 6 7]
Shares memory: True
After modifying view, original: [ 0 1 999 3 4 5 6 7 8 9]
Fancy index result: [1 3 5 7]
Shares memory: False
After modifying copy, original: [0 1 2 3 4 5 6 7 8 9]
Modified copy: [888 3 5 7]Chapter Summary
In this chapter, we learned:
- Basic indexing methods for 1D and multidimensional arrays
- Various slicing syntax and techniques
- Integer array indexing and boolean indexing
- Advanced fancy indexing usage
- Modifying array elements via indexing
- Indexing techniques in practical applications
- Performance considerations for views and copies
Next Steps
In the next chapter, we'll learn NumPy's mathematical operations and functions, including basic operations, statistical functions, trigonometric functions, and more.
Exercises
- Create a 5x5 array and extract its diagonal elements
- Extract all even elements from a 2D array
- Use boolean indexing to find local maxima in an array
- Implement a function to swap specified rows and columns in a 2D array
- Create an image mask that only keeps the circular center region of the image