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:
ndim: The number of dimensions (axes) of the array.shape: A tuple of integers indicating the size of the array in each dimension.size: The total number of elements in the array.dtype: The data type of the elements in the array (e.g., `int64`, `float64`).
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]]
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.
- View: A view shares data with the original array. Modifying a view modifies the original array. Slicing typically creates views.
- Copy: A copy is a completely new array with its own data. Modifying a copy does not affect the original array. Use the `.copy()` method to create a copy.
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)