TD J2 : tableaux numpy¶

On a étudié dans le TD précédent les listes python. On a apprécié leur souplesse mais on a vu leurs limites notamment en 2D. Le module Numpy est là pour y remédier.

À noter : pour faire ce TD, il est indispensable d'avoir le cours sous la main...

1. Tableau 1D¶

Voyons comment utiliser un tableau numpy et la facilité proposée pour les manipuler.

Q1. Écrire une commande python qui crée un tableau numpy contenant les entiers de 1 à 9

In [2]:
# Import de la libraire : alias usuel 'np'

import numpy as np

entiers = np.arange(1,10)

print(entiers)
[1 2 3 4 5 6 7 8 9]

Noter le type de la variable entiers :

In [3]:
type(entiers)
Out[3]:
numpy.ndarray

Q2. Compléter le script suivant pour qu'il trace la représentation graphique de la fonction myfunc

In [4]:
import matplotlib.pyplot as plt

#Une fonction personnelle : 
def myfunc(x):
    if x>0 :
        return x*x
    else :
        return -x*x
    
# On la vectorise :
myfunc_vect = np.vectorize(myfunc)

# On crée un tableau
tab7 = np.arange(-3,3,0.5)

# on obtient un nouveau tableau en appliquant notre nouvelle fonction à toutes les valeurs du tableau
tab8 = myfunc_vect(tab7)

plt.figure(1)
plt.clf()

plt.plot(tab7,tab8)

plt.show()
No description has been provided for this image

Cette fonctionnalité est très intéressante et très performante. On peut donc l'utiliser pour tracer des représentations graphiques de fonction mais aussi, de façon très performante, dans la manipulation des images (abordée dans un prochain TD...)

Exercice 1 : Nombres premiers et crible d'Erathostène (Extrait du livre de Gérard Swinnen : apprendre python 3)¶

Un nombre premier est un nombre qui n’est divisible que par un et par lui-même.

Q3. Écrire un programme qui établit la liste de tous les nombres premiers compris entre 1 et 1000 en utilisant la méthode du crible d’Eratosthène. L'objectif est d'obtenir un tableau contenant des 0 et des 1. Les indices sont les nombres entiers étudiés, et la valeur 0 signifie que l'entier n'est pas premier et 1 qu'il est premier:

  • Créez un tableau tab de 1000 éléments, chacun initialisé à la valeur 1, et mettre les deux premières valeurs à 0 (les entiers 0 et 1 ne sont pas des nombres premiers)
  • Parcourez ce tableau à partir de l’élément d’indice 2 : si l’élément analysé possède la valeur 1, mettez à zéro tous les autres éléments du tableau dont les indices sont multiples entiers de l’indice auquel vous êtes arrivé (ne pas hésiter à utiliser des slices).
  • Lorsque vous aurez parcouru ainsi tout le tableau, les indices des éléments de tab qui sont restés à 1 seront les nombres premiers recherchés.

En effet : à partir de l’indice 2, vous annulez tous les éléments d’indices pairs : 4, 6, ... Avec l’indice 3, vous annulez les éléments d’indices 6, 9, 12..., et ainsi de suite. Seuls resteront à 1 ceux dont l'indice est premier.

  • Ecrire enfin un code qui donne la liste nommée primes de tous les indices de tab dont la valeur est restée à 1, c'est à dire la liste de tous les nombres premiers inférieurs à 1000.
In [6]:
# Programmer le crible d'Erathostène
import numpy as np

N = 1000

tab = np.zeros(N)+1

tab[:2] = 0 # les deux premiers éléments du tableau sont mis à 0

for i in range(2,len(tab)):
    if tab[i] == 1 :
        tab[i+i::i] = 0
        
primes = [ i for i in range(len(tab)) if tab[i]==1]
print(primes)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

2. Tableaux 2D¶

Exercice 2¶

Q4. Ecrire un code permettant d'obtenir un tableau 1D contenant les entiers pairs entre 10 et 30.

In [7]:
import numpy as np
tab1 = np.arange(10,31,2)
print(tab1)
[10 12 14 16 18 20 22 24 26 28 30]

Q5. Ecrire un code permettant d'obtenir un tableau 2D avec 3 lignes et 4 colonnes dont tous les éléments valent 3.

In [8]:
tab2 = np.zeros((3,4)) +3
print(tab2)
[[3. 3. 3. 3.]
 [3. 3. 3. 3.]
 [3. 3. 3. 3.]]

Q6. Écrire un code permettant d'obtenir un tableau 2D avec 3 lignes et 4 colonnes dont tous les éléments valent 3, sauf ceux de la ligne d'indice 1 qui valent 2.

In [9]:
tab3 = np.zeros((3,4)) +3
tab3[1,:] = 2
print(tab3)
[[3. 3. 3. 3.]
 [2. 2. 2. 2.]
 [3. 3. 3. 3.]]

Q7. Écrire un code permettant d'obtenir un tableau 2D avec 3 lignes et 4 colonnes dont tous les éléments valent 0 sauf les éléments dont les indices de ligne et de colonne sont pairs qui valent 1.

In [10]:
tab4 = np.zeros((3,4))
tab4[::2,::2] = 1
print(tab4)
[[1. 0. 1. 0.]
 [0. 0. 0. 0.]
 [1. 0. 1. 0.]]

Q8. On considère le tableau tab=np.arange(1,43).reshape(7,6). Ecrire un code qui permet d'en extraire un tableau contenant uniquement les lignes et les colonnes d'indice impair.

In [11]:
tab = np.arange(1,43).reshape(7,6)
print(tab)
tab_extrait = tab[1::2,1::2]
print(tab_extrait)
[[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]
 [13 14 15 16 17 18]
 [19 20 21 22 23 24]
 [25 26 27 28 29 30]
 [31 32 33 34 35 36]
 [37 38 39 40 41 42]]
[[ 8 10 12]
 [20 22 24]
 [32 34 36]]

Exercice 3¶

Q8. Retour sur l'exercice des sommes doubles. En prenant n=10, calculer chacune des sommes suivantes à l'aide d'une liste par compréhension et/ou d'un tableau numpy, au lieu d'une double boucle:

  • $\displaystyle S_1=\sum_{i=1}^n\sum_{j=1}^n ij$
  • $\displaystyle S_2=\sum_{i=1}^n\sum_{j=1}^n i+j$
  • $\displaystyle S_3=\sum_{i=1}^n\sum_{j=1}^n \min(i,j)$
In [ ]:
n=10
# Première idée pour S1 :
# on crée notre liste de liste en python
lst1 = [ [ i*j for j in range(1,n) ] for i in range(1,n)]
print(lst1)
# on essaye de sommer, mais cela na marche pas :
S1 = sum(lst1)
# normal car on ne peut pas ajouter des listes python
[[1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8, 10, 12, 14, 16, 18], [3, 6, 9, 12, 15, 18, 21, 24, 27], [4, 8, 12, 16, 20, 24, 28, 32, 36], [5, 10, 15, 20, 25, 30, 35, 40, 45], [6, 12, 18, 24, 30, 36, 42, 48, 54], [7, 14, 21, 28, 35, 42, 49, 56, 63], [8, 16, 24, 32, 40, 48, 56, 64, 72], [9, 18, 27, 36, 45, 54, 63, 72, 81]]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[12], line 7
      5 print(lst1)
      6 # on essaye de sommer, mais cela na marche pas :
----> 7 S1 = sum(lst1)

TypeError: unsupported operand type(s) for +: 'int' and 'list'
In [13]:
n=10
# Deuxième idée, on met tous les éléments dans une seule liste :
lst1 = [ i*j for j in range(1,n) for i in range(1,n)]
print(lst1)
# Cette fois-ci on peut sommer :
S1 = sum(lst1)
print(S1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 4, 6, 8, 10, 12, 14, 16, 18, 3, 6, 9, 12, 15, 18, 21, 24, 27, 4, 8, 12, 16, 20, 24, 28, 32, 36, 5, 10, 15, 20, 25, 30, 35, 40, 45, 6, 12, 18, 24, 30, 36, 42, 48, 54, 7, 14, 21, 28, 35, 42, 49, 56, 63, 8, 16, 24, 32, 40, 48, 56, 64, 72, 9, 18, 27, 36, 45, 54, 63, 72, 81]
2025
In [ ]:
n=10
# Troisième idée, utiliser des tableaux numpy
lst1 = [ [ i*j for j in range(1,n) ] for i in range(1,n)]
lst1 = np.array(lst1) # conversion de liste de liste en tableau numpy
print(lst1)
# Cette fois-ci on peu sommer :
S1 = sum(sum(lst1))
print(S1)
# ou bien :
S1 = lst1.sum()
print(S1)
[[ 1  2  3  4  5  6  7  8  9]
 [ 2  4  6  8 10 12 14 16 18]
 [ 3  6  9 12 15 18 21 24 27]
 [ 4  8 12 16 20 24 28 32 36]
 [ 5 10 15 20 25 30 35 40 45]
 [ 6 12 18 24 30 36 42 48 54]
 [ 7 14 21 28 35 42 49 56 63]
 [ 8 16 24 32 40 48 56 64 72]
 [ 9 18 27 36 45 54 63 72 81]]
2025
2025
In [14]:
# S2 :
n=10
lst2 = [ [ i+j for j in range(1,n) ] for i in range(1,n)]
lst2 = np.array(lst2) # conversion de liste de liste en tableau numpy
print(lst2)
# Cette fois-ci on peu sommer :
S2 = sum(sum(lst2))
print(S2)
[[ 2  3  4  5  6  7  8  9 10]
 [ 3  4  5  6  7  8  9 10 11]
 [ 4  5  6  7  8  9 10 11 12]
 [ 5  6  7  8  9 10 11 12 13]
 [ 6  7  8  9 10 11 12 13 14]
 [ 7  8  9 10 11 12 13 14 15]
 [ 8  9 10 11 12 13 14 15 16]
 [ 9 10 11 12 13 14 15 16 17]
 [10 11 12 13 14 15 16 17 18]]
810
In [15]:
# S3
n=10
lst3 = [ [ min(i,j) for j in range(1,n) ] for i in range(1,n)]
lst3 = np.array(lst3) # conversion de liste de liste en tableau numpy
print(lst3)
# Cette fois-ci on peu sommer :
S3 = sum(sum(lst3))
print(S3)
[[1 1 1 1 1 1 1 1 1]
 [1 2 2 2 2 2 2 2 2]
 [1 2 3 3 3 3 3 3 3]
 [1 2 3 4 4 4 4 4 4]
 [1 2 3 4 5 5 5 5 5]
 [1 2 3 4 5 6 6 6 6]
 [1 2 3 4 5 6 7 7 7]
 [1 2 3 4 5 6 7 8 8]
 [1 2 3 4 5 6 7 8 9]]
285

3. Affectations : tableaux numpy VS listes python¶

!!! warning Attention ! On a vu que l'on pouvait utiliser le slicing pour extraire des informations depuis une liste ou un tableau, mais que l'on pouvait aussi s'en servir pour affecter des valeurs à une liste ou un tableau. Mais, le comportement pour les listes python et pour les tableaux numpy est bien différent. !!!

Voyons sur des données 1D ces différences, mais cela sera la même choses en dimensions multiples.

On considère les variables suivantes :

import numpy as np
lst = [2,4,6,8,10,12] # liste python
tab = np.array(lst) # tableau numpy

On peut faire :

  • lst[n:p]=[...] : remplace la sous-liste (n-p) de lst par le membre de droite, qui doit être une liste. Cette liste peut ne pas avoir le même nombre d'éléments que la sous-liste. Essayer les exemples suivants, prévoir puis analyser les résultats :

    lst[2:4]=[1]
    print(lst)
    lst[3:4]=[10,11,12,13]
    print(lst)
    lst[3:4]=[]
    print(lst)
    lst[3:3]=[0]
    print(lst)
    lst2 = [1]*5
    print(lst2)
    lst3=lst+lst2
    print(lst3)
    
In [ ]:
# Essayer les commandes ci-dessus :

lst = [2,4,6,8,10,12] # liste python
lst[2:4]=[1]
print(lst)
  • tab[n:p]=[...] : remplace terme à terme les éléments du sous-tableau par ceux de la liste du second membre, qui par conséquent doit avoir le même nombre d'éléments. Mais, il y a un cas particulier très utile : si le membre de droite n'est pas une liste, mais simplement une valeur, alors numpy va broadcaster cette valeur pour la transformer en une liste de bonne dimension. En d'autre termes, tous les éléments du sous-tableau seront remplacés par cette valeur. Essayer les exemples suivants, prévoir et analyser les résultas :

    # les commandes suivantes renvoient des erreurs (probèmes de tailles)
    tab[2:4]=[1]
    tab[3:4]=[10,11,12,13]
    tab[3:4]=[]
    tab[3:3]=[0]
    
    # Analyser les résultats :
    tab[2:4] = [10,11]
    print(tab)
    tab[:3]=5
    print(tab)
    tab[::2]=0
    print(tab)
    tab2 = np.array([1])*5
    print(tab2)
    tab3 = tab+tab2 # erreur si dimensions différentes
    tab4 = tab+tab
    
In [ ]:
# Essayer les commande ci-dessus :

import numpy as np
tab = np.array(lst) # tableau numpy

Exercice 4¶

On considère la liste : lst=['factoriser', 'développer','réduire', 'résoudre','simplifier'] Utiliser le slicing sur les listes python pour effectuer les opérations suivantes :

Q9. Supprimer l'élément 'développer' de la liste.

In [16]:
lst = ['factoriser', 'développer','réduire', 'résoudre','simplifier']
# on supprime l'élément indice 1 :
lst[1:2] = []
print(lst)
['factoriser', 'réduire', 'résoudre', 'simplifier']

Q10. Insérer l'élément 'distribuer' comme premier élément de la liste.

In [17]:
# on insère l'élément au début :
lst[:1] = ['distribuer']
print(lst)
['distribuer', 'réduire', 'résoudre', 'simplifier']

Q11. Remplacer l'élément 'simplifier' par les deux éléments 'hyperbole' et 'parabole'.

In [18]:
lst[-1:]=['hyperbole', 'parabole']
print(lst)
['distribuer', 'réduire', 'résoudre', 'hyperbole', 'parabole']