Py: NumPy
Py: NumPy

introduction à NumPy et MatPlotLib

Directory

CheatSheet

01numpy_introduction

numpy

Importer numpy

  • par convention numpy est utilisé via l'alias np
  • cela permet de prefixer les fonctions de la librairie en utilisant np. à la place de numpy.
In [1]:
import numpy as np

Arrays

  • les Arrays représentent une collection de valeurs

contrairement aux listes:

  • les arrays ont une taille fixe

    • elles peuvent être resize mais cela implique la recopie de l'array
  • toutes les valeurs ont le même type

    • typiquement des floats

tout comme les listes:

  • les arrays sont mutables
  • on peut changer les éléments d'un array

Arrays de numpy

  • les array sont fourni par le module numpy
  • la fonction array() crée et arrange une liste donnée
In [2]:
import numpy as np

x = np.array([0, 1, 2, 3, 4])
x
Out[2]:
array([0, 1, 2, 3, 4])

Affichage

  • la fonction print() nous donne un pretty display
In [3]:
print(x)
[0 1 2 3 4]
  • l'utilisation du nom de la variable (dans la console uniquement) nous donne un affichage qui nous permet de différencier les array des listes classiques
In [4]:
x
Out[4]:
array([0, 1, 2, 3, 4])

Indexe

  • on peut utiliser les indexes de la même façon que pour une liste
In [5]:
x[4]
Out[5]:
4
In [6]:
x[4] = 2
x
Out[6]:
array([0, 1, 2, 3, 2])

Les arrays ne sont pas des listes

  • même si ça y ressemble, les array sont une structure de donnée fondamentalement différente:
In [7]:
type(x)
Out[7]:
numpy.ndarray
  • par exemple, on ne peut pas utiliser des methodes comme append()
In [8]:
x.append(5)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-2f1e4fff5cec> in <module>()
----> 1 x.append(5)

AttributeError: 'numpy.ndarray' object has no attribute 'append'

Utilisation de fonctions sur des Arrays

  • Si on utilise des opérateurs arithmétiques sur des arrays, on crée un nouvel array auquel, sur chaque élément, a été appliqué l'opérateur
In [9]:
y = x * 2
y
Out[9]:
array([0, 2, 4, 6, 4])
  • même chose pour les fonctions
In [10]:
x = np.array([-1, 2, 3, -4])
y = abs(x)
y
Out[10]:
array([1, 2, 3, 4])

peupler les Array

  • pour peupler un array avec un range de valeurs, on utilise la fonction np.arange()
In [11]:
x = np.arange(0,10)
print(x)
[0 1 2 3 4 5 6 7 8 9]
  • on peut utiliser une incrémentation float
In [12]:
x = np.arange(0,1,0.1)
print(x)
[ 0.   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9]
In [13]:
x
Out[13]:
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

Vectorisation de fonctions

  • toutes les fonctions ne fonctionnent pas automatiquement avec les arrays
  • les fonctions qui fonctionnes avec les arrays sont dites vectorisées
  • la majorité des fonctions de numpy sont vectorisées
  • on peut définir des fonctions vectorisées nous même (un peu comme la surcharge en C++) grâce a la fonction supérieure numpy.vectorize()
In [14]:
def myfunc(x):
    if x >= 0.5:
        return x
    else:
        return 0.0

fv = np.vectorize(myfunc)
In [15]:
x = np.arange(0, 1, 0.1)
x
Out[15]:
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])
In [16]:
fv(x)
Out[16]:
array([ 0. ,  0. ,  0. ,  0. ,  0. ,  0.5,  0.6,  0.7,  0.8,  0.9])

Plot de base

  • on utilise le module matplotlib pour ploter des graphs
  • ce module fait partie de pyplot
  • par convention nous importons matplotlib via l'alias plt
  • ce module apporte des fonctions très similaires à celles de MATLAB
In [17]:
import matplotlib.pyplot as plt
# uniquement nécéssaire pour Jupyter
%matplotlib inline 

y = x*2 + 5
plt.plot(x, y)
Out[17]:
[<matplotlib.lines.Line2D at 0x1bf1870e3c8>]

Plot d'une sin

In [20]:
from numpy import pi, sin

x = np.arange(0, 2*pi, 0.01)
y = sin(x)
plt.plot(x, y)
Out[20]:
[<matplotlib.lines.Line2D at 0x1bf187c3080>]

Données multidimensionnelles

  • les arrays de numpy peuvent contenir des données multidimensionnelles
  • pour créér un array multidimensionnel, nous pouvons passer une liste de listes à la fonction array()
In [22]:
import numpy as np

x = np.array([[1, 2], [3, 4]])
x
Out[22]:
array([[1, 2],
       [3, 4]])

Array d'arrays

  • un array multidimensionnel est un array d'array
  • l'array extérieur contient les lignes
  • chaque ligne est un array
In [24]:
x[0]
Out[24]:
array([1, 2])
In [25]:
x[1]
Out[25]:
array([3, 4])
  • l'élément dans la seconde ligne et première colonne est:
In [26]:
x[1][0]
Out[26]:
3

Matrices

  • nous pouvons transformer un array multidimensionnel en matrice
In [27]:
M = np.matrix(x)
M
Out[27]:
matrix([[1, 2],
        [3, 4]])

Plot multidimensionnel avec des matrices

  • si nous utilisons plot() pour ploter une matrice, ce dernier utilisera les valeurs de l'axe des y (colones de la matrice).
In [31]:
from numpy import pi, sin, cos

x = np.arange(0, 2*pi, 0.01)
y = sin(x)
ax = plt.plot(x, np.matrix([sin(x), cos(x)]).T)

Performance

  • les matrices de numpy sont liées à des fonctions correspondantes écritent en C et FORTRAN
  • Ces librairies sont très rapides et peuvent être configurées de façon à ce que les opérations soient faites en parallèle sur plusieurs coeurs.

Opérations sur les matrices

  • Une fois que nous avons une matrice nous pouvons lui appliquer des opérations spécifiques à ces dernières
  • pour transposer et inverser on utilise respectivement les attributs T et I
In [35]:
import numpy as np

x = np.array([[1, 2], [3, 4]])
M = np.matrix(x)
M
Out[35]:
matrix([[1, 2],
        [3, 4]])

Pour effectuer la transposition $M^T$:

In [36]:
M.T
Out[36]:
matrix([[1, 3],
        [2, 4]])

Pour effectuer l'inversion $M^{-1}$:

In [37]:
M.I
Out[37]:
matrix([[-2. ,  1. ],
        [ 1.5, -0.5]])

Dimensions d'une matrice

  • le nombre total d'éléments et les dimensions de la matrice:
In [38]:
M.size
Out[38]:
4
In [39]:
M.shape
Out[39]:
(2, 2)
In [40]:
len(M.shape)
Out[40]:
2

Créer une matrice à partir de strings

  • nous pouvons aussi créér des matrices directement à partir de strigs:
In [41]:
I2 = np.matrix('2 0; 0 2')
I2
Out[41]:
matrix([[2, 0],
        [0, 2]])
  • le point virgule (;) marque le début d'une nouvelle ligne

Multiplication de matrices

  • maintenant que nous avons deux matrices, nous pouvons les multiplier:
In [42]:
M * I2
Out[42]:
matrix([[2, 4],
        [6, 8]])

Indexes et matrices

  • nous pouvons utiliser les indexes et même slicer une matrices en utilisant la même syntaxe que pour les listes
In [43]:
M[:,1]
Out[43]:
matrix([[2],
        [4]])

Les slices sont des références

  • de la façon suivante, on crée une référence à l'élément slicé et non pas une copie
In [44]:
V = M[:,1] # ne crée pas une copie des éléments mais référence l'objet initial !
V
Out[44]:
matrix([[2],
        [4]])
In [45]:
M[0,1] = -2
V
Out[45]:
matrix([[-2],
        [ 4]])

Copier des matrices et des vecteurs

  • pour copier une matrice ou une slice de ses éléments, on utilise la fonction np.copy()
In [46]:
M = np.matrix('1 2; 3 4')
V = np.copy(M[:,1]) # copie des éléments
V
Out[46]:
array([[2],
       [4]])
In [47]:
M[0,1] = -2
V
Out[47]:
array([[2],
       [4]])

Somme

  • une façon de faire la sommer un vecteur ou une matrice est via une boucle for
In [48]:
vector = np.arange(0.0, 100.0, 10.0)
vector
Out[48]:
array([  0.,  10.,  20.,  30.,  40.,  50.,  60.,  70.,  80.,  90.])
In [49]:
result = 0.0
for x in vector:
    result += x

result
Out[49]:
450.0
  • ce n'est pas une façon éfficace d'effectuer une somme

Somme efficace

  • à la place de la boucle for nous pouvons utiliser la fonction sum()
  • cette fonction est écrite en C et est beaucoup plus performante
In [50]:
vector = np.array([0, 1, 2, 3, 4])
print(np.sum(vector))
10

Somme des lignes / colones

  • quand nous avons affaire à des données multidimensionnelles, la fonction sum() possède un argument axis qui ne permet de spécifier si nous désirons la somme des lignes ou des colonnes
In [51]:
matrix = np.matrix('1 2 3; 4 5 6; 7 8 9')
print(matrix)
[[1 2 3]
 [4 5 6]
 [7 8 9]]
  • somme des lignes
In [53]:
np.sum(matrix, axis=0)
Out[53]:
matrix([[12, 15, 18]])
  • somme des colonnes
In [54]:
np.sum(matrix, axis=1)
Out[54]:
matrix([[ 6],
        [15],
        [24]])

Sommes cumulatives

In [55]:
x = np.matrix('1 2 3; 4 5 6; 7 8 9')
print(x)
[[1 2 3]
 [4 5 6]
 [7 8 9]]
In [59]:
y = np.cumsum(x)
print(np.cumsum(x, axis=0))
[[ 1  2  3]
 [ 5  7  9]
 [12 15 18]]
In [60]:
print(np.cumsum(x, axis=1))
[[ 1  3  6]
 [ 4  9 15]
 [ 7 15 24]]

Produit cumulé

  • de façon similaire, nous pouvons calculer $\large{y_n = \Pi^{n}_{i-1}{x_i}}$ en utilisant cumprod()
In [62]:
import numpy as np
x = np.array([1, 2, 3, 4, 5])
print(np.cumprod(x))
[  1   2   6  24 120]
  • nous pouvons calculer le produit cummulatif entre les lignes et les colonnes en utilisant le paramètre axis.

Génération de nombres pseudo aléatoires

  • le sous module numpy.random contient des fonctions pour générer des nombres aléatoires
In [63]:
from numpy.random import normal, uniform, exponential, randint
  • supposons que nous avons une variable aléatoire $\large{\epsilon \sim N(0,1)}$
  • dans Python nous pouvons utiliser cette distribution de la façon suivante:
In [66]:
epsilon = normal()
print(epsilon)
-1.2582109218484931
  • chaque appel de cette variable nous retournera la même valeur
In [68]:
print(epsilon)
-1.2582109218484931
  • si nous appellons encore une fois la fonction, celà va nous retourner un nouveau draw de cette distribution:
In [69]:
epsilon = normal()
print(epsilon)
-0.6266440554602674

Nombres pseudo-aléatoires

  • en réalité ces nombres ne sont pas des nombres aléatoires
  • ils sont basés sur un état initial appelé seed
  • si nous connaissons le seed, nous pouvons prédire précisément le reste de la séquence à partir de n'importe quel nombre "aléatoire".
  • cela dit, statistiquement parlant ces nombres se comportent comme des nombres aléatoires

Gestion des seed

  • dans certains cas nous avons besoin de pouvoir reproduir une séquence de nombres pseudo aléatoires
  • nous pouvons spécifier la valeur du seed avant utilisation de ces nombres
  • pour se faire on utilise la fonction seed() dans le sous module numpy.random
In [70]:
from numpy.random import seed

seed(5)
In [71]:
normal()
Out[71]:
0.44122748688504143
In [72]:
normal()
Out[72]:
-0.33087015189408764
In [73]:
seed(5)
In [74]:
normal()
Out[74]:
0.44122748688504143
In [75]:
normal()
Out[75]:
-0.33087015189408764

Générer multiple

  • pour se faire nous pouvons spécifier le paramétre size:
In [76]:
normal(size=10)
Out[76]:
array([ 2.43077119, -0.25209213,  0.10960984,  1.58248112, -0.9092324 ,
       -0.59163666,  0.18760323, -0.32986996, -1.19276461, -0.20487651])

Cette façon de procéder est BEAUCOUP plus rapide qu'une boucle for!

  • nous pouvons également spécifier plus d'une dimension:
In [77]:
normal(size=(5,5))
Out[77]:
array([[-0.35882895,  0.6034716 , -1.66478853, -0.70017904,  1.15139101],
       [ 1.85733101, -1.51117956,  0.64484751, -0.98060789, -0.85685315],
       [-0.87187918, -0.42250793,  0.99643983,  0.71242127,  0.05914424],
       [-0.36331088,  0.00328884, -0.10593044,  0.79305332, -0.63157163],
       [-0.00619491, -0.10106761, -0.05230815,  0.24921766,  0.19766009]])

Histogrammes

  • pour ploter un histogramme de données distribuées aléatoirement, on utilise la fonction hist() de mtplotlib:
In [79]:
import matplotlib.pyplot as plt
%matplotlib inline

data = normal(size=10000)
ax = plt.hist(data)

Calculer les histogrammes en matrices

  • la fonction histogram() dans le module numpy compte les fréquences dans les plages et retourner le résultat sous forme d'array 2d:
In [80]:
import numpy as np
np.histogram(data)
Out[80]:
(array([  23,  136,  618, 1597, 2626, 2635, 1620,  599,  130,   16], dtype=int64),
 array([-3.59780883, -2.87679609, -2.15578336, -1.43477063, -0.71375789,
         0.00725484,  0.72826758,  1.44928031,  2.17029304,  2.89130578,
         3.61231851]))

Statistiques

  • nous pouvons calculer les statistiques d'un sample de données en utilisant les fonctions de numpy mean() et var()
In [81]:
np.mean(data)
Out[81]:
-0.00045461080333497925
In [82]:
np.var(data)
Out[82]:
1.0016048722546331
  • ces fonctions ont aussi un paramètre axis pour calculer la moyenne d'arrays multidimensionnels.

Nombres aléatoires discrets

  • la fonction randint() du module numpy.random peut être utilisé pour sortir des nombres aléatoires
  • il prend deux paramètres: valeur basse (inclus), et valeur haute (exclue)
  • pour simuler un jet de dé:
In [83]:
die_roll = randint(0,6)+1
die_roll
Out[83]:
4

Résumé

02Numpy-tuto

Numpy

doc numpy

Numpy est une librairie centrale pour le calcule scientifique en Python. Elle contient une collection d'outils qui permettent de résoudre et de modéliser des problèmes mathématiques, scientifiques et du domaine de l'ingénierie.

Le coeur de ces outils est une structure de données de type liste multidimentionnelle de haut performance qui se nome tout simplement Array (Numpy Array).

  • Voici un exemple d'un array 2d dans Numpy:
In [4]:
import numpy

M = numpy.array([[1,2,3], [4,5,6]])
M
Out[4]:
array([[1, 2, 3],
       [4, 5, 6]])

Performance

  • les matrices de numpy sont liées à des fonctions correspondantes écritent en C et FORTRAN
  • Ces librairies sont très rapides et peuvent être configurées de façon à ce que les opérations soient faites en parallèle sur plusieurs coeurs.

Dimensions

Cette illustration représente les 3 premières dimensions de l'objet mathématique matrice

  • axis 0 (idx[0]) axe des $\large x$
  • axis 1 (idx[0][0]) axe des $\large y$
  • axis 2 (idx[0][0][0]) axe des $\large z$

Et voici la représentation de matrices comme nous le print() Numpy

  • matrice à une dimension:
[1,1,1]
  • matrice à deux dimensions:
[[[1 1 1] [1 1 1] [1 1 1]]
  • matrice à trois dimensions:
[[[1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1]]]

Arrays

  • les Arrays représentent une collection de données

contrairement aux listes:

  • les arrays ont une taille fixe

    • elles peuvent être resize mais cela implique la recopie de l'array
  • c'est une collection homogène (toutes les données ont le même type)

    • typiquement des floats

tout comme les listes:

  • les arrays sont mutables (on peut changer les éléments d'un array)

Numpy permet de créer plusieurs types d'arrays. On appelle:

  • vecteur un array 1d
  • matrice un array multi d. (fondamentalement c'est un vecteur aussi)

L'implémentation des Numpy Arrays possède 4 pointeurs importants:

  • data pointe sur l'adresse du premier byte de l'array
  • dtype pointe sur une représentation du type de donnès que contient la collection
  • shape pointe sur une représentation de la forme de l'array (tuple dont le nombre d'éléments représente le nombre de dimensions et la clé des éléments la taille de cette dimension)
  • strides pointe sur une représentation du nombre de bytes qui doivent être sauté en mémoire pour arriver au prochain élément. Si l'objet retourné est par exemple (10,1) ont doit sauter 1 byte pour passer à la colonne suivante et 10 bytes pour sauter à la ligne suivante.

En somme, un array contient des informations concernant les raw data (données en elles mêmes) mais aussi sur comment interpréter ces données.

In [5]:
print("représentation:  \n",    M,"\n")
print("pointeur data:   \t",    M.data)
print("pointeur type:   \t",    M.shape)
print("pointeur shape:  \t",   M.dtype)
print("pointeur strides:\t", M.strides)
représentation:  
 [[1 2 3]
 [4 5 6]] 

pointeur data:   	 <memory at 0x0000025C90B9B048>
pointeur type:   	 (2, 3)
pointeur shape:  	 int32
pointeur strides:	 (12, 4)

Les arrays possèdent des methodes qui nous permettent d'inspecter notre array voici celles qui peuvent être uttile à ce niveau:

  • .ndim retourne le nombre de dimensions
In [6]:
print(M.ndim)
2
  • .size retourne le nombre d'éléments
In [7]:
print(M.size)
6
  • .flags retourne des informations utiles sur la gestion de la mémoire
In [8]:
print(M.flags)
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
  • .itemize retourne le poids d'un élément de l'array en bytes
In [9]:
print(M.itemsize)
4
  • .nbytes retourne le poids total en bytes de l'array
In [10]:
print(M.nbytes)
24

Création d'arrays

  • par convention numpy est utilisé via l'alias np
  • cela permet de prefixer les fonctions de la librairie en utilisant np. à la place de numpy.
In [11]:
import numpy as np

Creation d'array 1d

  • conversion de listes classiques en array
In [12]:
a = [1,3,5,7,9]

print(type(a))
print(a)
<class 'list'>
[1, 3, 5, 7, 9]
In [13]:
b = np.array(a)

print(type(b))
print(b)
<class 'numpy.ndarray'>
[1 3 5 7 9]
  • création directe d'array
In [14]:
a = np.array([1,3,5,7,9], dtype=np.int64)

print(a)
print(a.dtype)
[1 3 5 7 9]
int64
  • il n'est pas obligatoire de spécifier le type de données par défaut ce sont des int32
In [15]:
b = np.array([1,3,5,7,9])

print(b)
print(b.dtype)
[1 3 5 7 9]
int32

Création de matrices (multi d.)

  • conversion de liste 2d en matrice
In [16]:
l = [[1,2,3], [4,5,6], [7,8,9]]
A = np.array(l)

print(A)
[[1 2 3]
 [4 5 6]
 [7 8 9]]
  • création directe de matrice
In [17]:
B = np.array([[1,2,3], [4,5,6], [7,8,9]])

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

Création d'array "vides" et peuplement d'array

Parfois on ne sait pas d'avance la valeurs des données que contiendra notre array où ces données seront importé d'une autre source. Dans ce cas on initialisera l'array respectivement avec des des placeholders "vides" ou nous utiliserons des fonctions pour charger les données à partir de fichiers textes. Un array vide est un array qui ne contient que des $1$ ou des $0$ qui sont les placeholders qui seront remplis par la suite.

ones(shape, dtype=None)

  • matrice 2d remplie de $1$ (si nous ne spécifions pas le type, par défaut la methode ones initialise avec des floats64)
In [18]:
a = np.ones((3,4))

print(a)
print(a.dtype)
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
float64
In [19]:
a = np.ones((3,4), dtype=np.int32)

print(a)
print(a.dtype)
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]
int32

zeros(shape, dtype=float)

  • matrice 3d de 0
In [20]:
b = np.zeros((2,3,4), dtype=np.int32)

print(b)
[[[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 0 0 0]
  [0 0 0 0]]]

empty(shape, dtype=float)

  • matrice 2d "vide" d'un certain type (par défaut float64)
In [21]:
c = np.empty((3,2), dtype=np.int32)

print(c)
print(c.dtype)
[[0 0]
 [0 0]
 [0 0]]
int32

random(shape)

  • matrice 2d remplie avec des valeurs aléaoires (pas de paramètre dtype)
In [22]:
d = np.random.random((3,2))

print(d)
print(d.dtype)
[[ 0.09215501  0.01565501]
 [ 0.20720279  0.92122324]
 [ 0.71029601  0.11913718]]
float64
  • matrice 2d remplie avec des valeurs aléatoires dans un range
In [23]:
d = np.random.uniform(low=0, high=30, size=(3,2))

print(d)
[[ 11.19862244  22.98332516]
 [ 14.15014321  19.59095938]
 [  4.04744523   5.37088694]]
  • matrice 2d remplie avec des valeurs aléatoires (int) dans un range
In [24]:
d = np.random.randint(30, size=(4,2)).astype(np.int16)
print(d)
[[ 6  8]
 [ 1  9]
 [ 8 14]
 [19  6]]

full(shape, fill_value, dtype=None)

  • matrice 3d remplie avec une valeur spécifique (warning si on ne spécifie pas de dtype)
In [25]:
e = np.full((3,2,3),5, dtype=np.int32)

print(e)
print(e.dtype)
[[[5 5 5]
  [5 5 5]]

 [[5 5 5]
  [5 5 5]]

 [[5 5 5]
  [5 5 5]]]
int32

arange(start=None, stop, step=None, dtype=None)

  • array 1d de valeurs espacées uniformément
In [26]:
f = np.arange(10,25,5)

print(f)
print(f.dtype)
[10 15 20]
int32
  • incrémentation à virgule flotante
In [27]:
f = np.arange(0,1,0.1)

print(f)
print(f.dtype)
[ 0.   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9]
float64

linspace(start, stop, endpoint=True, retstep=False, dtype=None)

  • array 1d de valeurs espacées uniformément
In [28]:
g = np.linspace(0,2,9)

print(g)
print(g.dtype)
[ 0.    0.25  0.5   0.75  1.    1.25  1.5   1.75  2.  ]
float64

arange() et linspace() nous permettent de peupler des arrays avec des valeurs espacées uniformément. La différence entre les deux est la signification du 3e paramètre passé en argument.

  • arange(): c'est le step qui désigne l'écart entre deux valeurs
  • linspace() c'est le nombre de samples:
In [29]:
for i in range(7,0,-1):
    print(np.linspace(0, 5, i, dtype=np.int32))
[0 0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 5]
[0 1 3 5]
[0 2 5]
[0 5]
[0]

Création d'array et matrice "identité"

An identity matrix is a square matrix of which all elements in the principal diagonal are ones and all other elements are zeros. When you multiply a matrix with an identity matrix, the given matrix is left unchanged.

In other words, if you multiply a matrix by an identity matrix, the resulting product will be the same matrix again by the standard conventions of matrix multiplication.

eye(N, M=None, k=0, dtype=float)

  • retourne une matrice 2d avec des $1$ sur la diagonale principale et les reste remplis avec des $0$
In [30]:
h = np.eye(3)

print(h)
print(h.dtype)
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
float64

identity(n, dtype=None)

  • retourne une matrice identité carrée (The identity array is a square array with ones on the main diagonal)
In [31]:
i = np.identity(4)

print(i)
print(i.dtype)
[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  1.]]
float64

Remplir un array avec les valeurs d'un fichier

loadtxt()

fichier value.txt

In [32]:
# Value1  Value2  Value3
# 0.2536  0.1008  0.3857
# 0.4839  0.4536  0.3561
# 0.1292  0.6875  0.5929
# 0.1781  0.3049  0.8928
# 0.6253  0.3486  0.8791
In [33]:
x, y, z = np.loadtxt('C:/Users/sol.rosca/Jupyter_notbooks/value.txt',
                    skiprows=1,
                    unpack=True)

genfromtxt()

fichier value2.txt

In [34]:
# Value1  Value2  Value3
# 0.4839  0.4536  0.3561
# 0.1292  0.6875  MISSING
# 0.1781  0.3049  0.8928
# MISSING 0.5801  0.2038
# 0.5993  0.4357  0.7410
In [35]:
my_array = np.empty((3,7))
my_array = np.genfromtxt('C:/Users/sol.rosca/Jupyter_notbooks/value2.txt',
                      skip_header=1,
                      filling_values=-999)
  • loadtxt() charge les données dans notre environement.
    • le premier parmètre que prenne les deux fonctions est le path du fichier value.txt.
    • ensuite viennent des arguments spécifiques au fonctions.
  • pour loadtxt() on passe la première ligne et on retourne les colonnes comme étant des arrays distincts avec l'argument unpack=TRUE. Celà veut dire que les valeurs de la première colonne (value1) vont dans la variable x etc...

à noter que si nous avons des valeurs délimitées par des virgules, ou si nous voulons spécifier le type de données, il existe des arguments delimiter et dtype qu'on peut ajouter à loadtxt()

  • genfromtxt() est utile dans le cas où nous avons à gérer un fichier où il manque des valeurs. Dans le cas présent, les valeurs manquantes sont marquées dans le fichier par string 'MISSING'. Cette fonction, converti les valeurs par l'argument du paramètre filing_values qu'on a ici set à la valeur -999.

Généralement la fonction genfromtxt() est plus flexible et plus robuste que loadtxt()et offre plus de possibilités.

In [36]:
M = np.array([x,y,z])
print(M)
[[ 0.2536  0.4839  0.1292  0.1781  0.6253]
 [ 0.1008  0.4536  0.6875  0.3049  0.3486]
 [ 0.3857  0.3561  0.5929  0.8928  0.8791]]
In [37]:
print(my_array)
[[  4.83900000e-01   4.53600000e-01   3.56100000e-01]
 [  1.29200000e-01   6.87500000e-01  -9.99000000e+02]
 [  1.78100000e-01   3.04900000e-01   8.92800000e-01]
 [ -9.99000000e+02   5.80100000e-01   2.03800000e-01]
 [  5.99300000e-01   4.35700000e-01   7.41000000e-01]]

Sauvegarder des arrays

In [38]:
import numpy as np
x = np.arange(0.0,5.0,1.0)
np.savetxt('test.npy', x, delimiter=',')

Il existe également les 3 façons supplémentaires de sauvgarder un array dans un fichier texte:

  • save() sauvegarde un array au format binaire npy
  • savez() sauvegarde plusieurs arrays au format non compressé npz
  • savez_compressed() sauvegarde plusieurs arrays et les compresse dans un npz

plus d'informations

Vectorisation de fonctions

  • toutes les fonctions ne fonctionnent pas automatiquement avec les arrays
  • les fonctions qui fonctionnes avec les arrays sont dites vectorisées
  • la majorité des fonctions de numpy sont vectorisées
  • on peut définir des fonctions vectorisées nous même (un peu comme la surcharge en C++) grâce a la fonction supérieure numpy.vectorize()
In [39]:
def myfunc(x):
    if x >= 0.5:
        return x
    else:
        return 0.0

fv = np.vectorize(myfunc)
In [40]:
x = np.arange(0, 1, 0.1)
print(x)
[ 0.   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9]
In [41]:
print(fv(x))
[ 0.   0.   0.   0.   0.   0.5  0.6  0.7  0.8  0.9]

Plots

  • on utilise le module matplotlib pour ploter des graphs
  • ce module fait partie de pyplot
  • par convention nous importons matplotlib via l'alias plt
  • ce module apporte des fonctions très similaires à celles de MATLAB

Plot de base

dans jupyter plt.show() crash (se renseigner)

In [42]:
import matplotlib.pyplot as plt
# uniquement nécéssaire pour Jupyter:
%matplotlib inline 

x = np.arange(0, 1, 0.1)

y = x*2 + 5
plt.plot(x, y)
Out[42]:
[<matplotlib.lines.Line2D at 0x25c9152f6a0>]
  • en éditeur on rajoute le .show() pour display
import numpy as np import matplotlib.pyplot as plt x = np.arange(0, 1, 0.1) y = x*2 + 5 plt.plot(x, y) plt.show()

plot d'une sin

In [43]:
from numpy import pi, sin

x = np.arange(0, 2*pi, 0.01)
y = sin(x)
plt.plot(x, y)
Out[43]:
[<matplotlib.lines.Line2D at 0x25c915d4320>]

plot de données

In [44]:
tps, Uch0, Uch1, Ut, It, pT = np.loadtxt('C:/Users/sol.rosca/Jupyter_notbooks/10khz.txt',
                skiprows=0,
                unpack=True)

x = tps
y = Uch0 -Uch1

plt.plot(x,y)
Out[44]:
[<matplotlib.lines.Line2D at 0x25c9167dba8>]

Matrices

In [45]:
import numpy as np

x = np.array([[1, 2], [3, 4]])
x
Out[45]:
array([[1, 2],
       [3, 4]])
  • nous pouvons transformer un array multidimensionnel en matrice
  • une matrice est un objet qui permet des opérations différentes que celles qu'on fait sur les arrays
In [46]:
M = np.matrix(x)
M
Out[46]:
matrix([[1, 2],
        [3, 4]])

Créer une matrice à partir de strings

  • nous pouvons aussi créér des matrices directement à partir de strigs ce qui économise des touches:
  • le point virgule (;) marque le début d'une nouvelle ligne
In [47]:
M = np.matrix('2 0; 0 2')
M
Out[47]:
matrix([[2, 0],
        [0, 2]])

Plot multidimensionnel avec des matrices

  • si nous utilisons plot() pour ploter une matrice, ce dernier utilisera les valeurs de l'axe des y (colones de la matrice).
In [48]:
from numpy import pi, sin, cos

x = np.arange(0, 2*pi, 0.01)
y = sin(x)
ax = plt.plot(x, np.matrix([sin(x), cos(x)]).T)

Indexes et slices

Ces opérations sont très similaires aux opérations qu'on peut faire sur les listes.

Indexes

In [49]:
m = np.random.random((3,3,3))

print(m)
[[[ 0.63941646  0.81352733  0.90651091]
  [ 0.51359365  0.24843515  0.15306928]
  [ 0.33191867  0.22029804  0.62857814]]

 [[ 0.49583472  0.98747013  0.72117189]
  [ 0.79852925  0.70926013  0.41980934]
  [ 0.11007736  0.47368575  0.07903667]]

 [[ 0.92623158  0.00308526  0.7942609 ]
  [ 0.58085088  0.55688129  0.92179524]
  [ 0.99415609  0.47479977  0.03155755]]]
  • retourne l'élément à l'indice 1
In [50]:
print(m[1])
[[ 0.49583472  0.98747013  0.72117189]
 [ 0.79852925  0.70926013  0.41980934]
 [ 0.11007736  0.47368575  0.07903667]]
  • retourne l'élément de la première ligne, seconde colone $(1,2)$
In [51]:
print(m[1][2])
[ 0.11007736  0.47368575  0.07903667]
  • même chose syntaxedifférente
In [52]:
print(m[1,2])
[ 0.11007736  0.47368575  0.07903667]
  • retourne l'élément de le première ligne, première colone, et 2 èlement de l'axe des $\Large z$ $(1,1,2)$
In [53]:
print(m[1,1,2])
0.419809341929

Slices

  • basique:
a[start:end] # items start through the end (but the end is not included!) a[start:] # items start through the rest of the array a[:end] # items from the beginning through the end (but the end is not included!)
In [54]:
n = np.array([[1,2], [3,4]])
print(n)
[[1 2]
 [3 4]]
  • accès aux colones:
In [55]:
o = n[:,1]
print(o)
[2 4]
  • accès aux lignes:
In [56]:
p = n[:1]
print(p)
[[1 2]]
  • même syntaxe pour les matrices:
In [57]:
N = np.matrix('6 7; 8 9')
print(N)
[[6 7]
 [8 9]]
In [58]:
O = N[:,1]
print(O)
[[7]
 [9]]
In [59]:
P = N[:1]
print(P)
[[6 7]]
  • Les slices sont une référence à l'objet initial et non pas une copie
In [60]:
o[1] = 10
print(n)
[[ 1  2]
 [ 3 10]]
In [61]:
O[1] = 10
print(N)
[[ 6  7]
 [ 8 10]]

Copier des matrices et des vecteurs

  • pour copier une matrice ou une slace de ses éléments, on utilise la fonction np.copy()
In [62]:
M = np.matrix('1 2; 3 4')
a = np.copy(M[:,1])

print(a)
[[2]
 [4]]
In [63]:
M[0,1] = -2
print(a)
[[2]
 [4]]

Somme

  • une façon de sommer les éléments d'un array ou d'une matrice est d'utiliser une boucle for
In [64]:
a = np.arange(0.0, 100.0, 10.0)
print(a)
[  0.  10.  20.  30.  40.  50.  60.  70.  80.  90.]
In [65]:
result = 0.0
for x in a:
    result += x

print(result)
450.0

Cette façon de faire est très couteuse en ressources. À éviter !

Somme efficace

  • à la place de la boucle for nous pouvons utiliser la fonction sum()
  • cette fonction est écrite en C et est beaucoup plus performante
In [66]:
a = np.array([0, 1, 2, 3, 4])
print(np.sum(a))
10

Somme des lignes / colones

  • quand nous avons affaire à des données multidimensionnelles, la fonction sum() possède un argument axis qui ne permet de spécifier si nous désirons la somme des lignes ou des colonnes
In [67]:
M = np.matrix('1 2 3; 4 5 6; 7 8 9')
print(M)
[[1 2 3]
 [4 5 6]
 [7 8 9]]
  • somme des lignes
In [68]:
print(np.sum(M, axis=0))
[[12 15 18]]
  • somme des colonnes
In [69]:
print(np.sum(M, axis=1))
[[ 6]
 [15]
 [24]]

Arrays dans la pratique

In [70]:
import numpy as np
  • les arrays sont des mutables et les variables qui les référencent peuvent pointer sur la même adresse

opérateur d'affectation (=)

  • référence du même objet
In [71]:
x = np.array([1,2,3,4])
y = x
x is y
Out[71]:
True
In [72]:
id(x), id(y)
Out[72]:
(2596600139328, 2596600139328)
In [73]:
x[0] = 9
y
Out[73]:
array([9, 2, 3, 4])
In [74]:
x[0] = 1
z = x[:]
x is z
Out[74]:
False
In [75]:
id(x), id(z)
Out[75]:
(2596600139328, 2596598756976)
In [76]:
x[0] = 8
z
Out[76]:
array([8, 2, 3, 4])

methode copy()

  • nouvel objet
In [77]:
x = np.array([1,2,3,4])
y = x.copy()
x is y
Out[77]:
False
In [78]:
id(x), id(y)
Out[78]:
(2596600339872, 2596598640192)
In [79]:
x[0] = 9
x
Out[79]:
array([9, 2, 3, 4])
In [80]:
y
Out[80]:
array([1, 2, 3, 4])

opérations basiques

In [81]:
a = np.arange(4.0)
print(a)
[ 0.  1.  2.  3.]
In [82]:
b = a * 23.4
print(b)
[  0.   23.4  46.8  70.2]
In [83]:
c = b/(a+1)
print(c)
[  0.    11.7   15.6   17.55]
In [84]:
c += 10
print(c)
[ 10.    21.7   25.6   27.55]

liste comme indexe

In [85]:
arr = np.arange(100,200)
print(arr)
[100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
 190 191 192 193 194 195 196 197 198 199]
In [86]:
select = [5,25,50,75,-5]
print(arr[select])
[105 125 150 175 195]

array de booléens

In [87]:
arr = np.arange(10, 20)
print(arr)
[10 11 12 13 14 15 16 17 18 19]
In [88]:
div_by_3 = (arr % 3 == 0)
print(div_by_3)
[False False  True False False  True False False  True False]
  • on peut également utiliser une liste de booléens comme indice
In [89]:
print(arr[div_by_3])
[12 15 18]

Methodes sur les arrays

In [90]:
arr = np.arange(10, 20)
print(arr)
[10 11 12 13 14 15 16 17 18 19]
In [91]:
arr.reshape((2,5))
print(arr)
[10 11 12 13 14 15 16 17 18 19]
In [92]:
arr.sum()
Out[92]:
145
In [93]:
arr.mean()
Out[93]:
14.5
In [94]:
arr.std()
Out[94]:
2.8722813232690143
In [95]:
arr.max()
Out[95]:
19
In [96]:
arr.min()
Out[96]:
10
In [97]:
div_by_3.all()
Out[97]:
False
In [98]:
div_by_3.any()
Out[98]:
True
In [99]:
div_by_3.sum()
Out[99]:
3
In [100]:
div_by_3.nonzero()
Out[100]:
(array([2, 5, 8], dtype=int64),)

.nonzero()

A common use for nonzero is to find the indices of an array, where a condition is True. Given an array a, the condition a > 3 is a boolean array and since False is interpreted as 0, np.nonzero(a > 3) yields the indices of the a where the condition is true.

In [101]:
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
a > 3
Out[101]:
array([[False, False, False],
       [ True,  True,  True],
       [ True,  True,  True]], dtype=bool)
In [102]:
np.nonzero(a > 3)
Out[102]:
(array([1, 1, 1, 2, 2, 2], dtype=int64),
 array([0, 1, 2, 0, 1, 2], dtype=int64))
  • The nonzero method of the boolean array can also be called.
In [103]:
(a > 3).nonzero()
Out[103]:
(array([1, 1, 1, 2, 2, 2], dtype=int64),
 array([0, 1, 2, 0, 1, 2], dtype=int64))

Tri d'arrays

  • sort() agit directement sur l'array

Create the array a=[2.3 1.2 5.4 1.7 7 0.4 5.1 6.3] and sort the elements

In [104]:
a = np.array([2.3, 1.2, 5.4, 1.7, 7, 0.4, 5.1, 6.3])
b = np.sort(a)
print(b)
[ 0.4  1.2  1.7  2.3  5.1  5.4  6.3  7. ]

Sort the arguments and show the array b = [5 7 2 3 4 1 9 8] in the same order of the arguments.

In [105]:
c = np.array([5, 7, 2, 3, 4, 1, 9, 8])
s = a.argsort()
print(c[s])
[1 7 3 5 9 2 8 4]

Transposition d'arrays

What transposing your arrays actually does is permuting the dimensions of it. Or, in other words, you switch around the shape of the array. Let’s take a small example to show you the effect of transposition:

In [106]:
arr = np.array([[1,2,3,4],[5,6,7,8]])
print(arr)
[[1 2 3 4]
 [5 6 7 8]]
In [107]:
print(np.transpose(arr))
[[1 5]
 [2 6]
 [3 7]
 [4 8]]
  • de façon équivalente on peut utiliser .T pour transposer:
In [108]:
print(arr.T)
[[1 5]
 [2 6]
 [3 7]
 [4 8]]

Opérations sur les matrices

  • Une fois que nous avons une matrice nous pouvons lui appliquer des opérations spécifiques à ces dernières
  • pour transposer et inverser on utilise respectivement les attributs T et I
In [109]:
x = np.array([[1, 2], [3, 4]])
M = np.matrix(x)
M
Out[109]:
matrix([[1, 2],
        [3, 4]])

transposition $M^T$:

In [110]:
M.T
Out[110]:
matrix([[1, 3],
        [2, 4]])

inversion $M^{-1}$:

In [111]:
M.I
Out[111]:
matrix([[-2. ,  1. ],
        [ 1.5, -0.5]])

dot product:

In [112]:
j = np.array([[0.0, -1.0], [1.0, 0.0]])
print(j)
[[ 0. -1.]
 [ 1.  0.]]
In [113]:
np.dot(j, j)
Out[113]:
array([[-1.,  0.],
       [ 0., -1.]])
In [114]:
j = np.matrix('0. -1,; 1. 0.')
In [115]:
print(j)
[[ 0. -1.]
 [ 1.  0.]]
In [116]:
np.dot(j, j)
Out[116]:
matrix([[-1.,  0.],
        [ 0., -1.]])

Statistiques

  • en plus des fonctions mean() var() et std() il existe aussi:

* median()

In [117]:
a = np.array([1, 4, 3, 8, 9, 2, 3])
np.median(a)
Out[117]:
3.0
  • corrcoef() coéfficient de corrélation
In [118]:
a = np.array([[1, 2, 1, 3], [5, 3, 1, 8]]) 
np.corrcoef(a)
Out[118]:
array([[ 1.        ,  0.72870505],
       [ 0.72870505,  1.        ]])
  • cov() covarince
In [119]:
np.cov(a)
Out[119]:
array([[ 0.91666667,  2.08333333],
       [ 2.08333333,  8.91666667]])

Opération spécifiques aux matrices

In [120]:
a = np.array([[1,2],[3,4]]) 
M = np.matrix(a)
  • résultat 1d:
In [121]:
a[0]
Out[121]:
array([1, 2])
  • résultat 2d:
In [122]:
M[0]
Out[122]:
matrix([[1, 2]])
  • $\large a \cdot a$ (élément x élément)
In [123]:
a * a
Out[123]:
array([[ 1,  4],
       [ 9, 16]])
  • multiplication algebrique de matrices
In [124]:
M * M
Out[124]:
matrix([[ 7, 10],
        [15, 22]])
  • element-wise power
In [125]:
a**3
Out[125]:
array([[ 1,  8],
       [27, 64]], dtype=int32)
  • multiplication de matrices $\large M \cdot M \cdot M$
In [126]:
M**3
Out[126]:
matrix([[ 37,  54],
        [ 81, 118]])
  • transposition $M^T$:
In [127]:
M.T
Out[127]:
matrix([[1, 3],
        [2, 4]])
  • transposition conjuguée (!= de .T pour des matrices complexes)
In [128]:
M.H
Out[128]:
matrix([[1, 3],
        [2, 4]])
  • inversion $M^{-1}$:
In [129]:
M.I
Out[129]:
matrix([[-2. ,  1. ],
        [ 1.5, -0.5]])

Opérations entre arrays

In [130]:
a = np.array([1,2,3])
b = np.array([5,2,6])
a + b
Out[130]:
array([6, 4, 9])
In [131]:
a - b 
Out[131]:
array([-4,  0, -3])
In [132]:
a * b
Out[132]:
array([ 5,  4, 18])
In [133]:
b / a
Out[133]:
array([ 5.,  1.,  2.])
In [134]:
a % b
Out[134]:
array([1, 0, 3], dtype=int32)
In [135]:
b**a
Out[135]:
array([  5,   4, 216], dtype=int32)
In [136]:
a = np.array([[1, 2], [3, 4], [5, 6]], float)
b = np.array([-1, 3], float)

a
Out[136]:
array([[ 1.,  2.],
       [ 3.,  4.],
       [ 5.,  6.]])
In [137]:
b
Out[137]:
array([-1.,  3.])
In [138]:
a + b
Out[138]:
array([[ 0.,  5.],
       [ 2.,  7.],
       [ 4.,  9.]])
In [139]:
a * a
Out[139]:
array([[  1.,   4.],
       [  9.,  16.],
       [ 25.,  36.]])
In [140]:
b * b
Out[140]:
array([ 1.,  9.])
In [141]:
a * b
Out[141]:
array([[ -1.,   6.],
       [ -3.,  12.],
       [ -5.,  18.]])

List comprehension

In [142]:
A = np.array([[n+m*10 for n in range(5)] for m in range(5)])
A
Out[142]:
array([[ 0,  1,  2,  3,  4],
       [10, 11, 12, 13, 14],
       [20, 21, 22, 23, 24],
       [30, 31, 32, 33, 34],
       [40, 41, 42, 43, 44]])
In [143]:
v = np.arange(0,5)
v
Out[143]:
array([0, 1, 2, 3, 4])
In [144]:
np.dot(A,A)
Out[144]:
array([[ 300,  310,  320,  330,  340],
       [1300, 1360, 1420, 1480, 1540],
       [2300, 2410, 2520, 2630, 2740],
       [3300, 3460, 3620, 3780, 3940],
       [4300, 4510, 4720, 4930, 5140]])
In [145]:
np.dot(A,v)
Out[145]:
array([ 30, 130, 230, 330, 430])
In [146]:
np.dot(v,v)
Out[146]:
30

Cast

  • nous pouvons cast un array en matrice ce qui a donc pour effet de changer le comportement des opérateurs $+,-,\cdot$
In [147]:
M = np.matrix(A)
v2 = np.matrix(v).T
v2
Out[147]:
matrix([[0],
        [1],
        [2],
        [3],
        [4]])
In [148]:
M*v2
Out[148]:
matrix([[ 30],
        [130],
        [230],
        [330],
        [430]])
  • produit interne
In [149]:
v2.T * v2
Out[149]:
matrix([[30]])
  • algèbre linéaire standard
In [150]:
v2 + M*v2
Out[150]:
matrix([[ 30],
        [131],
        [232],
        [333],
        [434]])

Exercices

04numpy_exercices

EXERCICES

Numpy Vectors and Matrices

In [2]:
import numpy as np

a = np.array([1,3,5,7,9]) 
b = np.array([3,5,6,7,9])
c = np.linspace(0, 1, 100)
A = np.array([[1, 2, 3], [3, 6, 7], [2, 5, 6]] ) 
B = np.zeros((5,6))
C = np.ones((4,6))
D = np.random.rand(3,4)

1. Print the shape, size and the type.

In [3]:
l = [a,b,c,A,B,C,D]

for i in l:
    print("\nshape: {}\nsize: {}\ndtype: {}\ntype: {}\narray:\n{}\n\n"
        .format(i.shape, i.size, i.dtype, type(i), i))
shape: (5,)
size: 5
dtype: int32
type: <class 'numpy.ndarray'>
array:
[1 3 5 7 9]



shape: (5,)
size: 5
dtype: int32
type: <class 'numpy.ndarray'>
array:
[3 5 6 7 9]



shape: (100,)
size: 100
dtype: float64
type: <class 'numpy.ndarray'>
array:
[ 0.          0.01010101  0.02020202  0.03030303  0.04040404  0.05050505
  0.06060606  0.07070707  0.08080808  0.09090909  0.1010101   0.11111111
  0.12121212  0.13131313  0.14141414  0.15151515  0.16161616  0.17171717
  0.18181818  0.19191919  0.2020202   0.21212121  0.22222222  0.23232323
  0.24242424  0.25252525  0.26262626  0.27272727  0.28282828  0.29292929
  0.3030303   0.31313131  0.32323232  0.33333333  0.34343434  0.35353535
  0.36363636  0.37373737  0.38383838  0.39393939  0.4040404   0.41414141
  0.42424242  0.43434343  0.44444444  0.45454545  0.46464646  0.47474747
  0.48484848  0.49494949  0.50505051  0.51515152  0.52525253  0.53535354
  0.54545455  0.55555556  0.56565657  0.57575758  0.58585859  0.5959596
  0.60606061  0.61616162  0.62626263  0.63636364  0.64646465  0.65656566
  0.66666667  0.67676768  0.68686869  0.6969697   0.70707071  0.71717172
  0.72727273  0.73737374  0.74747475  0.75757576  0.76767677  0.77777778
  0.78787879  0.7979798   0.80808081  0.81818182  0.82828283  0.83838384
  0.84848485  0.85858586  0.86868687  0.87878788  0.88888889  0.8989899
  0.90909091  0.91919192  0.92929293  0.93939394  0.94949495  0.95959596
  0.96969697  0.97979798  0.98989899  1.        ]



shape: (3, 3)
size: 9
dtype: int32
type: <class 'numpy.ndarray'>
array:
[[1 2 3]
 [3 6 7]
 [2 5 6]]



shape: (5, 6)
size: 30
dtype: float64
type: <class 'numpy.ndarray'>
array:
[[ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.]]



shape: (4, 6)
size: 24
dtype: float64
type: <class 'numpy.ndarray'>
array:
[[ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.]]



shape: (3, 4)
size: 12
dtype: float64
type: <class 'numpy.ndarray'>
array:
[[ 0.72993166  0.55632606  0.36446552  0.43072544]
 [ 0.48947311  0.09726672  0.76748068  0.01503544]
 [ 0.01426817  0.83050577  0.63646995  0.5173419 ]]


2. Transpose and invert the matrix A. What happens if in A you replace 7 by 9? Why?

In [4]:
print(A)
[[1 2 3]
 [3 6 7]
 [2 5 6]]
In [5]:
print((np.matrix(A).T).I)
[[ 0.5 -2.   1.5]
 [ 1.5  0.  -0.5]
 [-2.   1.  -0. ]]
In [6]:
A[1,2] = 9

print(A)
[[1 2 3]
 [3 6 9]
 [2 5 6]]

That happens and I don't know why

In [7]:
print((np.matrix(A).T).I)
---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
<ipython-input-7-acb438281b8a> in <module>()
----> 1 print((np.matrix(A).T).I)

c:\python3\lib\site-packages\numpy\matrixlib\defmatrix.py in getI(self)
    970         else:
    971             from numpy.dual import pinv as func
--> 972         return asmatrix(func(self))
    973 
    974     def getA(self):

c:\python3\lib\site-packages\numpy\linalg\linalg.py in inv(a)
    524     signature = 'D->D' if isComplexType(t) else 'd->d'
    525     extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
--> 526     ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
    527     return wrap(ainv.astype(result_t, copy=False))
    528 

c:\python3\lib\site-packages\numpy\linalg\linalg.py in _raise_linalgerror_singular(err, flag)
     88 
     89 def _raise_linalgerror_singular(err, flag):
---> 90     raise LinAlgError("Singular matrix")
     91 
     92 def _raise_linalgerror_nonposdef(err, flag):

LinAlgError: Singular matrix

3.

a. Make a dot product between A and D.

In [ ]:
print(np.dot(A, D))

b. Make a dot product between D and A.

In [ ]:
print(np.dot(D, A))

c. Make a dot product between the transpose of D and A.

In [ ]:
print(np.dot(D.T, A))

d. Make a dot product between D and C.

In [ ]:
print(np.dot(D, C))

Save and Load

a. Create a 1000 x 2000 random matrix with numbers from 0 to 1 and save it to a file called data.npy

In [16]:
m = np.random.random((1000, 2000))

print(m)
[[ 0.53593887  0.23864237  0.77004657 ...,  0.19734728  0.08791087
   0.320572  ]
 [ 0.24710999  0.98022189  0.91651642 ...,  0.91219853  0.8218685
   0.96209007]
 [ 0.77666955  0.27479376  0.76670483 ...,  0.76103011  0.16091954
   0.65381922]
 ..., 
 [ 0.88779387  0.04411058  0.49711053 ...,  0.32593406  0.62821396
   0.43341517]
 [ 0.44068849  0.15851668  0.05946043 ...,  0.18426719  0.53539616
   0.32829195]
 [ 0.22738633  0.02368653  0.69179358 ...,  0.50876636  0.91235435
   0.19747973]]
In [17]:
np.save('C:/Users/sol.rosca/Jupyter_notbooks/data.npy',m)

b. Load the matrix from the file and compare it to the original file.

In [20]:
# n = np.empty((1000,2000))
n = np.load('C:/Users/sol.rosca/Jupyter_notbooks/data.npy')

print(n)
[[ 0.53593887  0.23864237  0.77004657 ...,  0.19734728  0.08791087
   0.320572  ]
 [ 0.24710999  0.98022189  0.91651642 ...,  0.91219853  0.8218685
   0.96209007]
 [ 0.77666955  0.27479376  0.76670483 ...,  0.76103011  0.16091954
   0.65381922]
 ..., 
 [ 0.88779387  0.04411058  0.49711053 ...,  0.32593406  0.62821396
   0.43341517]
 [ 0.44068849  0.15851668  0.05946043 ...,  0.18426719  0.53539616
   0.32829195]
 [ 0.22738633  0.02368653  0.69179358 ...,  0.50876636  0.91235435
   0.19747973]]
In [21]:
print((n==m).all())
True

Reshape

a. Create an array of all numbers from 101 to 270 and reshape it into a matrix of 17 rows and 10 columns.

In [22]:
a = np.arange(101,271)
print(a)
[101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
 263 264 265 266 267 268 269 270]
In [23]:
a = a.reshape(17,10)
print(a)
[[101 102 103 104 105 106 107 108 109 110]
 [111 112 113 114 115 116 117 118 119 120]
 [121 122 123 124 125 126 127 128 129 130]
 [131 132 133 134 135 136 137 138 139 140]
 [141 142 143 144 145 146 147 148 149 150]
 [151 152 153 154 155 156 157 158 159 160]
 [161 162 163 164 165 166 167 168 169 170]
 [171 172 173 174 175 176 177 178 179 180]
 [181 182 183 184 185 186 187 188 189 190]
 [191 192 193 194 195 196 197 198 199 200]
 [201 202 203 204 205 206 207 208 209 210]
 [211 212 213 214 215 216 217 218 219 220]
 [221 222 223 224 225 226 227 228 229 230]
 [231 232 233 234 235 236 237 238 239 240]
 [241 242 243 244 245 246 247 248 249 250]
 [251 252 253 254 255 256 257 258 259 260]
 [261 262 263 264 265 266 267 268 269 270]]

b. Calculate the sum, the mean, the max and the min element in the 9th row.

In [24]:
print(a[8])
print(np.sum(a[8]))
print(np.mean(a[8]))
print(np.max(a[8]))
print(np.min(a[8]))
[181 182 183 184 185 186 187 188 189 190]
1855
185.5
190
181

c. Print all the elements that are divisible by 11.

In [25]:
print(a[np.where(a % 11 == 0)])
# equivalents
print(a[np.nonzero(a % 11 == 0)])
[110 121 132 143 154 165 176 187 198 209 220 231 242 253 264]
[110 121 132 143 154 165 176 187 198 209 220 231 242 253 264]
In [26]:
for i in a[np.nonzero(a % 11 == 0)]: print(i, end=' ')
110 121 132 143 154 165 176 187 198 209 220 231 242 253 264 

d. print their sum.

In [27]:
print(np.sum(a[np.nonzero(a % 11 == 0)]))
2805

Sort

a. Create the array a=[2.3 1.2 5.4 1.7 7 0.4 5.1 6.3] and sort the elements

In [28]:
a = np.array([2.3, 1.2, 5.4, 1.7, 7, 0.4, 5.1, 6.3])
b = np.sort(a)
print(b)
[ 0.4  1.2  1.7  2.3  5.1  5.4  6.3  7. ]

b. Sort the arguments and show the array b = [5 7 2 3 4 1 9 8] in the same order of the arguments.

In [29]:
c = np.array([5, 7, 2, 3, 4, 1, 9, 8])
s = a.argsort()
print(c[s])
[1 7 3 5 9 2 8 4]

Matrices

a. Create the matrix M=[2,3;4 1] using mat() calculate:

  • $ M \cdot M $
In [30]:
M = np.mat('2 3; 4 1')

print(M*M)
[[16  9]
 [12 13]]
  • $ M^5 $
In [31]:
print(M**5)
[[1772 1353]
 [1804 1321]]
  • $ M^T $
In [32]:
print(M.T)
[[2 4]
 [3 1]]
  • $ M^{-1} $
In [33]:
print(M.I)
[[-0.1  0.3]
 [ 0.4 -0.2]]

b. What happens if instead of mat() you use array?

You can't invert an array $ (a^{-1})$

  • $ a \cdot a $
In [34]:
a = np.array([[2,3], [4,1]])
print(a*a)
[[ 4  9]
 [16  1]]
  • $ a^5 $
In [35]:
print(a**5)
[[  32  243]
 [1024    1]]
  • $ a^T $
In [36]:
print(a.T)
[[2 4]
 [3 1]]

Matplot

Figures

Plot in green the function y = x ** 4 for x between -2 and 2 using 100 points. Label the figure properly.

In [37]:
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
%matplotlib inline
In [38]:
x = np.linspace(-2, 2, 100)
y = x**4
In [39]:
fig, ax = plt.subplots(figsize=(12,6), dpi=180)
matplotlib.rcParams.update({'font.size': 8, 'font.family': 'serif'})
ax.grid(True)


ax.plot(x, x**4, 'g', label=r"$ y = x^4 $", linewidth=2)
ax.legend(loc=2, fontsize=14);  # upper left corner
ax.set_xlabel(r'$x$', fontsize=18)
ax.set_ylabel(r'$y$', fontsize=18)
ax.set_title('$y = f(x^4)$', fontsize=18);

Subplots

Plot in the same figure two subplots one above each other:

  • The absolute value
  • The angle Of the following function:

Y = 1/(1+j*w)
If w takes values between -10 and 10 in 500 steps.

  • Label the plots.
In [40]:
x = np.arange(-10, 10, 20/500)
y = 1/(1+x)
In [41]:
fig, axes = plt.subplots(2, 1, figsize=(12,6), dpi=180)

matplotlib.rcParams.update({'font.size': 8, 'font.family': 'serif'})

axes[0].plot(y, abs(x), 'r', label="lab 1")
axes[1].plot(x,y, 'b', label="lab 2")

axes[0].set_title('title');
axes[1].set_title('title');

axes[0].legend(loc=2);  # upper left corner
axes[1].legend(loc=3);  # upper left corner

Multiple plots

Plot the functions sin(t) and cos(t) at the same plot and put a legend.

In [42]:
fig, axes = plt.subplots(figsize=(12,6), dpi=180)
matplotlib.rcParams.update({'font.size': 12, 'font.family': 'serif'})

t = np.linspace(-np.pi, np.pi, 256, endpoint=True)
C,S = np.cos(t), np.sin(t)


plt.xlim(t.min()*1.1, t.max()*1.1)
plt.ylim(C.min()*1.1, C.max()*1.1)

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
       [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

plt.yticks([-1, 0, +1],
       [r'$-1$', r'$0$', r'$+1$'])


plt.plot(t, C, color="blue", linewidth=2.5, linestyle="-", label="cosine")
plt.plot(t, S, color="red",  linewidth=2.5, linestyle="-", label="sine")



plt.legend(loc='upper left', frameon=False)




plt.show()