Pourquoi des tableaux, et ce qu'est un tableau
Une liste Python peut tout contenir, ce qui la rend souple mais lente pour les nombres : chaque élément est un objet distinct. NumPy ajoute le ndarray, un bloc de mémoire contenant des nombres d'un seul type, rangés les uns après les autres. Opérer sur tout le bloc en code compilé est en général des dizaines de fois plus rapide qu'une boucle Python, et utilise bien moins de mémoire. Presque toute bibliothèque quantitative (pandas, SciPy, scikit-learn) est construite dessus. Par convention on l'importe avec import numpy as np.
import numpy as np
# Create arrays
prices = np.array([184.25, 185.0, 183.2])
print(prices) # [184.25 185. 183.2 ]
print(np.zeros(3)) # [0. 0. 0.]
print(np.arange(0, 10, 3)) # [0 3 6 9]
print(np.linspace(0, 1, 5)) # [0. 0.25 0.5 0.75 1. ]
# An array knows its shape
table = np.array([[1, 2, 3], [4, 5, 6]])
print(table.shape, table.ndim, table.size) # (2, 3) 2 6Créer des tableaux
np.array(liste) convertit une liste (ou une liste de listes pour deux dimensions). np.zeros(n) et np.ones(n) créent des tableaux remplis, et np.zeros((lignes, colonnes)) prend un tuple de forme. np.arange(début, fin, pas) fonctionne comme range mais accepte des pas flottants et exclut fin ; à cause des arrondis, préférez np.linspace(début, fin, num), qui donne exactement num points régulièrement espacés et inclut les deux bouts. Chaque tableau a .shape (la taille dans chaque dimension), .ndim (le nombre de dimensions) et .size (le nombre total d'éléments).
import numpy as np
# arange with floats can surprise; linspace gives exactly the points you ask for
print(len(np.arange(0, 1, 0.1))) # 10 (1.0 is excluded)
print(len(np.linspace(0, 1, 11))) # 11 (both ends included)
# Shapes and sizes
grid = np.zeros((3, 4))
print(grid.shape, grid.ndim, grid.size) # (3, 4) 2 12
print(np.ones(2) * 5) # [5. 5.]dtype : un seul type pour tout le tableau
Chaque tableau a un dtype : int64 (entiers), float64 (décimaux), bool, et des variantes plus petites ou plus grandes comme float32 ou int8. NumPy choisit le dtype d'après les données : des entiers donnent int64, une seule décimale transforme tout en float64, et np.nan (not-a-number, le marqueur de valeur manquante) est un flottant, il impose donc float64. Choisissez un dtype vous-même avec dtype=..., ou convertissez avec .astype(...), qui renvoie un nouveau tableau. Un dtype plus petit économise de la mémoire (float32 occupe la moitié de float64), au prix de la précision.
import numpy as np
print(np.array([1, 2, 3]).dtype) # int64
print(np.array([1, 2.5, 3]).dtype) # float64 (one decimal upgrades everything)
print(np.array([True, False]).dtype) # bool
print(np.array([1, 2, np.nan])) # [ 1. 2. nan] (nan is a float)
# astype returns a new array; smaller dtypes use less memory
prices = np.zeros(1000)
print(prices.nbytes) # 8000
print(prices.astype(np.float32).nbytes) # 4000
print(np.array(["1.5", "2"], dtype=float)) # [1.5 2. ] (text converted to numbers)Pièges de conversion : troncature et dépassement
Convertir des décimaux en entiers avec .astype(int) tronque vers zéro, et les flottants ne représentent pas exactement la plupart des décimaux : 19.99 * 100 vaut 1998.9999999999998 et se tronque en 1998, un centime de moins. Pour convertir des prix en centimes entiers, arrondissez d'abord : np.round(prices * 100).astype(np.int64). Les dtypes entiers ont aussi une plage fixe et repartent silencieusement de l'autre côté : un int8 va de -128 à 127, donc 100 * 2 devient -56. Utilisez int64 pour l'argent et les comptages, et rappelez-vous que diviser des entiers avec / donne toujours des flottants tandis que // arrondit vers le bas.
import numpy as np
# Truncation: astype(int) cuts the decimals off
print(np.array([1.9, -1.9]).astype(int)) # [ 1 -1]
print(19.99 * 100, int(19.99 * 100)) # 1998.9999999999998 1998
print(np.round(np.array([19.99]) * 100).astype(np.int64)) # [1999]
# Overflow: an int8 wraps around silently
small = np.array([100, 50], dtype=np.int8)
print(small * 2) # [-56 100]
# / always gives floats, // floors
counts = np.array([1, 2, 3])
print(counts / 2, counts // 2) # [0.5 1. 1.5] [0 1 1].shape et .dtype de chaque tableau concerné : un int64 surprenant là où l'on attendait float64, ou une forme (5, 1) au lieu de (5,), explique la plupart des bogues. Préférez construire les tableaux avec des fonctions NumPy (np.linspace, np.asarray, astype) plutôt qu'avec des boucles Python ; les labs rejettent les boucles précisément pour cette raison.np.array,zeros,ones,arange,linspacecréent des tableaux ;.shape,.ndim,.sizeles décrivent.- Un dtype par tableau :
int64,float64,bool;astypeconvertit en un nouveau tableau. astype(int)tronque (arrondissez d'abord) ; les petits dtypes entiers repartent silencieusement ;nanimpose les flottants.
À suivre : indexation et découpage des tableaux, pour extraire lignes, colonnes, fenêtres et valeurs qui satisfont une condition.
Lab : ce qui est noté
- Disposer des points régulièrement espacés avec
make_grid25 pts - Transformer des valeurs brutes mixtes en flottants avec
to_float_array25 pts - Indiquer forme, taille et dtype avec
describe_array25 pts - Convertir des prix en centimes entiers sans risque avec
to_cents25 pts