Comment parcourir les lignes d'un DataFrame dans Pandas?
Réponse: NE PAS * !
L'itération chez les pandas est un anti-modèle, et c'est quelque chose que vous ne devriez faire que lorsque vous avez épuisé toutes les autres options. Vous ne devez utiliser aucune fonction avec " iter
" dans son nom pendant plus de quelques milliers de lignes ou vous devrez vous habituer à beaucoup d'attente.
Voulez-vous imprimer un DataFrame? UtilisationDataFrame.to_string()
.
Voulez-vous calculer quelque chose? Dans ce cas, recherchez les méthodes dans cet ordre (liste modifiée à partir d' ici ):
- Vectorisation
- Routines Cython
- Liste des compréhensions (
for
boucle vanille )
DataFrame.apply()
: i) Réductions pouvant être effectuées dans le cython, ii) Itération dans l'espace python
DataFrame.itertuples()
et iteritems()
DataFrame.iterrows()
iterrows
et itertuples
(tous deux recevant de nombreux votes dans les réponses à cette question) devraient être utilisés dans de très rares circonstances, telles que la génération d'objets de ligne / nametuples pour le traitement séquentiel, ce qui est vraiment la seule raison pour laquelle ces fonctions sont utiles.
Appel à l'autorité
La page de documentation sur l'itération a une énorme boîte d'avertissement rouge qui dit:
L'itération à travers des objets pandas est généralement lente. Dans de nombreux cas, l'itération manuelle sur les lignes n'est pas nécessaire [...].
* C'est en fait un peu plus compliqué que "pas". df.iterrows()
est la bonne réponse à cette question, mais "vectoriser vos opérations" est la meilleure. Je concède qu'il y a des circonstances où l'itération ne peut pas être évitée (par exemple, certaines opérations où le résultat dépend de la valeur calculée pour la ligne précédente). Cependant, il faut une certaine familiarité avec la bibliothèque pour savoir quand. Si vous n'êtes pas sûr d'avoir besoin d'une solution itérative, vous n'en avez probablement pas. PS: Pour en savoir plus sur ma justification de la rédaction de cette réponse, passez au bas de la page.
Un bon nombre d'opérations et de calculs de base sont "vectorisés" par des pandas (soit via NumPy, soit via des fonctions Cythonisées). Cela comprend l'arithmétique, les comparaisons, (la plupart) des réductions, le remodelage (comme le pivotement), les jointures et les opérations groupées. Consultez la documentation sur les fonctionnalités de base essentielles pour trouver une méthode vectorisée adaptée à votre problème.
S'il n'en existe pas, n'hésitez pas à écrire le vôtre en utilisant des extensions cython personnalisées .
La compréhension des listes devrait être votre prochain port d'escale si 1) il n'y a pas de solution vectorisée disponible, 2) les performances sont importantes, mais pas assez importantes pour passer par les tracas de la cythonisation de votre code, et 3) vous essayez d'effectuer une transformation élémentaire sur votre code. De nombreuses preuves suggèrent que la compréhension des listes est suffisamment rapide (et même parfois plus rapide) pour de nombreuses tâches courantes de pandas.
La formule est simple,
# iterating over one column - `f` is some function that processes your data
result = [f(x) for x in df['col']]
# iterating over two columns, use `zip`
result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]
# iterating over multiple columns - same data type
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]
# iterating over multiple columns - differing data type
result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]
Si vous pouvez encapsuler votre logique métier dans une fonction, vous pouvez utiliser une compréhension de liste qui l'appelle. Vous pouvez faire fonctionner des choses arbitrairement complexes grâce à la simplicité et la vitesse du python brut.
Les compréhensions de la
liste des mises en garde supposent que vos données sont faciles à utiliser - ce qui signifie que vos types de données sont cohérents et que vous n'avez pas de NaN, mais cela ne peut pas toujours être garanti.
- La première est plus évidente, mais lorsque vous traitez avec des NaN, préférez les méthodes pandas intégrées si elles existent (car elles ont une meilleure logique de gestion des cas d'angle), ou assurez-vous que votre logique métier inclut une logique de gestion NaN appropriée.
- Lorsque vous traitez avec des types de données mixtes, vous devez itérer au
zip(df['A'], df['B'], ...)
lieu de, df[['A', 'B']].to_numpy()
car ce dernier met implicitement à jour les données vers le type le plus courant. Par exemple, si A est numérique et B est une chaîne, to_numpy()
transtypera le tableau entier en chaîne, ce qui peut ne pas être ce que vous voulez. Heureusement, zip
cingler vos colonnes ensemble est la solution la plus simple à cela.
* YMMV pour les raisons décrites dans la section Mises en garde ci-dessus.
Un exemple évident
Montrons la différence avec un exemple simple d'ajout de deux colonnes pandas A + B
. Il s'agit d'une opération vectorisable, il sera donc facile de comparer les performances des méthodes décrites ci-dessus.
Code de référence, pour votre référence.
Je dois cependant mentionner que ce n'est pas toujours aussi sec et sec. Parfois, la réponse à "quelle est la meilleure méthode pour une opération" est "cela dépend de vos données". Mon conseil est de tester différentes approches sur vos données avant d'en choisir une.
Lectures complémentaires
* Les méthodes de chaîne Pandas sont "vectorisées" dans le sens où elles sont spécifiées sur la série mais fonctionnent sur chaque élément. Les mécanismes sous-jacents sont toujours itératifs, car les opérations de chaîne sont intrinsèquement difficiles à vectoriser.
Pourquoi j'ai écrit cette réponse
Une tendance courante que je remarque de nouveaux utilisateurs est de poser des questions du formulaire "comment puis-je répéter sur mon df pour faire X?". Affichage du code qui appelle iterrows()
tout en faisant quelque chose dans une boucle for. Voici pourquoi. Un nouvel utilisateur de la bibliothèque qui n'a pas été initié au concept de vectorisation envisagera probablement le code qui résout son problème comme itérant sur ses données pour faire quelque chose. Ne sachant pas comment itérer sur un DataFrame, la première chose qu'ils font, c'est Google et finir ici, à cette question. Ils voient ensuite la réponse acceptée leur dire comment faire, et ils ferment les yeux et exécutent ce code sans jamais se demander si l'itération n'est pas la bonne chose à faire.
Le but de cette réponse est d'aider les nouveaux utilisateurs à comprendre que l'itération n'est pas nécessairement la solution à chaque problème, et que des solutions meilleures, plus rapides et plus idiomatiques pourraient exister, et qu'il vaut la peine d'investir du temps pour les explorer. Je n'essaie pas de lancer une guerre d'itération contre la vectorisation, mais je veux que les nouveaux utilisateurs soient informés lors du développement de solutions à leurs problèmes avec cette bibliothèque.