Try adding two lists of numbers in plain Python, and you will see the problem at once. The plus sign joins the lists instead of adding the numbers. To add them one by one, you must write a loop. NumPy removes that loop. You write a + b, and every pair of numbers is added, in a single line.
NumPy is the Python library for fast number work. It gives you a data type called the array, a grid of numbers that holds one type of value and does maths on all values together. Almost every data library in Python, such as pandas, SciPy, scikit learn and Matplotlib, is built on top of it. If you want to do data analysis or machine learning in Python, you will use NumPy sooner or later.
This tutorial starts with installation and takes you through arrays, shape, slicing, linspace, sums, standard deviation, stacking and broadcasting. Every example was run, and the output you see is the real output. We also show what goes wrong in the most common mistakes, with the exact error.
NumPy stands for Numerical Python. It is a free, open source library for working with arrays of numbers. Its main object is the ndarray, a table of values that all have the same type, and that is indexed by whole numbers. It adds fast maths functions, tools for linear algebra, random numbers and Fourier transforms, and a way to join Python with code written in C, C plus plus and Fortran.
The simple way to think about it: a Python list holds anything, and an array holds one kind of thing, and because of that, NumPy can do maths on it very quickly.
Arrays take less memory, are fast and are convenient. Here is a test with one million whole numbers.
| Python list | NumPy array | |
|---|---|---|
| Memory for 1,000,000 integers | About 36 MB | 8 MB |
| Maths on every item | Needs a loop | One line, no loop |
| Types inside | Any mix | One type |
| Speed for doubling every item | Slower | Faster |
The memory figures came from a test I ran. The list figure counts the list and the number objects inside it, and it changes slightly between Python versions. In my run, doubling every item was more than 5 times faster with the array. The exact ratio depends on your computer, so test it on yours.
The same one command works on Windows, Mac and Linux. Open a terminal, or Command Prompt on Windows, and run:
If pip is not found, use python3 or py before it:
Now check that it worked, and see which version you have:
Your number may be different. The NumPy 2.5.0 release notes list Python 3.12 to 3.14 as supported versions, and Python 3.11 is dropped. If you are on an older Python, pip may install an older NumPy, which is fine for everything in this tutorial except the descending sort at the end.
Open the Terminal and run pip install numpy, or python3 -m pip install numpy if the first command is not found.
The simplest way is the same command in Command Prompt. If you use PyCharm, you can also do it inside the editor. Open File, then Settings, then your project, then Python Interpreter. Click the plus button, search for numpy and click Install Package. The exact menu names differ a little between PyCharm versions, so check them against your version. Then add the line below at the top of your file and you are ready.
Almost everybody writes np as the short name. Use np.
A NumPy array holds items of one type, and each item is found by its position, counted from zero. The directions of an array are called axes. A list of numbers has one axis. A table with rows and columns has two. Here is an example, a two row, three column table:
This array has two axes. NumPy calls this ndim, the number of dimensions. Some older tutorials call it the rank, but rank in linear algebra means something different, so in NumPy it is safer to say ndim.
Notice that the output has no commas. That is how NumPy prints an array, and it is a quick way to tell an array from a list.
A single dimension array has one axis, so it is a plain row of values.
A multi dimension array has two or more axes. You build it with one list that contains the rows, so there are brackets around all the rows.
A common mistake is to pass each row separately. It fails like this:
The message is confusing, because the second list was read as a type description. The fix is simple. Put one more pair of brackets around the rows.
An array has one type, so NumPy converts the values to fit.
Whole numbers and a decimal become decimals. Numbers and text all become text, shown here as U21, which means text strings. This surprises beginners, so check the type if a calculation does not behave.
The names ndim, itemsize and dtype are attributes, and the rest are functions. Operators are signs such as plus and minus, and we cover those in a later section.
| Attribute | What it tells you |
|---|---|
| ndim | The number of axes, which is 2 here |
| shape | The size along each axis, which is 2 rows and 3 columns |
| size | The total number of items, which is 6 |
| itemsize | The bytes used by each item, which is 8 here |
| dtype | The data type of the items, which is int64 here |
The output of itemsize and dtype depends on your system. On most 64 bit computers, whole numbers are int64, but on some Windows setups with older NumPy versions you may see int32 and 4. The attribute shape is the one you will use the most.
Reshape changes the rows and columns without changing the data. The total number of items must stay the same.
If you ask for a shape that does not fit, such as 4 by 2 for six items, NumPy raises a ValueError. Use minus 1 for one side, such as reshape(3, -1), and NumPy works out the missing number.
Slicing picks out parts of an array. Write the row first, then the column, separated by a comma. A colon means all of the rows or columns.
| Code | What it does |
|---|---|
| s[0, 2] | Row 0, column 2. The answer is 3 |
| s[0:, 2] | All rows from row 0 onward, column 2. The answer is 3, 6 and 13 |
| s[0:2, 1] | Rows 0 and 1 only, column 1. The answer is 2 and 5 |
Remember that the end number in a slice is not included. So 0:2 means rows 0 and 1, and not row 2.
The function linspace gives evenly spaced numbers between two points. Be careful with the spelling. A common typo, linespace, raises an AttributeError.
The three numbers are the start, the end and how many values you want. Both ends are included. A shorter case, with 5 values, is easier to read:
Linspace is very handy for the x values of a chart. We use it in our Matplotlib tutorial.
These five do most of the everyday work. Call them with the np prefix where needed, for example np.sqrt. Without the prefix Python raises a NameError.
| Function | What it does |
|---|---|
| max | The largest value in the array |
| min | The smallest value |
| sum | The total of all values |
| sqrt | The square root of every value, which gives a new array |
| std | The standard deviation, a measure of how spread out the values are |
A single total is not always what you need. The axis argument says in which direction to work. Axis 0 goes down the columns, and axis 1 goes across the rows.
The first line gives the total of each column. The second gives the total of each row. This one idea saves a lot of loops in real work.
Plain Python max on a two row array fails:
Python tries to compare whole rows, and cannot decide which row is bigger. Use a.max() or np.max(a) instead. The plain Python sum happens to work, but it adds row by row and gives [5 7 9], not 21, so use a.sum() when you want the single total.
The plus, minus, times and divide signs work on every pair of items at the same position. The two arrays need the same shape.
Note that a * b multiplies item by item. It is not the same as matrix multiplication, which uses the at sign, as in a @ b.
Broadcasting is what lets NumPy combine arrays of different shapes. The simplest case is one number and an array. Here, 5 bonus marks are added to every student, and each mark is raised by 10 percent.
You can use a condition inside the brackets to keep only some values. This is very useful in data work.
The first line gives the marks that are 70 or more. The second counts how many there are, because True counts as 1.
Stacking joins arrays. Use vstack to put one below the other, and hstack to put them side by side.
Note the double brackets. The function takes one group of arrays, so the arrays go inside their own brackets. For vstack the arrays need the same number of columns, and for hstack the same number of rows.
Ravel turns any array into a flat, one dimensional array. The result has one axis only, and its shape is (6,), so it is not a column.
Before NumPy 2.5, you had to sort and then reverse. The 2.5.0 release notes say np.sort and np.argsort now accept descending=True. The notes also say that NaN values go to the end in both directions, and that descending sorts may be slower, because the fast SIMD sorting is not used for them.
If you are on an older NumPy, this line raises a TypeError. Use np.sort(marks)[::-1] there instead.
| Error | Usual cause | Fix |
|---|---|---|
| AttributeError: no attribute linespace | A spelling mistake in linspace | Use np.linspace |
| NameError: name sqrt is not defined | The np prefix is missing | Use np.sqrt |
| NameError: name x is not defined | Using a variable that was never created | Use the name you created, such as a |
| TypeError: Field elements must be 2 or 3 tuples | Rows passed as separate arguments | Wrap all rows in one more pair of brackets |
| ValueError: truth value of an array is ambiguous | Plain Python max or min on a 2D array | Use a.max() or np.max(a) |
| ValueError: cannot reshape array | The new shape has a different item count | Make rows times columns equal to size |
| ModuleNotFoundError: No module named numpy | NumPy is not installed in this Python | Run python -m pip install numpy |
The 2.5.0 release notes list these main points. You do not need them to learn the basics, but they show where the library is going.
descending=True for np.sort and np.argsort.ndarray works with match and case statements.polyvalnd.If you are upgrading from NumPy 1.x, read the release notes before you update, because some old functions have been removed over the 2.x releases.
np.arange(1, 13).reshape(3, 4). Print its shape and its sum.axis argument.ravel.Here is the full script that was used to test the examples on this page. It ran on NumPy 2.5.3. The speed test prints only True or False, because the exact times change from one computer to another.
NumPy is small to learn and large in its effect. If you can create an array, check its shape, slice it, and do maths on it without a loop, you already have the skill that pandas, scikit learn and Matplotlib expect. Type the examples yourself, break them on purpose, and read the error messages, because that is where the learning happens. A good next step is to use the arrays you made here to draw a chart in Matplotlib, or load them into a pandas table.