DEV Community

Vuk Rosić
Vuk Rosić

Posted on

NumPy Essentials: Arrays and vectorization

NumPy Essentials: Arrays and Vectorization

Part 1: Getting Started

import numpy as np # Create your first array arr = np.array([1, 2, 3, 4, 5]) print(arr) # [1 2 3 4 5] 
Enter fullscreen mode Exit fullscreen mode

What happened: We converted a Python list into a NumPy array - the foundation of scientific computing.

Part 2: Arrays vs Lists

# Python list python_list = [1, 2, 3, 4, 5] print(type(python_list)) # <class 'list'>  # NumPy array numpy_array = np.array([1, 2, 3, 4, 5]) print(type(numpy_array)) # <class 'numpy.ndarray'> 
Enter fullscreen mode Exit fullscreen mode

Key difference: Lists store objects, arrays store numbers - much faster for math!

Part 3: Array Properties

arr = np.array([1, 2, 3, 4, 5]) print(arr.shape) # (5,) - 5 elements in 1 dimension print(arr.size) # 5 - total number of elements print(arr.dtype) # int64 - data type 
Enter fullscreen mode Exit fullscreen mode

Intuition: Shape tells you the dimensions, size tells you total elements.

Part 4: Creating Arrays

# Zeros zeros = np.zeros(5) # [0. 0. 0. 0. 0.]  # Ones ones = np.ones(3) # [1. 1. 1.]  # Range range_arr = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]  # Evenly spaced linspace = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1. ] 
Enter fullscreen mode Exit fullscreen mode

Practice: Create arrays filled with specific values or patterns.

Part 5: 2D Arrays (Matrices)

# Create a 2D array matrix = np.array([[1, 2, 3], [4, 5, 6]]) print(matrix.shape) # (2, 3) - 2 rows, 3 columns print(matrix.size) # 6 - total elements 
Enter fullscreen mode Exit fullscreen mode

Visualization: Think of it as a table with rows and columns.

Part 6: Array Creation Shortcuts

# 2D zeros zeros_2d = np.zeros((3, 4)) # 3x4 matrix of zeros  # Identity matrix identity = np.eye(3) # 3x3 identity matrix  # Random numbers random_arr = np.random.random(5) # 5 random numbers [0,1) 
Enter fullscreen mode Exit fullscreen mode

Use cases: Initialize matrices for machine learning, create test data.

Part 7: Array Indexing

arr = np.array([10, 20, 30, 40, 50]) # Single element print(arr[0]) # 10 - first element print(arr[-1]) # 50 - last element  # Multiple elements print(arr[1:4]) # [20 30 40] - slice notation 
Enter fullscreen mode Exit fullscreen mode

Rule: Same as Python lists, but much faster for large arrays.

Part 8: 2D Array Indexing

matrix = np.array([[1, 2, 3], [4, 5, 6]]) # Single element print(matrix[0, 1]) # 2 - row 0, column 1  # Entire row print(matrix[1, :]) # [4 5 6] - row 1, all columns  # Entire column print(matrix[:, 2]) # [3 6] - all rows, column 2 
Enter fullscreen mode Exit fullscreen mode

Syntax: [row, column] - comma separates dimensions.

Part 9: The Magic of Vectorization

# Python way (slow) python_list = [1, 2, 3, 4, 5] result = [] for x in python_list: result.append(x * 2) # NumPy way (fast) numpy_array = np.array([1, 2, 3, 4, 5]) result = numpy_array * 2 # [2 4 6 8 10] 
Enter fullscreen mode Exit fullscreen mode

Vectorization: Apply operations to entire arrays at once - no loops needed!

Part 10: Element-wise Operations

a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) # Basic operations print(a + b) # [5 7 9] - addition print(a - b) # [-3 -3 -3] - subtraction print(a * b) # [4 10 18] - multiplication print(a / b) # [0.25 0.4 0.5] - division 
Enter fullscreen mode Exit fullscreen mode

Key insight: Operations happen element-by-element automatically.

Part 11: Broadcasting

# Array and scalar arr = np.array([1, 2, 3, 4]) result = arr + 10 # [11 12 13 14]  # Different shapes a = np.array([[1, 2, 3]]) # 1x3 b = np.array([[10], [20]]) # 2x1 result = a + b # 2x3 result 
Enter fullscreen mode Exit fullscreen mode

Broadcasting: NumPy automatically expands arrays to compatible shapes.

Part 12: Mathematical Functions

arr = np.array([1, 4, 9, 16]) # Common functions print(np.sqrt(arr)) # [1. 2. 3. 4.] - square root print(np.log(arr)) # natural logarithm print(np.exp(arr)) # exponential print(np.sin(arr)) # sine 
Enter fullscreen mode Exit fullscreen mode

Advantage: All functions work element-wise across entire arrays.

Part 13: Array Statistics

data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # Basic statistics print(np.mean(data)) # 5.5 - average print(np.median(data)) # 5.5 - middle value print(np.std(data)) # 2.87 - standard deviation print(np.sum(data)) # 55 - total 
Enter fullscreen mode Exit fullscreen mode

Use case: Quick analysis of datasets without writing loops.

Part 14: Array Reshaping

arr = np.array([1, 2, 3, 4, 5, 6]) # Reshape to 2x3 reshaped = arr.reshape(2, 3) print(reshaped) # [[1 2 3] # [4 5 6]]  # Flatten back to 1D flat = reshaped.flatten() # [1 2 3 4 5 6] 
Enter fullscreen mode Exit fullscreen mode

Rule: Total elements must stay the same (2×3 = 6 elements).

Part 15: Boolean Indexing

data = np.array([1, 5, 3, 8, 2, 9]) # Create boolean mask mask = data > 4 # [False True False True False True]  # Filter data filtered = data[mask] # [5 8 9]  # One-liner big_numbers = data[data > 4] # [5 8 9] 
Enter fullscreen mode Exit fullscreen mode

Power: Select elements based on conditions without loops.

Part 16: Array Concatenation

a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) # Concatenate combined = np.concatenate([a, b]) # [1 2 3 4 5 6]  # Stack vertically stacked = np.vstack([a, b]) # [[1 2 3] # [4 5 6]] 
Enter fullscreen mode Exit fullscreen mode

Use case: Combine datasets or results from different computations.

Part 17: Matrix Operations

# Matrix multiplication A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 6], [7, 8]]) # Element-wise multiplication element_wise = A * B # [[5 12] [21 32]]  # Matrix multiplication matrix_mult = A @ B # [[19 22] [43 50]] 
Enter fullscreen mode Exit fullscreen mode

Difference: * is element-wise, @ is true matrix multiplication.

Part 18: Performance Comparison

import time # Large arrays size = 1000000 a = np.random.random(size) b = np.random.random(size) # Time NumPy start = time.time() result = a + b numpy_time = time.time() - start print(f"NumPy time: {numpy_time:.4f} seconds") # Typically 100x faster than pure Python! 
Enter fullscreen mode Exit fullscreen mode

Why faster: NumPy uses optimized C code under the hood.

Part 19: Common Patterns

# Generate data x = np.linspace(0, 10, 100) # 100 points from 0 to 10 y = np.sin(x) # Sine wave  # Find peaks peaks = y[y > 0.9] # Normalize data normalized = (y - np.mean(y)) / np.std(y) 
Enter fullscreen mode Exit fullscreen mode

Real-world: Data generation, filtering, and preprocessing.

Part 20: Advanced Indexing

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # Fancy indexing rows = [0, 2] cols = [1, 2] result = arr[rows, cols] # [2 9] - elements at (0,1) and (2,2)  # Boolean indexing with conditions mask = (arr > 3) & (arr < 8) # Multiple conditions filtered = arr[mask] # [4 5 6 7] 
Enter fullscreen mode Exit fullscreen mode

Power: Extract complex patterns from data with simple syntax.

Part 21: Array Sorting

data = np.array([3, 1, 4, 1, 5, 9, 2, 6]) # Sort array sorted_data = np.sort(data) # [1 1 2 3 4 5 6 9]  # Get sort indices indices = np.argsort(data) # [1 3 6 0 2 7 4 8]  # Sort 2D array matrix = np.array([[3, 1], [4, 2]]) sorted_matrix = np.sort(matrix, axis=1) # Sort each row 
Enter fullscreen mode Exit fullscreen mode

Use case: Order data for analysis or find top/bottom values.

Part 22: Working with NaN

data = np.array([1, 2, np.nan, 4, 5]) # Check for NaN has_nan = np.isnan(data) # [False False True False False]  # Remove NaN clean_data = data[~np.isnan(data)] # [1. 2. 4. 5.]  # NaN-aware functions mean_ignore_nan = np.nanmean(data) # 3.0 
Enter fullscreen mode Exit fullscreen mode

Real data: Often contains missing values - NumPy handles them gracefully.

Part 23: Array Memory and Views

arr = np.array([1, 2, 3, 4, 5]) # Slicing creates a view (shares memory) view = arr[1:4] view[0] = 999 print(arr) # [1 999 3 4 5] - original changed!  # Copy creates new array copy = arr.copy() copy[0] = 777 print(arr) # [1 999 3 4 5] - original unchanged 
Enter fullscreen mode Exit fullscreen mode

Memory efficiency: Views save memory, copies ensure independence.

Part 24: Practical Example - Data Analysis

# Simulate temperature data days = 30 temperatures = np.random.normal(25, 5, days) # Mean 25°C, std 5°C  # Analysis avg_temp = np.mean(temperatures) hot_days = np.sum(temperatures > 30) cold_days = np.sum(temperatures < 20) temp_range = np.max(temperatures) - np.min(temperatures) print(f"Average: {avg_temp:.1f}°C") print(f"Hot days (>30°C): {hot_days}") print(f"Cold days (<20°C): {cold_days}") print(f"Temperature range: {temp_range:.1f}°C") 
Enter fullscreen mode Exit fullscreen mode

Real application: Weather data analysis with just a few lines.

Part 25: Image Processing Example

# Create a simple "image" (2D array) image = np.random.randint(0, 256, (100, 100)) # 100x100 grayscale  # Basic operations bright_image = image + 50 # Brighten dark_image = image * 0.5 # Darken threshold = image > 128 # Binary threshold  # Image statistics print(f"Average brightness: {np.mean(image):.1f}") print(f"Bright pixels: {np.sum(image > 200)}") 
Enter fullscreen mode Exit fullscreen mode

Application: Images are just arrays of numbers - perfect for NumPy.

Part 26: Scientific Computing

# Simulate a simple physics problem time = np.linspace(0, 10, 1000) # Time from 0 to 10 seconds gravity = 9.81 # m/s² initial_velocity = 50 # m/s  # Calculate position (physics equation) position = initial_velocity * time - 0.5 * gravity * time**2 # Find maximum height max_height = np.max(position) max_time = time[np.argmax(position)] print(f"Maximum height: {max_height:.1f}m at {max_time:.1f}s") 
Enter fullscreen mode Exit fullscreen mode

Power: Solve complex scientific problems with vectorized operations.

Part 27: Performance Tips

# Avoid Python loops # BAD: result = [] for x in large_array: result.append(x**2) # GOOD: result = large_array**2 # Use built-in functions # BAD: total = 0 for x in large_array: total += x # GOOD: total = np.sum(large_array) 
Enter fullscreen mode Exit fullscreen mode

Golden rule: If you're writing a loop, there's probably a NumPy function for it.

Part 28: Common Mistakes

# Mistake 1: Creating arrays in loops # BAD: arr = np.array([]) for i in range(1000): arr = np.append(arr, i) # Slow!  # GOOD: arr = np.arange(1000) # Fast!  # Mistake 2: Not using vectorization # BAD: result = np.zeros(len(arr)) for i in range(len(arr)): result[i] = arr[i] * 2 # GOOD: result = arr * 2 
Enter fullscreen mode Exit fullscreen mode

Efficiency: Pre-allocate arrays and use vectorized operations.

Part 29: Next Steps

# What you can do with NumPy: # 1. Data analysis (pandas builds on NumPy) # 2. Machine learning (scikit-learn uses NumPy) # 3. Image processing (OpenCV, PIL) # 4. Scientific computing (SciPy) # 5. Deep learning (TensorFlow, PyTorch)  # Example: Linear regression in one line X = np.random.random((100, 2)) y = np.random.random(100) weights = np.linalg.lstsq(X, y, rcond=None)[0] 
Enter fullscreen mode Exit fullscreen mode

Foundation: NumPy is the base for the entire Python scientific ecosystem.

Key Takeaways

  1. Arrays > Lists: Faster, more memory efficient for numerical data
  2. Vectorization: Apply operations to entire arrays at once
  3. Broadcasting: Automatically handle different array shapes
  4. Boolean indexing: Filter data with conditions
  5. No loops: NumPy functions are optimized - use them!
  6. Shape matters: Understanding dimensions is crucial
  7. Memory views: Slicing shares memory, copying creates new arrays

Practice Challenge

# Create a 10x10 matrix of random numbers # Find all numbers greater than 0.5 # Calculate their average # Replace numbers less than 0.3 with 0  matrix = np.random.random((10, 10)) mask = matrix > 0.5 high_values = matrix[mask] average = np.mean(high_values) matrix[matrix < 0.3] = 0 print(f"Found {len(high_values)} values > 0.5") print(f"Their average: {average:.3f}") 
Enter fullscreen mode Exit fullscreen mode

Master these concepts and you'll have a solid foundation for data science, machine learning, and scientific computing!

Top comments (0)