Arrays & creation
The NumPy array (ndarray) is the foundation of the whole Python data stack. Pandas, scikit-learn, PyTorch and
Matplotlib all hold their numbers in arrays, so learning to create and inspect them well pays off everywhere.
Creating arrays
import numpy as np
a = np.array([1, 2, 3])
m = np.array([[1, 2], [3, 4]])
zeros = np.zeros((3, 4))
seq = np.arange(0, 10, 2) # [0 2 4 6 8]
lin = np.linspace(0, 1, 5) # 5 evenly spaced numbers
print(m.shape, m.ndim, m.dtype) # (2, 2) 2 int64
NumPy arrays are homogeneous and stored contiguously, which makes maths on them 10–100x faster than Python lists.
The main constructors
| Call | Gives you |
|---|---|
np.zeros(n) / np.ones((r, c)) |
Arrays filled with 0 or 1 |
np.full((2, 3), 9.5) |
Every element set to one value |
np.empty((3, 3)) |
Uninitialised memory — fast, but contains garbage |
np.arange(start, stop, step) |
Like range, with a step and an exclusive stop |
np.linspace(start, stop, num) |
A fixed count of evenly spaced values, stop included |
np.eye(3) |
Identity matrix |
np.zeros_like(x) |
Same shape and dtype as x, filled with zeros |
Use arange when the step matters (every 5 minutes) and linspace when the number of points matters (100 points
for a smooth curve). arange with float steps can produce one element more or fewer than you expect because of
floating-point rounding, so prefer linspace for decimals.
The attributes worth memorising
stock = np.array([[12, 4, 9], # 2 warehouses x 3 products
[ 7, 0, 15]])
stock.shape # (2, 3) rows, columns
stock.ndim # 2 number of dimensions
stock.size # 6 total elements
stock.dtype # int64 type of every element
stock.nbytes # 48 memory used
shape is the one you will print most often. Most NumPy bugs are shape bugs.
Generating data
rng = np.random.default_rng(42)
prices = rng.normal(250, 40, size=1000).round(2) # simulated item prices in ₹
codes = rng.integers(1, 5, size=10) # store codes 1..4
Seeding with default_rng(42) makes the numbers reproducible, which matters when you share a notebook.
Why not just use a list?
py_list = list(range(1_000_000))
arr = np.arange(1_000_000)
# lists need a loop or comprehension
doubled_list = [x * 2 for x in py_list]
# arrays do it in compiled code
doubled_arr = arr * 2
The array version is typically 20–50x faster and uses roughly a quarter of the memory, because a Python list stores pointers to a million separate integer objects while the array stores a million packed 8-byte values.
Loading from files
data = np.loadtxt("readings.csv", delimiter=",", skiprows=1)
np.save("readings.npy", data) # fast binary round-trip
back = np.load("readings.npy")
For anything with mixed text and numbers or column names, reach for pandas instead.
Common mistakes
np.array(1, 2, 3)— the values must be in a list:np.array([1, 2, 3]).- Expecting
np.arange(0, 1, 0.1)to include 1.0; the stop is exclusive. - Using
np.emptyand assuming it is zero-filled. - Building an array by appending in a loop;
np.appendcopies the whole array each time. Collect into a list and convert once, or preallocate withnp.zeros.
Practice
Create a 4 x 6 array of weekly sales for four branches (use a seeded Generator, values between 20,000 and
80,000). Print its shape, dtype and memory use, build a matching all-zeros array with zeros_like, and make a
linspace of 6 target values rising from 40,000 to 70,000.