#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
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]: 60#1D Array Slicing
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
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
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
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
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
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
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
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
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
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
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
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
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