📊 Array Size and Indexing

Understanding array size and indexing is essential for accessing and manipulating your data! Size tells you how many elements you have, while indexing lets you pinpoint specific values. These fundamentals are the building blocks for all data analysis and array operations.

Think of indexing like having coordinates to find any piece of data in your array!

import numpy as np

# Array size and indexing basics
data = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]])

print(f"Array: \n{data}")
print(f"Total size: {data.size} elements")
print(f"Shape: {data.shape}")

# Basic indexing examples
print(f"First element: {data[0, 0]}")
print(f"Middle element: {data[1, 1]}")  
print(f"Last element: {data[2, 2]}")
print(f"First row: {data[0]}")
print(f"Last column: {data[:, 2]}")

📏 Understanding Array Size

Array size tells you the total number of elements, which is crucial for loops, memory planning, and data processing:

import numpy as np

# Different ways to measure array size
vector = np.array([1, 2, 3, 4, 5])
matrix = np.array([[1, 2, 3], [4, 5, 6]])
cube = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])

print(f"1D Array: {vector}")
print(f"  Size: {vector.size}")
print(f"  Shape: {vector.shape}")
print(f"  Length: {len(vector)}")

print(f"2D Array: \n{matrix}")
print(f"  Size: {matrix.size}")
print(f"  Shape: {matrix.shape}")
print(f"  Rows: {matrix.shape[0]}, Columns: {matrix.shape[1]}")

print(f"3D Array shape: {cube.shape}")
print(f"  Size: {cube.size}")
print(f"  Calculation: {cube.shape[0]} × {cube.shape[1]} × {cube.shape[2]} = {cube.size}")

Size vs Shape vs Length:

  • size: Total number of elements (all dimensions)
  • shape: Dimensions of each axis
  • len(): Size of first dimension only

🎯 1D Array Indexing

Start with 1D arrays - the simplest indexing case:

import numpy as np

# 1D indexing examples
temperatures = np.array([20.5, 22.1, 19.8, 21.3, 23.0, 18.7])

print(f"Temperatures: {temperatures}")
print(f"Array size: {temperatures.size}")

# Positive indexing
print(f"First temp: {temperatures[0]}°C")
print(f"Third temp: {temperatures[2]}°C")
print(f"Last temp: {temperatures[5]}°C")

# Negative indexing (from the end)
print(f"Last temp: {temperatures[-1]}°C")
print(f"Second to last: {temperatures[-2]}°C")
print(f"Third from end: {temperatures[-3]}°C")

# Using size for dynamic indexing
last_index = temperatures.size - 1
print(f"Last index: {last_index}")
print(f"Last temp (dynamic): {temperatures[last_index]}°C")

📊 2D Array Indexing

2D arrays need two indices: [row, column]:

import numpy as np

# 2D indexing examples
grades = np.array([
    [85, 92, 78, 91],  # Student 1
    [79, 88, 95, 82],  # Student 2  
    [91, 85, 89, 94],  # Student 3
    [88, 90, 87, 89]   # Student 4
])

print(f"Grades array: \n{grades}")
print(f"Shape: {grades.shape} (students, subjects)")

# Individual element access
print(f"Student 1, Subject 1: {grades[0, 0]}")
print(f"Student 2, Subject 3: {grades[1, 2]}")
print(f"Student 4, Subject 4: {grades[3, 3]}")

# Row and column access
print(f"Student 1 all grades: {grades[0]}")        # Entire row
print(f"Subject 1 all grades: {grades[:, 0]}")     # Entire column
print(f"Last student grades: {grades[-1]}")        # Last row
print(f"Last subject grades: {grades[:, -1]}")     # Last column

🧮 Multi-dimensional Indexing

For 3D and higher dimensions, you need more indices:

import numpy as np

# 3D array indexing
# Shape: (classes, students, subjects)
school_data = np.array([
    [[85, 90, 78], [92, 88, 85]],  # Class 1: 2 students, 3 subjects
    [[79, 85, 91], [88, 92, 87]],  # Class 2: 2 students, 3 subjects  
    [[91, 89, 94], [85, 87, 90]]   # Class 3: 2 students, 3 subjects
])

print(f"School data shape: {school_data.shape}")
print(f"Classes: {school_data.shape[0]}")
print(f"Students per class: {school_data.shape[1]}")
print(f"Subjects: {school_data.shape[2]}")

# 3D indexing examples
print(f"Class 1, Student 1, Subject 1: {school_data[0, 0, 0]}")
print(f"Class 2, Student 2, Subject 3: {school_data[1, 1, 2]}")

# Accessing slices
print(f"All Class 1 data: \n{school_data[0]}")
print(f"Student 1 from all classes: \n{school_data[:, 0, :]}")
print(f"Subject 1 from all: {school_data[:, :, 0].flatten()}")

🔍 Array Size in Practice

Understanding size helps with data processing and validation:

import numpy as np

# Practical size usage
print("📊 Practical Array Size Usage")
print("=" * 30)

# Example 1: Data validation
sensor_data = np.random.randn(24, 7)  # 24 hours, 7 days
expected_readings = 24 * 7

print(f"Sensor data shape: {sensor_data.shape}")
print(f"Expected readings: {expected_readings}")
print(f"Actual readings: {sensor_data.size}")
print(f"Data complete: {sensor_data.size == expected_readings}")

# Example 2: Memory estimation
image_height, image_width = 1080, 1920
color_channels = 3
total_pixels = image_height * image_width * color_channels

print(f"\nImage analysis:")
print(f"Resolution: {image_height}×{image_width}")
print(f"Total pixels: {image_height * image_width:,}")
print(f"With RGB channels: {total_pixels:,}")

# Create and check
image_array = np.zeros((image_height, image_width, color_channels), dtype=np.uint8)
print(f"Array size: {image_array.size:,}")
print(f"Memory usage: {image_array.nbytes / 1024 / 1024:.1f} MB")

🎯 Safe Indexing Practices

Avoid common indexing errors with these practices:

import numpy as np

# Safe indexing examples
data = np.array([10, 20, 30, 40, 50])

print(f"Data: {data}")
print(f"Valid indices: 0 to {len(data) - 1}")

# Safe index checking
def safe_get(array, index):
    if 0 <= index < len(array):
        return array[index]
    else:
        return f"Index {index} out of bounds"

# Test safe indexing
print(f"Index 2: {safe_get(data, 2)}")
print(f"Index 10: {safe_get(data, 10)}")  # Out of bounds
print(f"Index -1: {safe_get(data, -1)}")  # This would be valid in NumPy

# Using negative indices safely
print(f"Last element: {data[-1]}")
print(f"Second to last: {data[-2]}")

# Dynamic indexing with size
middle_index = data.size // 2
print(f"Middle element (index {middle_index}): {data[middle_index]}")

📋 Index vs Position Understanding

Understanding the difference between position and index is crucial:

import numpy as np

# Position vs Index explanation
scores = np.array([85, 92, 78, 95, 89])

print(f"Scores: {scores}")
print(f"Array size: {scores.size}")

print(f"\nPosition vs Index:")
for i in range(scores.size):
    position = i + 1  # Human-friendly position
    value = scores[i]  # Computer index
    print(f"Position {position} (Index {i}): {value}")

# Finding elements
target_score = 95
index_of_target = np.where(scores == target_score)[0]
if len(index_of_target) > 0:
    idx = index_of_target[0]
    print(f"\nScore {target_score} found at:")
    print(f"  Index: {idx}")
    print(f"  Position: {idx + 1}")
else:
    print(f"Score {target_score} not found")

🔄 Size and Indexing with Reshaping

Array size stays constant during reshaping, but indexing patterns change:

import numpy as np

# Size and indexing with reshaping
original = np.arange(12)  # 12 elements: 0, 1, 2, ..., 11
reshaped = original.reshape(3, 4)

print(f"Original: {original}")
print(f"  Size: {original.size}")
print(f"  Element at index 5: {original[5]}")

print(f"Reshaped: \n{reshaped}")
print(f"  Size: {reshaped.size} (unchanged)")
print(f"  Element at [1, 1]: {reshaped[1, 1]}")

# Finding equivalent positions
flat_index = 5
row = flat_index // 4  # 4 columns
col = flat_index % 4
print(f"Flat index {flat_index} → Row {row}, Column {col}")
print(f"Values match: {original[flat_index]} == {reshaped[row, col]}")

# Using flat indexing
print(f"Using flat indexing: {reshaped.flat[5]}")

🎯 Key Takeaways

🚀 What's Next?

Perfect! You now understand array properties completely - shape, dimensions, data types, size, and indexing. Next, let's explore array operations where you'll put this knowledge to work with mathematical computations.

Continue to: Basic Mathematical Operations

Ready to compute with arrays! ⚡✨

Was this helpful?

😔Poor
🙁Fair
😊Good
😄Great
🤩Excellent