Le type **array** de la bibliothèque NumPy.

On commence par charger la biblithèque numpy sous l'espace de nom réduit np. Toutes les classes et les fonctions sont alors préfixées par np..

In [1]:
import numpy as np

Le type qui va nous intéresser est array. Il permet de représenter les vecteurs.

In [2]:
v = np.array( [1., 2., 3.] ) # construction à partir d'une liste
print(v)               # affichage différent d'une liste
v # c'est un array, et pas une liste basique Python
[ 1.  2.  3.]
Out[2]:
array([ 1.,  2.,  3.])

On peut récupérer la taille d'un vecteur grâce à la fonction len(), ou grâce à la fonction shape() qui donne en réalité les dimensions d'une quantité de type array (plusieurs dimensions correspondant à une imbrication d'array, utile notamment pour représenter des matrices).

In [3]:
print( "Le vecteur v est de taille", len(v), ".")
print(np.shape(v))
n, = np.shape(v) # v est un vecteur, donc seule la première dimension nous intéresse
print ("Il contient donc ", n, " éléments.")
Le vecteur v est de taille 3 .
(3,)
Il contient donc  3  éléments.
In [4]:
print("matrice")
a = np.zeros(shape=(3,3)) # matrice 3x3
a[1,2] = 1
print(a)
print("tenseur")
a = np.zeros(shape=(2,2,2)) # tenseur à 3 indices
a[0,1,1] = 2
print(a)
matrice
[[ 0.  0.  0.]
 [ 0.  0.  1.]
 [ 0.  0.  0.]]
tenseur
[[[ 0.  0.]
  [ 0.  2.]]

 [[ 0.  0.]
  [ 0.  0.]]]

La manipulation des quantités de type array est similaire à celle des listes Python.

In [5]:
v = np.arange(1, 15, 2) # nombres impairs de 1 à 14 : arange() au lieu de range()
print(v)

v[0] = 100
print(v[:2], v[3:5])
[ 1  3  5  7  9 11 13]
[100   3] [7 9]

Comme pour les listes, il faut faire attention lorsqu'on utilise les affectations, car il y a partage des données. Pour faire une vraie copie, il faut le demander explicitement.

In [6]:
u = np.array([1,2,3])

v = u
w = u.copy()
print(v)
print(w)
print()

u[2] = 100 # modifie u, ainsi que v qui est juste un alias pour u.
print(v)
print(w)
[1 2 3]
[1 2 3]

[  1   2 100]
[1 2 3]

Contrairement à range(), la fonction arange() accepte des nombres flottants en arguments.

In [7]:
v = np.arange(0., 2., 0.3)
print(v)
[ 0.   0.3  0.6  0.9  1.2  1.5  1.8]

De plus, il existe la fonction linspace() qui prend en entrée a, b et n, et qui renvoie un array avec n valeurs allant de a à b et régulièrement espacées.

In [8]:
print(np.linspace(0, 1, 9))
print(np.linspace(0, np.pi, 10))
[ 0.     0.125  0.25   0.375  0.5    0.625  0.75   0.875  1.   ]
[ 0.          0.34906585  0.6981317   1.04719755  1.3962634   1.74532925
  2.0943951   2.44346095  2.7925268   3.14159265]

Les opérations sur les scalaires s'entendent de façon naturelle lorsqu'un des arguments est de type array. L'opération est alors appliqué à chaque élément du vecteur.

In [9]:
print(v)
print(10 * v)
print(np.sqrt(v))
[ 0.   0.3  0.6  0.9  1.2  1.5  1.8]
[  0.   3.   6.   9.  12.  15.  18.]
[ 0.          0.54772256  0.77459667  0.9486833   1.09544512  1.22474487
  1.34164079]

Si on dispose de deux quantités de type array, on peut aussi faire la somme ou le produit coefficient par coefficient grâces aux opérateurs + et * . Attention toutefois à appliquer ces opérations sur des vecteurs de même taille uniquement.

In [10]:
u = np.array( [2., 2., 2., 2., 2., 2., 2.] )
print(u)
print(v)
print()
print(u + v)
print(u * v) # note : ceci est équivalent à 2 * v
[ 2.  2.  2.  2.  2.  2.  2.]
[ 0.   0.3  0.6  0.9  1.2  1.5  1.8]

[ 2.   2.3  2.6  2.9  3.2  3.5  3.8]
[ 0.   0.6  1.2  1.8  2.4  3.   3.6]
In [11]:
u = np.array( [1., 2., 3.] )
u + v # erreur, les tailles de u et v sont différentes
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-11-dcc220a1b4f3> in <module>()
      1 u = np.array( [1., 2., 3.] )
----> 2 u + v # erreur, les tailles de u et v sont différentes

ValueError: operands could not be broadcast together with shapes (3,) (7,) 

Enfin, on dispose de beaucoup de fonctions utiles. Consulter la documentation

In [12]:
print(v)
print("La moyenne des éléments de v est", np.mean(v))
print("De plus, l'écart type est de ", np.std(v))
[ 0.   0.3  0.6  0.9  1.2  1.5  1.8]
La moyenne des éléments de v est 0.9
De plus, l'écart type est de  0.6

Matrices

Voyons maintenant comme définir et manipuler des matrices. La définition peut se faire via le constructeur array(), en donnant cette fois une liste de listes en arguments.

In [13]:
m = np.array( [[1, 2, 3],
               [4, 5, 6]])
print(m)
[[1 2 3]
 [4 5 6]]

Notez que la variable m ainsi définie est en réalité une quantité de type array contenant des valeurs elles-même de type array.

In [14]:
m[0] # première ligne de la matrice
Out[14]:
array([1, 2, 3])

La fonction len() nous permet de récupérer le nombre de lignes de la matrice.

In [15]:
len(m)
Out[15]:
2

La fonction shape() va, elle, nous renvoyer un couple d'entier, nous permettant ainsi de récupérer les dimensions de notre matrice.

In [16]:
np.shape(m)
Out[16]:
(2, 3)

Il existe quelques fonctions pour obtenir rapidement quelques matrices particulières.

In [17]:
print( np.zeros( shape=(3,5) )) # matrice de 0s
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]
In [18]:
print( np.eye(4))# matrice identité de taille 4, identity(4) convient aussi
[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  1.]]
In [19]:
print( np.diag(v)) # matrice diagonale
[[ 0.   0.   0.   0.   0.   0.   0. ]
 [ 0.   0.3  0.   0.   0.   0.   0. ]
 [ 0.   0.   0.6  0.   0.   0.   0. ]
 [ 0.   0.   0.   0.9  0.   0.   0. ]
 [ 0.   0.   0.   0.   1.2  0.   0. ]
 [ 0.   0.   0.   0.   0.   1.5  0. ]
 [ 0.   0.   0.   0.   0.   0.   1.8]]
In [20]:
print( np.ones( (2,3) ))# matrice de 1s
[[ 1.  1.  1.]
 [ 1.  1.  1.]]

Les opérations vues précédemment sur les quantités de type array s'appliquent de manière similaire sur les matrices.

In [21]:
print("m :")
print(m)
print()
print("10 * m :")
print(10 * m)
print()
print("élévation des coefficients de m au carré :")
print(m ** 2)
print()
print("m + matrice de 1s :")
print( m + np.ones( (2,3) ))
m :
[[1 2 3]
 [4 5 6]]

10 * m :
[[10 20 30]
 [40 50 60]]

élévation des coefficients de m au carré :
[[ 1  4  9]
 [16 25 36]]

m + matrice de 1s :
[[ 2.  3.  4.]
 [ 5.  6.  7.]]

On dispose en plus de quelques opérations propres aux matrices.

In [22]:
print( m.transpose()) # transposée
print()
print(m.T) # autre façon d'obtenir la transposée
[[1 4]
 [2 5]
 [3 6]]

[[1 4]
 [2 5]
 [3 6]]
In [23]:
n = np.array( [ [1+1j, 1], [1-1j, 2+3*1j] ] )
print("n :")
print(n)
print()

print("matrice conjuguée :")
print(n.conj())
print()

print("matrice adjointe :")
print(n.conj().T)
n :
[[ 1.+1.j  1.+0.j]
 [ 1.-1.j  2.+3.j]]

matrice conjuguée :
[[ 1.-1.j  1.-0.j]
 [ 1.+1.j  2.-3.j]]

matrice adjointe :
[[ 1.-1.j  1.+1.j]
 [ 1.-0.j  2.-3.j]]

Attention à l'opérateur * qui effectue un produit coefficient par coefficient.

In [24]:
m * m # produit coefficient par coefficient
Out[24]:
array([[ 1,  4,  9],
       [16, 25, 36]])

Pour faire un produit matrice × vecteur ou matrice × matrice, il faut utiliser la fonction dot().

In [25]:
print(m)
print()
print(np.dot(m, np.array([0., 1., 2.]) ))
print()
print(np.dot(np.array([1., 1.]), m))
print()
print(np.dot(m, np.diag([10, 100, 1000]) ))
[[1 2 3]
 [4 5 6]]

[  8.  17.]

[ 5.  7.  9.]

[[  10  200 3000]
 [  40  500 6000]]

Affichage des lignes et des colonnes

In [26]:
m = np.array( [[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]])
# les lignes
print(m[0,:],m[1,:],m[2,:])
print("________________\n")
# les colonnes
print(m[:,0],m[:,1],m[:,2])
[1 2 3] [4 5 6] [7 8 9]
________________

[1 4 7] [2 5 8] [3 6 9]
In [27]:
print(m[:,::-1]) # inversion de l'ordre des colonnes
[[3 2 1]
 [6 5 4]
 [9 8 7]]

Affectation

In [28]:
print(m.shape)
print(m.shape[0], m.shape[1])
for i in range(m.shape[0]):
    for j in range(m.shape[1]):
        m[i,j] = i + j
print(m)
(3, 3)
3 3
[[0 1 2]
 [1 2 3]
 [2 3 4]]
In [29]:
f = lambda x: x**2
print(f(m))
[[ 0  1  4]
 [ 1  4  9]
 [ 4  9 16]]
In [30]:
m[:,:] = 0
print(m)
[[0 0 0]
 [0 0 0]
 [0 0 0]]
In [31]:
m[:] = np.array([1, 2, 3])
print(m)
m[:,2] = np.ones(3)
print(m)
m[1,:] = np.zeros(3)
print(m)
[[1 2 3]
 [1 2 3]
 [1 2 3]]
[[1 2 1]
 [1 2 1]
 [1 2 1]]
[[1 2 1]
 [0 0 0]
 [1 2 1]]