NumPy Arrays

Introduction to NumPy Arrays

NumPy (Numerical Python) is the fundamental package for scientific computing with Python. It provides support for large, multi-dimensional arrays and matrices, along with a large collection of high-level mathematical functions to operate on these arrays.

The core of NumPy is the `ndarray` object, a powerful N-dimensional array object that allows for efficient storage and manipulation of numerical data. This makes it a cornerstone for data science, machine learning, and scientific research in Python.

Creating NumPy Arrays

You can create NumPy arrays in several ways. The most common is from a Python list or tuple.

import numpy as np # Create a 1D array a = np.array([1, 2, 3, 4, 5]) print(a) # Create a 2D array b = np.array([[1, 2, 3], [4, 5, 6]]) print(b)

NumPy also provides functions to create arrays with initial values:

# Array of zeros zeros_array = np.zeros((3, 4)) print(zeros_array) # Array of ones ones_array = np.ones((2, 3)) print(ones_array) # Array with a range of values range_array = np.arange(0, 10, 2) # start, stop, step print(range_array) # Array with evenly spaced values linspace_array = np.linspace(0, 1, 5) # start, stop, number of samples print(linspace_array)

Key Array Attributes

NumPy arrays have several important attributes:

import numpy as np arr = np.array([[1, 2, 3], [4, 5, 6]]) print("Number of dimensions:", arr.ndim) print("Shape:", arr.shape) print("Size:", arr.size) print("Data type:", arr.dtype)

Indexing and Slicing

Accessing elements and subarrays in NumPy is similar to Python lists, but extended to multiple dimensions.

import numpy as np arr = np.array([10, 20, 30, 40, 50, 60]) # Accessing elements print(arr[2]) # Output: 30 print(arr[-1]) # Output: 60 # Slicing print(arr[1:4]) # Output: [20 30 40] print(arr[:3]) # Output: [10 20 30] print(arr[::2]) # Output: [10 30 50] # 2D array indexing arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # Access element at row 1, column 2 print(arr_2d[1, 2]) # Output: 6 # Slice a row print(arr_2d[0, :]) # Output: [1 2 3] # Slice a column print(arr_2d[:, 1]) # Output: [2 5 8] # Slice a sub-array print(arr_2d[0:2, 1:3]) # Output: # [[2 3] # [5 6]]
Note: Slicing in NumPy creates a view of the original array, not a copy. Changes to the view will affect the original array.

Array Operations

NumPy supports element-wise operations. Arithmetic operations apply element by element.

import numpy as np a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) # Addition print(a + b) # Output: [5 7 9] # Subtraction print(a - b) # Output: [-3 -3 -3] # Multiplication (element-wise) print(a * b) # Output: [ 4 10 18] # Division print(a / b) # Output: [0.25 0.4 0.5 ] # Universal functions (ufuncs) print(np.sqrt(a)) print(np.exp(a)) print(np.sin(a))

These operations are highly optimized for performance.

View vs. Copy

Understanding the difference between a view and a copy is crucial when manipulating NumPy arrays.

import numpy as np original_array = np.array([1, 2, 3, 4, 5]) # Creating a view view_array = original_array[1:4] print("Original array (before view modification):", original_array) print("View array:", view_array) view_array[0] = 99 # Modifying the view print("Original array (after view modification):", original_array) # Original array is changed print("View array (modified):", view_array) print("-" * 20) # Creating a copy copy_array = original_array.copy() print("Original array (before copy modification):", original_array) print("Copy array:", copy_array) copy_array[0] = 100 # Modifying the copy print("Original array (after copy modification):", original_array) # Original array is NOT changed print("Copy array (modified):", copy_array)
Important: Always be mindful of whether you are working with a view or a copy to avoid unintended side effects.

Further Reading