DataLens

Why NumPy: arrays vs Python lists

Meet the array, the data structure behind pandas and machine learning, and see why it beats lists for numbers.

Level: Foundations · 7 min read

Practise this module

The questions for this lesson run in your browser and check your answer straight away.

The idea

Python lists are wonderful general-purpose containers: they hold anything, grow and shrink, and mix types. But they weren't built for maths on lots of numbers. Try to double every price in a list:

prices = [185, 320, 95, 65, 110]   # thousand Rupiah
print(prices * 2)
[185, 320, 95, 65, 110, 185, 320, 95, 65, 110]

That's not doubling, that's repeating the list. To double the values, you need a loop:

doubled = [p * 2 for p in prices]
print(doubled)
[370, 640, 190, 130, 220]

NumPy (Numerical Python) adds a new data structure, the array, where maths works the way you'd expect: on every element at once.

import numpy as np

prices = np.array([185, 320, 95, 65, 110])
print(prices * 2)
[370 640 190 130 220]

No loop. import numpy as np is a universal convention: every tutorial, colleague and library uses the short name np.

Analogy

A list is a shopping bag: anything fits, but you take items out one by one. An array is an egg carton: every slot holds the same kind of thing, in a fixed grid, so you can handle the whole carton at once.

Maths on whole arrays

Now the real reason arrays exist. Say you have each product's price in one array and how many of each you sold in another, in the same order. Revenue per product is price times units, for every product. With arrays, the ordinary operators work element by element, so you can write it exactly like that:

units = np.array([3, 1, 4, 2, 5])
revenue = prices * units           # 185*3, 320*1, 95*4, ...
print(revenue)
print(revenue.sum())
[555 320 380 130 550]
1935

The first element of prices is multiplied by the first element of units, the second by the second, and so on. With lists you'd need zip and a loop; with arrays it's one line that reads like the formula on paper: revenue = price × units.

Comparisons work element by element too, giving True/False for each value:

print(prices > 100)
[ True  True False False  True]

You'll use these "masks" to filter data in a later module.

Why arrays are fast

Shorter code is nice, but the bigger win is speed. On a few numbers you won't notice, but analysts regularly work with millions. Here's the same job, squaring a million numbers, done once with a list and once with an array, with a timer around each:

import time

numbers = list(range(1_000_000))
start = time.perf_counter()
squares = [n * n for n in numbers]
list_time = time.perf_counter() - start

array = np.arange(1_000_000)
start = time.perf_counter()
squares = array * array
array_time = time.perf_counter() - start

print(f"list:  {list_time * 1000:.1f} ms")
print(f"array: {array_time * 1000:.1f} ms")
list:  48.3 ms
array: 1.2 ms

Your numbers will differ (and the browser is slower than a laptop), but arrays are typically 10 to 100 times faster. Why?

  1. One type, packed tightly. A list stores pointers to separate Python objects scattered in memory. An array stores raw numbers side by side, like a column in a spreadsheet.
  2. The loop runs in C. array * array still loops over a million numbers, but inside NumPy's compiled C code, not Python, which skips all the per-element overhead of the Python interpreter.

This style of writing whole-array operations instead of Python loops is called vectorization, and it's the core skill of this track.

One type per array

Because arrays are packed tightly, every element must have the same type. Mix integers and floats, and NumPy converts everything to the type that can hold them all:

print(np.array([1, 2, 3.5]))
print(np.array([1, 2, "three"]))
[1.  2.  3.5]
['1' '2' 'three']

The first became all floats (1. means 1.0). The second turned every number into text, which is rarely what you want. If your array ends up full of strings, check your input data.

Where you'll meet NumPy

Even if you rarely import numpy yourself, you use it constantly:

Understanding arrays is understanding what all of those are doing under the hood.

Why this matters for clean code

revenue = prices * units is shorter than a loop, but more importantly it reads like the business rule. There's no index variable to get wrong, no list to append to, no off-by-one. Vectorized code is usually faster, shorter and clearer all at once, which is rare in programming.

Recap

Practise this module

The questions for this lesson run in your browser and check your answer straight away.

Next: Creating arrays (array, arange, zeros, ones, linspace) →