Python NumPy Tutorial

Work with NumPy arrays: shapes, vectorized operations, reductions along axes, filtering, broadcasting and the difference between views and copies.

Lesson 75 of 107Advanced13 min read

NumPy is the core library for numerical computing in Python. Its ndarray stores numbers of one type in a compact block and runs maths on whole arrays at once in fast compiled code, so prices * 1.2 updates a million values without a Python loop. pandas, Matplotlib, scikit-learn and most scientific packages are built on it.

Python
import numpy as np
counts = np.array([[8, 10], [12, 6]])   # 2 rows, 2 columns
print(counts.shape)                      # (2, 2)
print(counts.sum(axis=1))                # [18 18]: total of each row

Install it with python -m pip install numpy. This tutorial covers array shape and type, vectorized operations, the axis argument, boolean filtering and broadcasting, and when slices share data. The examples analyse passenger counts on a ferry service: rows are days, columns are departures. If you're coming from lists, read arrays in Python first.

Array shape

Create arrays from lists or with helper functions:

Python
import numpy as np
passengers = np.array([[8, 10, 7], [12, 6, 9]])
print(passengers.shape, passengers.ndim, passengers.size, passengers.dtype)
# (2, 3) 2 6 int64
zeros = np.zeros((3, 4))           # 3 rows of 4 zeros
steps = np.arange(0, 10, 2)        # [0 2 4 6 8]
grid = np.arange(6).reshape(2, 3)  # [[0 1 2] [3 4 5]]
  • shape gives the size of each dimension as a tuple: (rows, columns) for a 2-D array.
  • dtype is the element type. Every element has the same one, chosen from the data (int64, float64, bool...). The default integer size can differ by platform.
  • reshape() changes the shape without changing the data; the total size must stay the same.

Index 2-D arrays with array[row, column]: passengers[1, 0] is 12, passengers[0] is the first row and passengers[:, 2] is the third column. Operations between arrays need compatible shapes; combining a (2, 3) array with a (2, 2) one raises ValueError: operands could not be broadcast together.

Vectorization

Arithmetic and comparisons apply element by element to whole arrays:

Python
fares = np.array([4.5, 4.5, 6.0])
print(fares * 1.1)                 # [4.95 4.95 6.6 ]
print(passengers * fares)          # revenue per departure, per day
print(passengers > 8)              # boolean array of the same shape

This is called vectorization. The loop still happens, but inside NumPy's compiled code rather than in Python, which is typically tens to hundreds of times faster for large arrays. Functions such as np.sqrt, np.round, np.maximum and np.where work the same way.

Vectorization changes how you write the calculation, not what it means. passengers * fares gives the same numbers as a nested loop multiplying each count by its fare; it's just shorter and faster. If a calculation is hard to express with array operations, a clear loop is still acceptable for small data.

A boolean array can filter another array: passengers[passengers > 8] returns [10 12 9], the counts above 8. Combine conditions with & and |, with brackets: passengers[(passengers > 6) & (passengers < 10)].

Axes

Reductions such as sum, mean, min and max can work on the whole array or along an axis:

Python
passengers = np.array([[8, 10, 7],
                       [12, 6, 9]])
print(passengers.sum())          # 52: everything
print(passengers.sum(axis=0))    # [20 16 16]: down each column
print(passengers.sum(axis=1))    # [25 27]: across each row

axis=0 collapses the rows, giving one result per column; axis=1 collapses the columns, giving one result per row. A helpful way to remember it: the axis you name is the one that disappears from the shape. (2, 3) summed over axis 0 becomes shape (3,).

Mixing up the axis produces numbers that look plausible but answer the wrong question, such as totals per departure when you wanted totals per day. Check the result's shape, and label results clearly when you print or chart them.

Views and copies

Basic slicing returns a view: a new array object that shares the original's data. Changing the view changes the original:

Python
week = np.array([8, 10, 7, 12, 6])
first_three = week[:3]          # a view
first_three[0] = 99
print(week)                     # [99 10  7 12  6]

safe = week[:3].copy()          # independent data
safe[0] = 0
print(week[0])                  # still 99

Views make slicing fast and memory-efficient, but surprise people used to lists, where slicing copies. Call .copy() when you need to modify a part without affecting the whole.

Fancy indexing, with a list of positions or a boolean mask such as week[[0, 2]] or week[week > 8], always returns a copy. reshape() returns a view when it can. np.shares_memory(a, b) tells you whether two arrays share data, which is handy while learning.

Independent practice and a worked check

Task: analyse a passenger grid with shape checks, row and column reductions and a view versus copy comparison.

Python
import numpy as np

grid = np.array([[5, 9, 4, 8], [7, 3, 6, 10]])
assert grid.shape == (2, 4)

print("Day totals:", grid.sum(axis=1))          # [26 26]
print("Departure totals:", grid.sum(axis=0))    # [12 12 10 18]
print("Busiest departure:", grid.sum(axis=0).argmax())   # 3

view = grid[0]
copy = grid[0].copy()
view[0] = 0
print(grid[0, 0], copy[0])                      # 0 5

argmax() returns the position of the largest value. Changing the view altered grid, while the copy kept the original 5. For the worked check, axis=1 sums the values within each row, producing one total per row.

Reference and next practice

The official NumPy absolute beginner's guide and broadcasting guide go further. Continue with the pandas tutorial and Matplotlib tutorial. Practise with the Python exercises and Python quiz.

NumPy Tutorial Summary

  • Array shape: ndarray stores numeric values with a shape and dtype.
  • Vectorization: Array operations apply compiled elementwise work rather than requiring an explicit Python loop.
  • Axes: Axis arguments select the dimensions along which reductions operate.
  • Views and copies: Basic slicing often returns a view sharing storage, while copy makes independent array data.

NumPy Tutorial Examples

Each example shows the code, the output it produces and what each part does.

Example 1

NumPy Tutorial in a small program

Python
import numpy as np
counts = np.array([[8, 10], [12, 6]])
print(counts.sum(axis=1).tolist())
print((counts + 1).tolist())
Output
[18, 18]
[[9, 11], [13, 7]]
Line-by-line explanation
  1. Line 2A 2 by 2 array: two days, two departures.
  2. Line 3axis=1 sums across each row: 8 + 10 and 12 + 6.
  3. Line 4Adding 1 applies to every element; tolist() converts back to Python lists for display.
Example 2

Analysing a week of departures

Python
import numpy as np

passengers = np.array([
    [8, 10, 7],
    [12, 6, 9],
    [15, 14, 11],
])
fares = np.array([4.5, 4.5, 6.0])
days = np.array(["Mon", "Tue", "Wed"])

print("Shape:", passengers.shape)
print("Per day:", passengers.sum(axis=1).tolist())
print("Per departure:", passengers.mean(axis=0).round(1).tolist())
revenue = passengers * fares
print("Revenue per day:", revenue.sum(axis=1).tolist())
print("Busy days:", days[passengers.sum(axis=1) > 30].tolist())
print("Above 10:", passengers[passengers > 10].tolist())
Output
Shape: (3, 3)
Per day: [25, 27, 40]
Per departure: [11.7, 10.0, 9.0]
Revenue per day: [123.0, 135.0, 196.5]
Busy days: ['Wed']
Above 10: [12, 15, 14, 11]
Line-by-line explanation
  1. Line 13mean(axis=0) averages each column, giving one value per departure.
  2. Line 14fares has shape (3,), so it's broadcast across every row: each column is multiplied by its fare.
  3. Line 16A boolean array built from the row totals selects the matching day names.

Common NumPy Tutorial Mistakes

Using the wrong axis

Don't
passengers = np.array([[8, 10, 7], [12, 6, 9]])
daily = passengers.sum(axis=0)      # [20 16 16]: these are per-departure totals
Do
daily = passengers.sum(axis=1)      # [25 27]: one total per day (row)

The named axis is the one that collapses. Check the result's shape matches what you expect.

Modifying a slice and changing the original

Don't
week = np.array([8, 10, 7])
adjusted = week[:2]
adjusted -= 1                        # week is now [7 9 7]
Do
week = np.array([8, 10, 7])
adjusted = week[:2].copy()
adjusted -= 1                        # week is unchanged

NumPy Tutorial in Real Projects

NumPy in practice

NumPy is everywhere numbers are processed in Python: image processing treats pictures as 3-D arrays of pixel values, finance calculates returns over price arrays, physics and engineering simulate systems on grids, and machine learning stores features and model weights as arrays. pandas DataFrames hold their numeric columns as NumPy arrays, and scikit-learn models take arrays as input.

Typical workflows load data, check its shape and dtype, clean or filter with boolean masks, and summarise along axes, exactly the operations in this lesson. Performance-sensitive code avoids Python loops over elements entirely in favour of vectorized expressions.

NumPy Tutorial FAQ

What is the difference between a NumPy array and a Python list?

A NumPy array holds values of one type in a compact block and supports fast element-wise maths, multiple dimensions and axis reductions. A list holds any objects, can mix types, and * repeats it instead of multiplying the numbers.

What does axis=0 mean in NumPy?

It means "along the first dimension", down the rows. For a 2-D array, sum(axis=0) gives one total per column, and sum(axis=1) gives one total per row.

What is broadcasting in NumPy?

Broadcasting lets NumPy combine arrays of different but compatible shapes by stretching the smaller one, without copying it. A (3, 3) array times a (3,) array multiplies each row by the same three values. Shapes are compared from the right, and each dimension must be equal or 1.

Why did changing my slice change the original array?

Basic slices are views that share data with the original. Use .copy() to get an independent array. Boolean and list indexing return copies already.

Is NumPy faster than Python loops?

For numerical work on large arrays, usually by a large factor, because vectorized operations run in compiled code. For small arrays or logic that doesn't fit array operations, the difference may not matter.

NumPy Tutorial Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

What does axis=1 sum in a two dimensional array?

Multiple choicemedium

Which review concern is valid for numpy tutorial?

NumPy Tutorial Quiz

2 questions to check what you learned.

  1. What does axis=1 sum in a two dimensional array?

    • Every column into one row
    • Values within each row
    • Python ignores the distinction
  2. Which statement correctly describes axes?

    • Axis arguments select the dimensions along which reductions operate.
    • Only the example output matters, not the rule
    • Every operation has the same behavior