Data Tools

NumPy projects for beginners: three array projects with complete code

Build three NumPy projects with complete Python code: summarise weekly sales, clean sensor readings and scale features. Understand shapes, masks and broadcasting.

Useful NumPy projects for beginners make the shape of the data visible. Build a weekly sales summary, a sensor-quality report and a feature scaler. These three projects practise arrays, axes, masks, missing values and broadcasting, with complete code and results you can verify by hand.

You need basic Python variables, loops and functions. The article explains the NumPy operations as they appear. All datasets are small, invented examples included in the code; no accounts, external files or model downloads are needed.

If Python itself is new, start with Python projects for beginners. To learn the array basics first, open Why NumPy and shape, dtype and reshaping.

Choose your NumPy project

ProjectWhat you buildMain ideaA result you can check
Weekly sales summaryTotals for products and weeksArray shape and aggregation axesBoth sets of totals sum to 58 units
Sensor-quality reportMeans and flags with invalid readingsBoolean masks and finite valuesTwo invalid readings; no invented zeroes
Feature scalerComparable columns for model inputsBroadcasting and constant columnsTraining column means become zero

In this article:

Set up NumPy

Create a project folder and a virtual environment with python -m venv .venv. Activate it using source .venv/bin/activate on macOS/Linux or .venv\Scripts\Activate.ps1 in Windows PowerShell. Then install NumPy and run the first saved script:

python -m pip install numpy
python weekly_units.py

You can also run each example in its own notebook cell. The displayed outputs were checked with Python 3.12.3 and NumPy 2.5.4. You only need NumPy for these projects, not pandas or a machine learning library.

Project 1: summarise weekly sales

The task: calculate total units sold per product and per week, then identify the product with the largest total. Each row is one product and each column is one week.

Save this as weekly_units.py:

import numpy as np

products = np.array(["Notebooks", "Folders", "Markers"])
units = np.array([
    [4, 6, 5, 5],
    [2, 3, 1, 2],
    [8, 7, 6, 9],
])

product_totals = units.sum(axis=1)
weekly_totals = units.sum(axis=0)

print("Shape:", units.shape)
for product, total in zip(products, product_totals):
    print(f"{product}: {total}")
print("Weekly totals:", weekly_totals.tolist())
print("Top product:", products[product_totals.argmax()])
assert product_totals.sum() == weekly_totals.sum() == 58

Expected output:

Shape: (3, 4)
Notebooks: 20
Folders: 8
Markers: 30
Weekly totals: [14, 16, 12, 16]
Top product: Markers

The shape (3, 4) means three products measured over four weeks. For sum(axis=1), NumPy reduces the week axis, leaving one total per product. For sum(axis=0), it reduces the product axis, leaving one total per week.

Both routes add the same 12 values, so both must reach 58. The assertion checks that agreement. argmax returns the position of the first maximum, and indexing products at that position retrieves its name. Here Markers has the largest total, 30.

Try it yourself: add a fourth product, Stickers, with weekly values [1, 2, 3, 4]. The shape should become (4, 4), the grand total 68 and the top product should remain Markers. Add the product name as well as its row and update the assertion. Then decide how you would report a tie instead of silently choosing the first maximum.

Study aggregations along axes if choosing an axis feels like guessing. It is easier to understand a model's input matrix once you can explain what each row and column means.

Project 2: clean sensor readings

The task: report each sensor's mean, the number of usable observations and how often its readings exceed 22. The units are arbitrary; the threshold is an exercise rule, not a real equipment limit.

One reading is missing, represented by np.nan, and another is infinite, represented by np.inf. Save this as sensor_report.py:

import numpy as np

sensors = ["A", "B", "C"]
readings = np.array([
    [21.0, np.nan, 23.0],
    [19.0, 20.0, np.inf],
    [18.0, 19.0, 20.0],
])

valid = np.isfinite(readings)
observed = valid.sum(axis=1)
if (observed == 0).any():
    raise ValueError("Every sensor needs at least one finite reading")

clean = np.where(valid, readings, np.nan)
means = np.nanmean(clean, axis=1)
hot_readings = (clean > 22).sum(axis=1)

print("Invalid readings:", int((~valid).sum()))
for sensor, mean, count, hot in zip(sensors, means, observed, hot_readings):
    print(f"{sensor}: mean {mean:.2f}, observed {count}, above 22: {hot}")
assert observed.tolist() == [2, 2, 3]

Expected output:

Invalid readings: 2
A: mean 22.00, observed 2, above 22: 1
B: mean 19.50, observed 2, above 22: 0
C: mean 19.00, observed 3, above 22: 0

isfinite produces a Boolean array: each position says whether the corresponding reading is a finite number. Adding Boolean values counts the True entries. The code keeps that observation count beside each mean so the reader can see how much evidence contributed.

where preserves finite readings and replaces the others with NaN. nanmean then averages the observed values. Replacing invalid readings with zero would change the means and imply an observation that was never made. Sensor A's mean is (21 + 23) / 2 = 22, and one of its readings is above 22. A value equal to 22 would not meet that strict > condition.

Try it yourself: replace A's missing reading with 25. Its observed count should become 3, its mean 23 and its count above 22 should become 2. Then make every reading for B invalid. The code should raise its explicit error because there is no observed value from which to calculate a mean.

Continue with indexing, slicing and masks. For the same reporting problem in a table with dates and column names, try pandas projects for beginners.

Project 3: scale numerical features

The task: express columns on a comparable numerical scale, while handling a constant column and reusing the training calculation for a new row. A feature is one input measurement used by a model.

The first two invented columns measure on different scales; the third is always 1. Save this as scale_features.py:

import numpy as np

train = np.array([
    [10.0, 100.0, 1.0],
    [20.0, 200.0, 1.0],
    [30.0, 300.0, 1.0],
])
new_rows = np.array([[40.0, 400.0, 1.0]])

mean = train.mean(axis=0)
scale = train.std(axis=0)
safe_scale = np.where(scale == 0, 1.0, scale)
train_scaled = (train - mean) / safe_scale
new_scaled = (new_rows - mean) / safe_scale

print("Training column means:", mean.tolist())
print("Constant columns:", (scale == 0).tolist())
print("Scaled training rows:", train_scaled.round(3).tolist())
print("Scaled new row:", new_scaled.round(3).tolist())
assert np.allclose(train_scaled.mean(axis=0), 0)
assert np.isfinite(train_scaled).all()

Expected output:

Training column means: [20.0, 200.0, 1.0]
Constant columns: [False, False, True]
Scaled training rows: [[-1.225, -1.225, 0.0], [0.0, 0.0, 0.0], [1.225, 1.225, 0.0]]
Scaled new row: [[2.449, 2.449, 0.0]]

mean(axis=0) and std(axis=0) each return three values, one per column. NumPy applies those values across every row, an operation called broadcasting. The first column's training mean is 20; subtracting it centres that column at zero. Dividing by its standard deviation sets its scale. Here std uses its default ddof=0, treating the training rows as the population for this transformation.

The constant column has a standard deviation of zero. Using 1 as its divisor avoids division by zero; its centred values remain zero. The checks confirm that the transformed training columns have approximately zero means and contain no infinite or missing results.

The new row uses the training means and scales, even though its values are larger. Its first two transformed values are about 2.449. Recalculating the scaling from a test dataset would change the reference and can leak information into evaluation; see data leakage in machine learning.

Try it yourself: change the new row to [20, 200, 1]; its transformed result should be [0, 0, 0]. Then add another training row, recompute the training statistics and check the training means again. Explain why the new row must use whichever statistics were fitted on that training set.

The lessons on broadcasting and standard deviation help connect the array operations to their meaning.

Make these projects your own

For a useful NumPy project, record the shape and meaning of every input before adding more operations. Then:

  1. Change one input and predict its effect on the output.
  2. Check totals or a small hand-calculated result with an assertion.
  3. State how you handle missing values, ties or a zero denominator.
  4. Put the calculation in a function, keeping the reporting code separate.
  5. Explain where the example's assumptions stop applying.

For real sensor data, a finite number can still be invalid because of units or a broken instrument. For model features, these examples assume finite training inputs. Those are checks to add when your own problem requires them, rather than treating a successful calculation as proof that the data is sound.

Common questions

Which NumPy project should I start with?

Start with the weekly units summary. You can calculate each total by hand, and the array has clear row and column meanings. Move to the sensor project for missing values, then feature scaling for broadcasting.

Are these NumPy projects suitable for beginners in Python?

They are suitable once you can run a script and understand variables, loops and simple functions. If those are new, begin with the Python track. You do not need to know machine learning before learning arrays.

Do these projects include source code?

Yes. Each project has a complete code block, its teaching data and the expected output. Copy a block into the suggested file or a notebook cell. No separate download is needed.

What should I put on GitHub or in a portfolio?

Add an extension you designed, instructions for running it, your checks and an explanation of the assumptions. Explain the shape of the arrays and why the operations answer the question. Do not present the original invented dataset as a real business result.

Continue with the NumPy module

Start SchoolWhool's NumPy module to practise shapes, indexing, broadcasting, aggregation and linear algebra in order. Open lesson parts and key terms are free to read; a free account adds quizzes and saved progress.

NumPy is the opening numbered module of Data Tools and is part of the free sample. When you want the wider learning path, explore the Data Tools course and compare course access. Pro adds practice for every module, projects and certificates.

References

The code and datasets are original examples. For the operations used here, see the official NumPy documentation on array basics and axes, broadcasting, finite-value checks, means with missing values and standard deviation.

Related course

The four libraries every machine learning notebook uses: NumPy arrays and broadcasting, pandas tables, readable Matplotlib charts, and the scikit-learn API.

Open lessons' parts and key terms are free to read, with no account.

What you will be able to do

  • Reason about an array's shape and dtype before an operation runs.
  • Select, filter, group and join tables with pandas.
  • Make charts that answer one question clearly.
  • Use scikit-learn's fit, transform and predict with confidence.