python22.sci2u.dk Active sci2u
Loading...
Login
Prefer latest booklet Prefer latest booklet Login
Link to booklet is copied to clipboard!
Saved to booklet!
Removed from booklet!
Started capturing to booklet.
Stopped capturing to booklet.
Preferring latest booklet.
No longer prefers latest booklet.
Entered edit mode.
Exited edit mode.
Edit mode

Click on the booklet title or a chapter title to edit (max. 30 characters)


Python book

Basic Python Numerical Python
2.1 Intro
2.2 NumPy array vs Python list I
2.3 NumPy array vs Python list II
2.4 Accessing elements
2.5 Arrays vs lists
2.6 Changing NumPy arrays
2.7 Random numbers
2.8 Uniform distribution
2.9 NumPy arrays II
2.10 NumPy arrays III
2.11 NumPy arrays IV
2.12 NumPy arrays V
Plotting with Matplotlib Advanced Python Add Chapter..

Numerical Python

2.1 Intro

The NumPy package was first introduced here. It provides most of the functionality one needs to do numerical manipulations and handling datasets in Python. Recall that the package is imported with the statement:
import numpy as np
after which one may start working with numerical values in Python in all sorts of ways. For instance, creating a list of eight numbers from 0 to 1 is done with the linspace function:
x = np.linspace(0,1,8)
x
that outputs:
array([0.        , 0.14285714, 0.28571429, 0.42857143, 0.57142857, 0.71428571, 0.85714286, 1.        ]) 
Notice how it may be a little annoying to get very many decimals on the printed values. To avoid that you may change the default printing behavior of NumPy, with this function call:
np.set_printoptions(precision=3)
after which you will get only 3 decimals:
array([0.   , 0.143, 0.286, 0.429, 0.571, 0.714, 0.857, 1.   ])
The content of the variable x remains unchanged. It is only the printing of it that is affected. The array(...) part of the print reveals that the variable x is a NumPy array:
type(x)
numpy.ndarray
In many contexts, a NumPy array is precisely what you want, but if you want a Python list you may use the method tolist:
x.tolist()
[0.0,
 0.14285714285714285,
 0.2857142857142857,
 0.42857142857142855,
 0.5714285714285714,
 0.7142857142857142,
 0.8571428571428571,
 1.0]


2.2 NumPy array vs Python list I

A one dimensional NumPy array is not just a Python list. In fact, a NumPy array has the properties you would like in order to do numerical manipulations of a list of numbers. To illustrate this, assume you have the same list of numbers both as a Python list, x_list, and as a NumPy array, x_array:
x_list = [1, 4, 9]
x_array = np.array(x_list)
print('x_list:          ',x_list)
print('x_array:         ',x_array)
print('x_array.tolist():',x_array.tolist())
x_list:           [1, 4, 9]
x_array:          [1 4 9]
x_array.tolist(): [1, 4, 9]
Then multiplying each list with 2 gives two different results:
print('2 * x_list: ',2 * x_list)
print('2 * x_array:',2 * x_array)
2 * x_list:  [1, 4, 9, 1, 4, 9]
2 * x_array: [ 2  8 18]
The Python list is repeated twice, while the NumPy array has all its elements doubled, i.e. the operations on the NumPy array are done element wise.
Another example of a numerical manipulation possible for a NumPy array is the adding a constant to it:
x_array + 100
array([101, 104, 109])
If you provide a Python list as the argument for a NumPy function, the function first converts the input to a NumPy array and then does its action element wise on the array. Thus the NumPy function np.sqrt applied to either a Python list or a NumPy array:
np.sqrt(x_list)
np.sqrt(x_array)
gives the same result:
array([1., 2., 3.])


2.3 NumPy array vs Python list II

Another reason to work with NumPy arrays rather than with Python lists is that the former are much faster. Consider that you have 10000 numbers in either type of list and wish to evaluate the sum, then with a NumPy array:
an_array = np.arange(10000)
print(len(an_array))
print(np.sum(an_array))
%timeit np.sum(an_array)
10000
49995000
11.3 µs ± 575 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
it takes: 11 micro seconds for such an evaluation, while with a Python list:
a_list = list(an_array)
print(len(a_list))
print(sum(a_list))
%timeit sum(a_list)
10000
49995000
1.02 ms ± 5.48 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
it takes 1 millisecond, i.e. about a hundred times longer. %timeit is a so-called magic command of the Jupyter Notebook. It repeats the following Python statement a great number of times and evaluates the average time it takes to execute it. The output obviously depends on your hardware.


2.4 Accessing elements

import numpy as np
a = np.arange(6)*20
a
array([ 0, 20, 40, 60, 80, 100])
As with ordinary lists, you may pick out elements of the one-dimensional NumPy array:
One element is picked like this:
a[2]
40
Elements up till some index like this:
a[:2]
array([ 0, 20])
Elements from some index and up like this:
a[3:]
array([60, 80, 100])
The last element like this:
a[-1]
100


2.5 Arrays vs lists

So why are they called NumPy arrays and not just NumPy lists? Well, that is because you can add more dimensions. If you have a one-dimensional NumPy arrays, it may look like this: See here


2.6 Changing NumPy arrays

Two NumPy arrays can be combined into one:
a = np.arange(6)*20
a
b = (np.arange(2)+1)*30
b
np.concatenate( (a,b) )
array([  0,  20,  40,  60,  80, 100])
array([30, 60])
array([  0,  20,  40,  60,  80, 100,  30,  60])
If you need to delete entries in a NumPy array, you use the np.delete function that takes as arguments the existing NumPy array and indices of elements to delete.
a
np.delete(a,3)
np.delete(a,(1,2))
np.delete(a,range(len(a)-2))
a
array([  0,  20,  40,  60,  80, 100])
array([  0,  20,  40,  80, 100])
array([  0,  60,  80, 100])
array([ 80, 100])
array([  0,  20,  40,  60,  80, 100])
Note that np.delete returns a new NumPy array, so if you just want to delete the element in place, you have to reassign the variable:
a = np.delete(a,range(len(a)-2))
a
array([ 80, 100])
See more on the topic here.


2.7 Random numbers

NumPy has a module, random, that provides random numbers. You get a single random number by calling the function rand() from the module:
import numpy as np
np.random.rand()
0.4375872112626925
Calling the function again gives a new random number:
np.random.rand()
0.8917730007820798
You may also get a whole list of random numbers by providing an integer argument while calling:
np.set_printoptions(precision=3) # only 3 decimals in print
np.random.rand(5)
array([0.964, 0.383, 0.792, 0.529, 0.568])
Often, when developing some Python code, it is helpful to get the same random numbers everytime the code is run. You can do that by providing a seed to the random module:
np.random.seed(0)
np.random.rand(2)
array([0.549, 0.715])
You still get random numbers:
np.random.rand(2)
array([0.603, 0.545])
But once you provide the seed again, you start over and the same random numbers in the same sequence once more:
np.random.seed(0)
np.random.rand(2)
array([0.549, 0.715])


2.8 Uniform distribution

The random numbers that are provided by calling np.random.rand() are uniformly distributed between 0 and 1. It means that the likelihood of getting a random number between and is independent on as long as . Making histograms of 100 or 10000 random numbers illustrates how a uniform distribution looks like. Writing this:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()

r = np.random.rand(100)
ax.hist(r)
in one cell and this in another cell:
r = np.random.rand(10000)
ax.hist(r)
and we get plots like these:

Figure 1 First plot: 100 random numbers, second plot: 10000 random numbers.

With just 100 random numbers, there is a great variation in each of the ten bins of the histogram from 0 to 1. With 10000 random numbers, there is almost the same amount of random numbers in each bin.


2.9 NumPy arrays II

The following commands build a non-trivial, one-dimensional NumPy array:
a1 = np.arange(10,14)
a2 = np.arange(20,24)
a12 = np.concatenate((a1,a2))
print(a1)
print(a2)
print(a12)
a = np.concatenate((a12,20+a1))
print(a)
[10 11 12 13]
[20 21 22 23]
[10 11 12 13 20 21 22 23]
[10 11 12 13 20 21 22 23 30 31 32 33]
which can be turned into a two-dimensional NumPy array, e.g with 3 lists of each 4 elements:
a = a.reshape(3,4)
a
array([[10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33]])
The dimensions of a NumPy array can be queried with the shape attribute:
a.shape
(3, 4)
A two-dimensional NumPy array can be thought of as a list of lists. Printing the 1st and second (inner) list of the (outer) list supports this notion:
print(a[0])
print(a[1])
[10 11 12 13]
[20 21 22 23]
And one may loop through the (inner) lists in the (other list) like this:
for row in a:
    print(row)
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]


2.10 NumPy arrays III

Consider the two-dimensional NumPy array:
a = np.array([[10, 11, 12, 13],
              [20, 21, 22, 23],
              [30, 31, 32, 33]])
Selecting the rows (the inner lists) of the array with an index, as in a[0], a[1], and a[2], one may inspect the individual members of the inner lists, by adding another index in square brackets, e.g. [2] that will select for the 3rd element in every row:
print(a[0][2])
print(a[1][2])
print(a[2][2])
12
22
32
Together, the three print statements effectively select the 3rd row of the array a. However, getting three separate numbers is rather impractical. A more rational way to get the 3rd coloumn is the following:
print(a[:,2])
[12 22 32]
where the colon, :, means that all rows (i.e. elements of the outer list) should be considered, while ,2 means that all 3rd elements of these rows are selected. One may get inspired and use the : for the second coordinate, selecting all elements in a given row:
print(a[1,:])
print(a[1])
[20 21 22 23]
[20 21 22 23]
That works fine, but as seen, the ,: is not required to pick out a row, since [1] already is sufficient.


2.11 NumPy arrays IV

A NumPy array,
a = np.array([[10, 11, 12, 13],
              [20, 21, 22, 23],
              [30, 31, 32, 33]])
a
array([[10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33]])
may be transposed, meaning that rows and coloumns are interchanged:
np.transpose(a)
array([[10, 20, 30],
       [11, 21, 31],
       [12, 22, 32],
       [13, 23, 33]])
and meaning that the first dimension is now indexing what used to be the coloumns:
for col in np.transpose(a):
    print(col)
[10 20 30]
[11 21 31]
[12 22 32]
[13 23 33]
These "used to be coloumns"-rows may of course be indexed. E.g. the 3rd coloumn of a can be gotten like this:
np.transpose(a)[2]
array([12, 22, 32])
Note that it does not matter whether the transpose function from the NumPy package is passed an array as done above, or the transpose method on a NumPy object is invoked as done here:
a.transpose()[2]
array([12, 22, 32])


2.12 NumPy arrays V

A two-dimensional NumPy array, may be converted to a one-dimensional one with the flatten method:
a = np.array([[10, 11, 12, 13],
              [20, 21, 22, 23],
              [30, 31, 32, 33]])
a.flatten()
array([10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33])
Note how none of the methods, transpose and flatten, lead to an actual change of the NumPy object, which maintains its original shape:
a
array([[10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33]])
Sometime, you may encounter a two-dimensional NumPy array with just one coloumn. Here we construct it deliberately:
a = a.reshape(12,1)
a 
array([[10],
       [11],
       [12],
       [13],
       [20],
       [21],
       [22],
       [23],
       [30],
       [31],
       [32],
       [33]])
Whenever that happens, you might consider calling the squeeze method to reduce the dimensionality:
a.squeeze()
array([10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33])
However, you may also take direct action and invoke the reshape method:
a
array([[10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33]])
a.reshape(12)
array([10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33])


Sci2u Assignment: 820
Delete "Python book"?
Once deleted this booklet is gone forever!
Block is found in multiple booklets!

Choose which booklet to go to:

© 2019-2022 Uniblender ApS