Quels sont les avantages de NumPy par rapport aux listes Python régulières?

466

Quels sont les avantages de NumPy par rapport aux listes Python régulières?

J'ai environ 100 séries de marchés financiers et je vais créer un réseau de cubes de 100x100x100 = 1 million de cellules. Je vais régresser (3 variables) chaque x avec chaque y et z, pour remplir le tableau avec des erreurs standard.

J'ai entendu dire que pour les "grandes matrices", je devrais utiliser NumPy par opposition aux listes Python, pour des raisons de performances et d'évolutivité. Le fait est que je connais les listes Python et elles semblent fonctionner pour moi.

Quels seront les avantages si je passe à NumPy?

Et si j'avais 1000 séries (c'est-à-dire 1 milliard de cellules à virgule flottante dans le cube)?

Thomas Browne
la source

Réponses:

727

Les tableaux de NumPy sont plus compacts que les listes Python - une liste de listes que vous décrivez, en Python, prendrait au moins 20 Mo, tandis qu'un tableau NumPy 3D avec des flotteurs simple précision dans les cellules pourrait tenir dans 4 Mo. L'accès à la lecture et à l'écriture d'éléments est également plus rapide avec NumPy.

Peut-être que vous ne vous souciez pas tant que ça d'un million de cellules, mais vous le feriez certainement pour un milliard de cellules - aucune des deux approches ne s'intégrerait dans une architecture 32 bits, mais avec des versions 64 bits, NumPy s'en tirerait avec 4 Go environ. , Python seul aurait besoin d'au moins environ 12 Go (beaucoup de pointeurs qui doublent de taille) - un matériel beaucoup plus coûteux!

La différence est principalement due à l '"indirectité" - une liste Python est un tableau de pointeurs vers des objets Python, au moins 4 octets par pointeur plus 16 octets même pour le plus petit objet Python (4 pour le type pointeur, 4 pour le nombre de références, 4 pour la valeur - et les allocateurs de mémoire arrondissent à 16). Un tableau NumPy est un tableau de valeurs uniformes - les nombres à simple précision prennent chacun 4 octets, ceux à double précision, 8 octets. Moins flexible, mais vous payez considérablement pour la flexibilité des listes Python standard!

Alex Martelli
la source
J'ai essayé d'utiliser "sys.getsizeof ()" pour comparer la taille des listes Python et des tableaux NumPy avec le même nombre d'éléments et cela ne semble pas indiquer que les tableaux NumPy étaient beaucoup plus petits. Est-ce le cas ou sys.getsizeof () a-t-il des problèmes pour déterminer la taille d'un tableau NumPy?
Jack Simpson
3
@JackSimpson getsizeofn'est pas fiable. La documentation indique clairement que: Seule la consommation de mémoire directement attribuée à l'objet est prise en compte, pas la consommation de mémoire des objets auxquels il se réfère. Cela signifie que si vous avez des listes python imbriquées, la taille des éléments n'est pas prise en compte.
Bakuriu
4
getsizeofsur une liste ne vous indique que la quantité de RAM que l'objet liste lui-même consomme et la RAM consommée par les pointeurs de son tableau de données, il ne vous indique pas la quantité de RAM consommée par les objets auxquels ces pointeurs se réfèrent.
PM 2Ring
@AlexMartelli, pourriez-vous s'il vous plaît me faire savoir où obtenez-vous ces chiffres?
lmiguelvargasf
Attention, votre estimation de la taille de la liste Python équivalente de liste de listes est erronée. Le tableau numpy de 4 Go de C float(4 octets) se traduirait par quelque chose de plus proche de 32 Go de lists et de Python float(qui sont en fait des C double), pas de 12 Go; chacun floatsur 64 bits Python occupe ~ 24 octets (en supposant qu'aucune perte d'alignement dans l'allocateur), plus 8 autres octets dans listpour contenir la référence (et qui ignore la surallocation et les en-têtes d'objet pour les lists eux-mêmes, ce qui pourrait ajouter un autre Go en fonction de exactement combien de surutilisation se produit).
ShadowRanger
232

NumPy n'est pas seulement plus efficace; c'est aussi plus pratique. Vous obtenez gratuitement de nombreuses opérations vectorielles et matricielles, ce qui permet parfois d'éviter un travail inutile. Et ils sont également mis en œuvre efficacement.

Par exemple, vous pouvez lire votre cube directement depuis un fichier dans un tableau:

x = numpy.fromfile(file=open("data"), dtype=float).reshape((100, 100, 100))

Somme le long de la deuxième dimension:

s = x.sum(axis=1)

Trouvez les cellules au-dessus d'un seuil:

(x > 0.5).nonzero()

Supprimez chaque tranche d'indexation paire le long de la troisième dimension:

x[:, :, ::2]

En outre, de nombreuses bibliothèques utiles fonctionnent avec les tableaux NumPy. Par exemple, des bibliothèques d'analyse statistique et de visualisation.

Même si vous n'avez pas de problèmes de performances, l'apprentissage de NumPy en vaut la chandelle.

Roberto Bonvallet
la source
Merci - vous avez fourni une autre bonne raison dans votre troisième exemple, car en effet, je vais chercher dans la matrice des cellules au-dessus du seuil. De plus, je chargeais depuis sqlLite. L'approche fichier sera beaucoup plus efficace.
Thomas Browne
112

Alex a mentionné l'efficacité de la mémoire et Roberto mentionne la commodité, et ce sont deux bons points. Pour quelques autres idées, je mentionnerai la vitesse et la fonctionnalité .

Fonctionnalité: Vous avez beaucoup intégré avec NumPy, FFT, convolutions, recherche rapide, statistiques de base, algèbre linéaire, histogrammes, etc. Et vraiment, qui peut vivre sans FFT?

Vitesse: voici un test pour faire une somme sur une liste et un tableau NumPy, montrant que la somme sur le tableau NumPy est 10 fois plus rapide (dans ce test - le kilométrage peut varier).

from numpy import arange
from timeit import Timer

Nelements = 10000
Ntimeits = 10000

x = arange(Nelements)
y = range(Nelements)

t_numpy = Timer("x.sum()", "from __main__ import x")
t_list = Timer("sum(y)", "from __main__ import y")
print("numpy: %.3e" % (t_numpy.timeit(Ntimeits)/Ntimeits,))
print("list:  %.3e" % (t_list.timeit(Ntimeits)/Ntimeits,))

qui sur mes systèmes (pendant que j'exécute une sauvegarde) donne:

numpy: 3.004e-05
list:  5.363e-04
tom10
la source
44

Voici une belle réponse de la FAQ sur le site scipy.org :

Quels avantages les tableaux NumPy offrent-ils par rapport aux listes Python (imbriquées)?

Les listes de Python sont des conteneurs polyvalents efficaces. Ils prennent en charge l'insertion, la suppression, l'ajout et la concaténation (assez) efficaces, et les compréhensions de liste de Python les rendent faciles à construire et à manipuler. Cependant, ils ont certaines limitations: ils ne prennent pas en charge les opérations «vectorisées» comme l'addition et la multiplication élément par élément, et le fait qu'ils peuvent contenir des objets de types différents signifient que Python doit stocker les informations de type pour chaque élément, et doit exécuter le code de répartition de type en opérant sur chaque élément. Cela signifie également que très peu d'opérations de liste peuvent être effectuées par des boucles C efficaces - chaque itération nécessiterait des vérifications de type et d'autres méthodes de comptabilité de l'API Python.

Eliezer
la source
9

Tous ont mis en évidence presque toutes les différences majeures entre le tableau numpy et la liste python, je les résumerai ici:

  1. Les tableaux Numpy ont une taille fixe à la création, contrairement aux listes Python (qui peuvent croître dynamiquement). La modification de la taille de ndarray créera un nouveau tableau et supprimera l'original.

  2. Les éléments d'un tableau Numpy doivent tous être du même type de données (nous pouvons également avoir le type hétérogène mais cela ne vous permettra pas d'opérations mathématiques) et auront donc la même taille en mémoire

  3. Les tableaux Numpy facilitent les avancées mathématiques et d'autres types d'opérations sur un grand nombre de données. De telles opérations sont généralement exécutées plus efficacement et avec moins de code que ce qui est possible en utilisant des séquences pythons intégrées

Parvez Khan
la source