The NumPy array
In short: A NumPy array (ndarray) holds numbers of one type (dtype) with a shape, and computes with them much faster than a Python list.
Problem
“Add VAT to every price”
The shop has 25 products. The manager wants the prices with VAT: every price times 1.2. Then they want a year of sales by day: 25 products over 365 days, that is 9,125 numbers.
So far numbers in Python have lived in a list. But a list does not do maths:
* 2 does not double the prices, it repeats the list twice. * 1.2 is an error. What is left is a for loop for every calculation, and with 9,125 numbers, then a million, the code gets long and slow.
The idea
An array: one block of numbers
A list is a collection of separate objects. Each of its slots holds an address, and the number itself is elsewhere in memory, with its own Python “wrapper”. That is why a list can hold anything: a number, text, another list.
Data analysis does not need that. It needs many numbers of the same type. NumPy is the library for this, and its core is the array: the numbers sit next to each other in one block of memory, all of one type. Here is a million prices as a list and as an array:
The list takes 20.2 MB and the array 8.0 MB: 8 bytes per price and nothing more. The sandbox is 32-bit. On an ordinary 64-bit computer the addresses and wrappers are bigger and the list grows to about 32 MB, while the array stays at 8 MB.
A block of same-typed numbers is also faster to work through: NumPy runs over it with ready-made C code, without asking for the type of every number. Here is VAT on a million prices:
array * 1.2 multiplies all the prices at once. In the sandbox the array is several times faster than the loop. On an ordinary computer the gap is tens of times. The exact time depends on the machine, so the code only says which is faster.
More precisely, if you are curious
import numpy as np is everyone’s habit, like pd for pandas. pandas itself is built on NumPy: a table column keeps its numbers in an array. So what you learn here also holds for tables.
The idea
An array from the table: dtype
The prices are already in products.csv. to_numpy() takes a column of the table as an array. Every array knows the type of its numbers: that is the dtype.
prices[:5] gives the first five, as with a list. An array prints without commas: [1.2 1.9 0.8 2.5 1.6].
float64: decimal numbers, 8 bytes each (64 bits). The prices are like that.int64: whole numbers, also 8 bytes each. The stock is like that.
See it
When types mix
There is one type for the whole array. What happens if you put different things in it?
- Whole and decimal: all become decimal.
40becomes40.0without loss, while the other way round would cut 1.5. - One piece of text: everything becomes text.
<U32means a string of up to 32 characters. The numbers are no longer numbers.
More precisely, if you are curious
If you write np.array([40, 25, 60]) in the sandbox, the type is int32, not int64. The default whole number follows the machine, and the sandbox is 32-bit. On your computer it is int64. Columns read with pandas are int64 here too. For quantities in a shop both types are enough: int32 holds numbers up to about 2.1 billion.
The idea
Shape: shape and ndim
The prices are one row of numbers. Sales by week are a table: a row for every product, a column for every week. An array can be both.
shapeis the shape: how many numbers there are in each direction.ndimis the number of directions (dimensions).
The prices have the shape (25,): one dimension with 25 numbers. The comma is there because a shape is always a pair, a triple and so on (a tuple), even with one number in it. The table is (3, 4): 3 rows (the products) and 4 columns (the weeks). Rows first, then columns, as with shape in pandas.
Try it
Products and weeks
qty holds units per product (rows) and per week (columns). Put the number of products in n_products and the number of weeks in n_weeks, taken from the shape of the array.
Solution
import numpy as np
qty = np.array([
[4, 2, 5, 3],
[1, 0, 2, 2],
[6, 7, 5, 8],
])
n_products = qty.shape[0]
n_weeks = qty.shape[1]qty.shape is (3, 4), so n_products = qty.shape[0] (3) and n_weeks = qty.shape[1] (4). len(qty) gives only the number of rows, and qty.size the count of all the numbers: 12.
The idea
Ready-made arrays: arange and zeros
Often an array does not come from a file, you make it yourself:
np.arange(start, end)gives consecutive numbers, likerange. The end is not included.np.zeros(shape)gives an array of zeros. It is handy for a table you will fill in. The shape of a table is a pair:np.zeros((rows, columns)), with double brackets.
The days run from 1 to 365, so the end is 366. The table for a year of sales is (25, 365): 9,125 zeros of type float64, ready for the numbers.
Exercise
The price list and the year
Make days with the days from 1 to 365, and sales: a table of zeros with a row for each of the 25 products and a column for every day.
Solution
import numpy as np
days = np.arange(1, 366)
sales = np.zeros((25, 365))days = np.arange(1, 366): the end 366 is not included, so the last day is 365. np.arange(365) starts at 0. sales = np.zeros((25, 365)): rows first (the products), then columns (the days). np.zeros((365, 25)) is also a table, but flipped.
Put the prices and the stock into one array table with two rows: the first with the prices, the second with the stock. Put the type of table in kind.
Solution
import numpy as np
import pandas as pd
products = pd.read_csv('products.csv')
prices = products['price'].to_numpy()
stock = products['stock'].to_numpy()
table = np.array([prices, stock])
kind = table.dtypetable = np.array([prices, stock]) has the shape (2, 25). The type is float64, even though the stock was int64: everything in one array has one type, and the prices are decimals. That is why the stock of 40 now shows as 40.0.
Test
Check yourself
Related lessons
Section titled "Related lessons"- Builds on: The first table
- Continues in: Vectorization · Summaries and missing values · Broadcasting: the number, the row and the column · Series and DataFrame
- Tasks on this topic: NumPy