Comment parcourir les lignes d'un DataFrame dans Pandas?


1954

J'ai un DataFramedes pandas:

import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df

Production:

   c1   c2
0  10  100
1  11  110
2  12  120

Maintenant, je veux parcourir les lignes de ce cadre. Pour chaque ligne, je veux pouvoir accéder à ses éléments (valeurs dans les cellules) par le nom des colonnes. Par exemple:

for row in df.rows:
   print row['c1'], row['c2']

Est-il possible de faire cela chez les pandas?

J'ai trouvé cette question similaire . Mais cela ne me donne pas la réponse dont j'ai besoin. Par exemple, il est suggéré d'y utiliser:

for date, row in df.T.iteritems():

ou

for row in df.iterrows():

Mais je ne comprends pas ce qu'est l' rowobjet et comment je peux travailler avec lui.


11
Le df.iteritems () parcourt les colonnes et non les lignes. Ainsi, pour le faire itérer sur les lignes, vous devez transposer (le "T"), ce qui signifie que vous changez les lignes et les colonnes les unes dans les autres (réfléchissez sur la diagonale). Par conséquent, vous itérez efficacement la trame de données d'origine sur ses lignes lorsque vous utilisez df.T.iteritems ()
Stefan Gruenwald

12
Si vous êtes nouveau sur ce sujet et que vous êtes un débutant en pandas, NE PAS RÉPÉTER !! L'itération sur les trames de données est un anti-modèle, et quelque chose que vous ne devriez pas faire, sauf si vous voulez vous habituer à beaucoup d'attente. Selon ce que vous essayez de faire, il existe probablement de bien meilleures alternatives . iter*les fonctions doivent être utilisées dans de très rares circonstances. Également lié .
cs95

19
Contrairement à ce que dit cs95, il existe de très bonnes raisons de vouloir parcourir une trame de données, de sorte que les nouveaux utilisateurs ne devraient pas se sentir découragés. Un exemple est si vous souhaitez exécuter du code en utilisant les valeurs de chaque ligne en entrée. De plus, si votre trame de données est raisonnablement petite (par exemple moins de 1000 éléments), les performances ne sont pas vraiment un problème.
oulenz

1
@oulenz: Si, pour une raison étrange, vous voulez vous opposer à l'utilisation de l'API dans le but pour lequel il a été conçu (transformations de données hautes performances), alors soyez mon invité. Mais à tout le moins, ne l'utilisez pas iterrows, il existe de meilleures façons d'itérer sur un DataFrame, vous pourriez tout aussi bien parcourir une liste de listes à ce stade. Si vous êtes au point où vous ne faites rien d'autre que d'itérer sur des DataFrames, il n'y a vraiment aucun avantage à utiliser un DataFrame (en supposant que l'itérer dessus est la seule chose que vous faites avec). Juste mon 2c.
cs95

8
J'appuie @oulenz. Pour autant que je sache, pandasc'est le choix de lire un fichier csv même si l'ensemble de données est petit. Il est tout simplement plus facile de programmer pour manipuler les données avec les API
Chris

Réponses:


2640

DataFrame.iterrows est un générateur qui produit à la fois l'index et la ligne

import pandas as pd
import numpy as np

df = pd.DataFrame([{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}])

for index, row in df.iterrows():
    print(row['c1'], row['c2'])

Output: 
   10 100
   11 110
   12 120

207
Remarque: "Parce que iterrows renvoie une série pour chaque ligne, il ne conserve pas les dtypes sur les lignes." En outre, "Vous ne devez jamais modifier quelque chose sur lequel vous faites une itération." Selon les documents de pandas 0.19.1
viddik13

3
@ viddik13 c'est une bonne note merci. Pour cette raison, je suis tombé sur un cas où les valeurs numériques comme 431341610650où lire comme 4.31E+11. Existe-t-il un moyen de préserver les dtypes?
Aziz Alto du

26
Utilisation @AzizAlto itertuples, comme expliqué ci-dessous. Voir aussi pandas.pydata.org/pandas-docs/stable/generated/…
Axel

101
Ne l'utilisez pas. Itertuples est plus rapide et préserve le type de données. Plus d'infos
James L.

11
D'après la documentation : "L'itération à travers les objets pandas est généralement lente. Dans de nombreux cas, l'itération manuelle sur les lignes n'est pas nécessaire [...]". Votre réponse est correcte (dans le contexte de la question) mais ne la mentionne nulle part, elle n'est donc pas très bonne.
cs95

464

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 ):

  1. Vectorisation
  2. Routines Cython
  3. Liste des compréhensions ( forboucle vanille )
  4. DataFrame.apply(): i) Réductions pouvant être effectuées dans le cython, ii) Itération dans l'espace python
  5. DataFrame.itertuples() et iteritems()
  6. 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.


Plus rapide que la boucle: vectorisation , Cython

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 .


Next Best Thing: List Comprehensions *

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.

  1. 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.
  2. 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, zipcingler 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.

entrez la description de l'image ici

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.


24
C'est la seule réponse qui se concentre sur les techniques idiomatiques à utiliser avec les pandas, ce qui en fait la meilleure réponse à cette question. Apprendre à obtenir la bonne réponse avec le bon code (au lieu de la bonne réponse avec le mauvais code - c'est-à-dire inefficace, ne s'adapte pas, trop adapté à des données spécifiques) est une grande partie de l'apprentissage des pandas (et des données en général).
LinkBerest

3
Je pense que vous êtes injuste envers la boucle for, car ils ne sont que légèrement plus lents que la compréhension de la liste dans mes tests. L'astuce consiste à boucler au zip(df['A'], df['B'])lieu de df.iterrows().
Imperishable Night

2
@ImperishableNight Pas du tout; le but de cet article n'est pas de dénoncer l'itération en général - c'est de dénoncer spécifiquement l'utilisation de iterrows(), et de dénoncer implicitement l'itération si et quand de meilleures alternatives existent. forles boucles en elles-mêmes sont OK, mais les compréhensions de liste sont meilleures si vous effectuez de manière itérative des transformations élément par élément.
cs95

1
@sdbbs existe, utilisez sort_values ​​pour trier vos données, puis appelez to_string () sur le résultat.
cs95

1
Sous List Comprehensions, l'exemple "itération sur plusieurs colonnes" nécessite une mise en garde: DataFrame.valuesconvertira chaque colonne en un type de données commun. DataFrame.to_numpy()fait cela aussi. Heureusement, nous pouvons utiliser zipavec n'importe quel nombre de colonnes.
David Wasserman

397

Vérifiez d' abord si vous avez vraiment besoin d' itérer sur les lignes d'un DataFrame. Voir cette réponse pour des alternatives.

Si vous devez toujours parcourir les lignes, vous pouvez utiliser les méthodes ci-dessous. Notez quelques mises en garde importantes qui ne sont mentionnées dans aucune des autres réponses.

itertuples() est censé être plus rapide que iterrows()

Mais attention, selon la documentation (pandas 0.24.2 en ce moment):

  • iterrows: dtypepeut ne pas correspondre d'une ligne à l'autre

    Étant donné que iterrows renvoie une série pour chaque ligne, il ne conserve pas les dtypes entre les lignes (les dtypes sont conservés entre les colonnes pour DataFrames). Pour conserver les dtypes tout en itérant sur les lignes, il est préférable d'utiliser itertuples () qui retourne des couples nommés des valeurs et qui est généralement beaucoup plus rapide que iterrows ()

  • iterrows: ne modifiez pas les lignes

    Vous ne devez jamais modifier quelque chose sur lequel vous faites une itération. Ce n'est pas garanti de fonctionner dans tous les cas. Selon les types de données, l'itérateur renvoie une copie et non une vue, et y écrire n'aura aucun effet.

    Utilisez plutôt DataFrame.apply () :

    new_df = df.apply(lambda x: x * 2)
  • itertuples:

    Les noms de colonne seront renommés en noms de position s'ils sont des identifiants Python non valides, répétés ou commencent par un trait de soulignement. Avec un grand nombre de colonnes (> 255), les tuples réguliers sont retournés.

Voir les documents de pandas sur l'itération pour plus de détails.


4
Juste une petite question de quelqu'un qui lit ce fil si longtemps après son achèvement: comment df.apply () se compare-t-il aux itertuples en termes d'efficacité?
Raul Guarini

4
Remarque: vous pouvez également dire quelque chose comme for row in df[['c1','c2']].itertuples(index=True, name=None):inclure uniquement certaines colonnes dans l'itérateur de ligne.
Brian Burns

12
Au lieu de getattr(row, "c1"), vous pouvez utiliser juste row.c1.
viraptor

1
Je suis sûr à environ 90% que si vous utilisez à la getattr(row, "c1")place de row.c1, vous perdez tout avantage de performance itertupleset si vous avez réellement besoin d'accéder à la propriété via une chaîne, vous devez utiliser iterrows à la place.
Noctiphobia

3
J'ai trébuché sur cette question parce que, même si je savais qu'il y avait split-apply-combine, j'avais toujours vraiment besoin d'itérer sur un DataFrame (comme l'indique la question). Tout le monde n'a pas le luxe de s'améliorer avec numbaet cython(les mêmes documents disent que "ça vaut toujours la peine d'être optimisé en Python d'abord"). J'ai écrit cette réponse pour aider les autres à éviter les problèmes (parfois frustrants) car aucune des autres réponses ne mentionne ces mises en garde. Tromper quelqu'un ou dire "c'est la bonne chose à faire" n'a jamais été mon intention. J'ai amélioré la réponse.
viddik13

201

Vous devez utiliser df.iterrows(). Bien que l'itération ligne par ligne ne soit pas particulièrement efficace car les Seriesobjets doivent être créés.


12
Est-ce plus rapide que de convertir le DataFrame en un tableau numpy (via .values) et d'opérer directement sur le tableau? J'ai le même problème, mais j'ai fini par convertir en un tableau numpy puis en utilisant cython.
vgoklani

12
@vgoklani Si l'itération ligne par ligne est inefficace et que vous avez un tableau numpy non-objet, l'utilisation du tableau numpy brut sera presque sûrement plus rapide, en particulier pour les tableaux avec plusieurs lignes. vous devez éviter d'itérer sur les lignes à moins que vous ne deviez absolument le faire
Phillip Cloud

7
J'ai fait un peu de test sur la consommation de temps pour df.iterrows (), df.itertuples () et zip (df ['a'], df ['b']) et publié le résultat dans la réponse d'un autre question: stackoverflow.com/a/34311080/2142098
Richard Wong

154

Bien que ce iterrows()soit une bonne option, cela itertuples()peut parfois être beaucoup plus rapide:

df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'})

%timeit [row.a * 2 for idx, row in df.iterrows()]
# => 10 loops, best of 3: 50.3 ms per loop

%timeit [row[1] * 2 for row in df.itertuples()]
# => 1000 loops, best of 3: 541 µs per loop

5
Une grande partie de la différence de temps dans vos deux exemples semble être due au fait que vous semblez utiliser l'indexation basée sur les étiquettes pour la commande .iterrows () et l'indexation basée sur des nombres entiers pour la commande .itertuples ().
Alex

2
Pour un dataframe basé sur des données financières (horodatage et 4x float), les itertuples sont 19,57 fois plus rapides que les iterrows sur ma machine. Seul for a,b,c in izip(df["a"],df["b"],df["c"]:est presque aussi rapide.
harbun

7
Pouvez-vous expliquer pourquoi c'est plus rapide?
Abe Miessler

4
@AbeMiessler encadre iterrows()chaque ligne de données dans une série, alors itertuples()que non.
miradulo

3
Notez que l'ordre des colonnes est en fait indéterminé, car il dfest créé à partir d'un dictionnaire, donc row[1]pourrait faire référence à l'une des colonnes. Il s'avère que les temps sont à peu près les mêmes pour l'entier contre les colonnes flottantes.
Brian Burns

88

Vous pouvez également utiliser df.apply()pour parcourir les lignes et accéder à plusieurs colonnes pour une fonction.

documents: DataFrame.apply ()

def valuation_formula(x, y):
    return x * y * 0.5

df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)

Le df [«prix»] fait-il référence à un nom de colonne dans le bloc de données? J'essaie de créer un dictionnaire avec des valeurs uniques à partir de plusieurs colonnes dans un fichier csv. J'ai utilisé votre logique pour créer un dictionnaire avec des clés et des valeurs uniques et j'ai eu une erreur indiquant TypeError: ("Les objets 'Series' sont modifiables, donc ils ne peuvent pas être hachés", u'occurrence à l'index 0 ')
SRS

Code: df ['Workclass'] = df.apply (lambda row: dic_update (row), axis = 1) end of line id = 0 end of line def dic_update (row): if row not in dic: dic [row] = id id = id + 1
SRS

Tant pis, je l'ai. Modification
SRS

2
Avoir l'axe par défaut à 0 est le pire
zthomas.nc

9
Notez que applycela n'itératite pas sur les lignes, mais plutôt qu'il applique une fonction ligne par ligne. Le code ci - dessus ne fonctionnerait pas si vous vraiment faire , par exemple itérations de besoin et indeces lorsque l'on compare les valeurs entre les différentes lignes (dans ce cas , vous ne pouvez rien mais itérer).
gented

82

Vous pouvez utiliser la fonction df.iloc comme suit:

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']

1
Je sais qu'il faut éviter cela en faveur des iterrows ou itertuples, mais il serait intéressant de savoir pourquoi. Des pensées?
rocarvaj

12
C'est la seule technique valide que je connaisse si vous souhaitez conserver les types de données et également faire référence aux colonnes par nom. itertuplespréserve les types de données, mais supprime tout nom qu'il n'aime pas. iterrowsfait le contraire.
Ken Williams

6
Passé des heures à essayer de parcourir les particularités des structures de données des pandas pour faire quelque chose de simple ET expressif. Il en résulte un code lisible.
Sean Anderson

Bien que cela for i in range(df.shape[0])puisse accélérer un peu cette approche, elle est toujours environ 3,5 fois plus lente que l'approche iterrows () ci-dessus pour mon application.
Kim Miller

Sur les gros Datafrmes, cela semble mieux car cela my_iter = df.itertuples()prend le double de la mémoire et beaucoup de temps pour le copier. pareil pour iterrows().
Bastiaan

33

Je cherchais comment itérer sur les lignes ET les colonnes et je me suis arrêté ici donc:

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)

18

Vous pouvez écrire votre propre itérateur qui implémente namedtuple

from collections import namedtuple

def myiter(d, cols=None):
    if cols is None:
        v = d.values.tolist()
        cols = d.columns.values.tolist()
    else:
        j = [d.columns.get_loc(c) for c in cols]
        v = d.values[:, j].tolist()

    n = namedtuple('MyTuple', cols)

    for line in iter(v):
        yield n(*line)

Ceci est directement comparable à pd.DataFrame.itertuples. Je vise à effectuer la même tâche avec plus d'efficacité.


Pour le dataframe donné avec ma fonction:

list(myiter(df))

[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]

Ou avec pd.DataFrame.itertuples:

list(df.itertuples(index=False))

[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

Un test complet
Nous testons la mise à disposition de toutes les colonnes et le sous-ensemble des colonnes.

def iterfullA(d):
    return list(myiter(d))

def iterfullB(d):
    return list(d.itertuples(index=False))

def itersubA(d):
    return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7']))

def itersubB(d):
    return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False))

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns='iterfullA iterfullB itersubA itersubB'.split(),
    dtype=float
)

for i in res.index:
    d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col')
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);

entrez la description de l'image ici

entrez la description de l'image ici


2
Pour les personnes qui ne veulent pas lire le code: la ligne bleue est intertuples, la ligne orange est une liste d'un itérateur à travers un bloc de rendement. interrowsn'est pas comparé.
James L.

18

Comment itérer efficacement?

Si vous devez vraiment itérer une trame de données pandas, vous voudrez probablement éviter d'utiliser iterrows () . Il existe différentes méthodes et l'habituel iterrows()est loin d'être le meilleur. itertuples () peut être 100 fois plus rapide.

En bref:

  • En règle générale, utilisez df.itertuples(name=None). En particulier, lorsque vous avez un nombre fixe de colonnes et moins de 255 colonnes.Voir point (3)
  • Sinon, utilisez df.itertuples()sauf si vos colonnes ont des caractères spéciaux tels que des espaces ou '-'.Voir point (2)
  • Il est possible d'utiliser itertuples()même si votre dataframe a des colonnes étranges en utilisant le dernier exemple.Voir point (4)
  • À utiliser uniquement iterrows()si vous ne pouvez pas utiliser les solutions précédentes. Voir point (1)

Différentes méthodes pour parcourir les lignes d'une trame de données pandas:

Générez une trame de données aléatoire avec un million de lignes et 4 colonnes:

    df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))
    print(df)

1) L'habitude iterrows()est pratique mais sacrément lente:

start_time = time.clock()
result = 0
for _, row in df.iterrows():
    result += max(row['B'], row['C'])

total_elapsed_time = round(time.clock() - start_time, 2)
print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))

2) La valeur par défaut itertuples()est déjà beaucoup plus rapide, mais elle ne fonctionne pas avec les noms de colonnes tels que My Col-Name is very Strange(vous devez éviter cette méthode si vos colonnes sont répétées ou si un nom de colonne ne peut pas être simplement converti en nom de variable python).

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row.B, row.C)

total_elapsed_time = round(time.clock() - start_time, 2)
print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

3) La valeur itertuples()par défaut en utilisant name = None est encore plus rapide mais pas vraiment pratique car vous devez définir une variable par colonne.

start_time = time.clock()
result = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
    result += max(col2, col3)

total_elapsed_time = round(time.clock() - start_time, 2)
print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4) Enfin, le nommé itertuples()est plus lent que le point précédent mais vous n'avez pas à définir de variable par colonne et cela fonctionne avec des noms de colonnes tels que My Col-Name is very Strange.

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')])

total_elapsed_time = round(time.clock() - start_time, 2)
print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

Production:

         A   B   C   D
0       41  63  42  23
1       54   9  24  65
2       15  34  10   9
3       39  94  82  97
4        4  88  79  54
...     ..  ..  ..  ..
999995  48  27   4  25
999996  16  51  34  28
999997   1  39  61  14
999998  66  51  27  70
999999  51  53  47  99

[1000000 rows x 4 columns]

1. Iterrows done in 104.96 seconds, result = 66151519
2. Named Itertuples done in 1.26 seconds, result = 66151519
3. Itertuples done in 0.94 seconds, result = 66151519
4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

Cet article est une comparaison très intéressante entre les iterrows et les itertuples


14

Pour boucler toutes les lignes d'un, dataframevous pouvez utiliser:

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]

1
Il s'agit d'une indexation chaînée. Je ne recommande pas de faire cela.
cs95

@ cs95 Que recommanderiez-vous à la place?
CONvid19

Si vous voulez que cela fonctionne, appelez df.columns.get_loc pour obtenir la position d'index entier de la colonne de date (en dehors de la boucle), puis utilisez un seul appel d'indexation iloc à l'intérieur.
cs95

14
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]

1
quelles sont les performances de cette option lorsqu'elle est utilisée sur une grande trame de données (millions de lignes par exemple)?
Bazyli Debowski

Honnêtement, je ne sais pas exactement, je pense qu'en comparaison avec la meilleure réponse, le temps écoulé sera à peu près le même, car les deux cas utilisent la construction "pour". Mais la mémoire peut être différente dans certains cas.
Grag2015

4
Il s'agit d'une indexation chaînée. Ne l'utilisez pas!
cs95

7

Parfois, un modèle utile est:

# Borrowing @KutalmisB df example
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
# The to_dict call results in a list of dicts
# where each row_dict is a dictionary with k:v pairs of columns:value for that row
for row_dict in df.to_dict(orient='records'):
    print(row_dict)

Ce qui se traduit par:

{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}

6

Pour boucler toutes les lignes de a dataframeet utiliser les valeurs de chaque ligne de manière pratique , namedtuplespeut être converti en ndarrays. Par exemple:

df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])

Itération sur les rangées:

for row in df.itertuples(index=False, name='Pandas'):
    print np.asarray(row)

résulte en:

[ 1.   0.1]
[ 2.   0.2]

Veuillez noter que si index=True, l'index est ajouté en tant que premier élément du tuple , ce qui peut être indésirable pour certaines applications.


5

Il existe un moyen d'itérer les lignes de lancement tout en obtenant un DataFrame en retour, et non une série. Je ne vois personne mentionner que vous pouvez passer l'index en tant que liste pour la ligne à renvoyer en tant que DataFrame:

for i in range(len(df)):
    row = df.iloc[[i]]

Notez l'utilisation de crochets doubles. Cela renvoie un DataFrame avec une seule ligne.


Cela a été très utile pour obtenir la nième ligne dans une trame de données après le tri. Merci!
Jason Harrison

3

Pour afficher et modifier des valeurs, j'utiliserais iterrows(). Dans une boucle for et en utilisant le décompactage de tuple (voir l'exemple:) i, row, j'utilise le rowpour afficher uniquement la valeur et utiliser iavec la locméthode lorsque je souhaite modifier des valeurs. Comme indiqué dans les réponses précédentes, ici, vous ne devez pas modifier quelque chose que vous répétez.

for i, row in df.iterrows():
    df_column_A = df.loc[i, 'A']
    if df_column_A == 'Old_Value':
        df_column_A = 'New_value'  

Ici, le rowdans la boucle est une copie de cette ligne, et non une vue de celle-ci. Par conséquent, vous ne devez PAS écrire quelque chose comme row['A'] = 'New_Value'cela, cela ne modifiera pas le DataFrame. Cependant, vous pouvez utiliser iet locspécifier le DataFrame pour effectuer le travail.


2

Je sais que je suis en retard à la partie répondante, mais je voulais juste ajouter à la réponse de @ cs95 ci-dessus, qui je pense devrait être la réponse acceptée. Dans sa réponse, il montre que la vectorisation des pandas surpasse de loin les autres méthodes des pandas pour calculer des choses avec des trames de données.

Je voulais ajouter que si vous convertissez d'abord la trame de données en un tableau numpy puis utilisez la vectorisation, c'est encore plus rapide que la vectorisation des trames de données pandas (et cela inclut le temps de le reconvertir en une série de trames de données).

Si vous ajoutez les fonctions suivantes au code de référence de @ cs95, cela devient assez évident:

def np_vectorization(df):
    np_arr = df.to_numpy()
    return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)

def just_np_vectorization(df):
    np_arr = df.to_numpy()
    return np_arr[:,0] + np_arr[:,1]

entrez la description de l'image ici


1

Vous pouvez également effectuer une numpyindexation pour des accélérations encore plus importantes. Ce n'est pas vraiment une itération, mais cela fonctionne beaucoup mieux que l'itération pour certaines applications.

subset = row['c1'][0:5]
all = row['c1'][:]

Vous pouvez également le caster dans un tableau. Ces index / sélections sont censés agir déjà comme des tableaux Numpy mais j'ai rencontré des problèmes et je devais lancer

np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file

1

Il y a tellement de façons de parcourir les lignes dans la trame de données des pandas. Une manière très simple et intuitive est:

df=pd.DataFrame({'A':[1,2,3], 'B':[4,5,6],'C':[7,8,9]})
print(df)
for i in range(df.shape[0]):
    # For printing the second column
    print(df.iloc[i,1])
    # For printing more than one columns
    print(df.iloc[i,[0,2]])

0

Cet exemple utilise iloc pour isoler chaque chiffre de la trame de données.

import pandas as pd

 a = [1, 2, 3, 4]
 b = [5, 6, 7, 8]

 mjr = pd.DataFrame({'a':a, 'b':b})

 size = mjr.shape

 for i in range(size[0]):
     for j in range(size[1]):
         print(mjr.iloc[i, j])

0

Certaines bibliothèques (par exemple une bibliothèque Java Interop que j'utilise) nécessitent que les valeurs soient transmises dans une rangée à la fois, par exemple, en cas de streaming de données. Pour reproduire la nature du streaming, je 'stream' mes valeurs de trame de données une par une, j'ai écrit ci-dessous, ce qui est pratique de temps en temps.

class DataFrameReader:
  def __init__(self, df):
    self._df = df
    self._row = None
    self._columns = df.columns.tolist()
    self.reset()
    self.row_index = 0

  def __getattr__(self, key):
    return self.__getitem__(key)

  def read(self) -> bool:
    self._row = next(self._iterator, None)
    self.row_index += 1
    return self._row is not None

  def columns(self):
    return self._columns

  def reset(self) -> None:
    self._iterator = self._df.itertuples()

  def get_index(self):
    return self._row[0]

  def index(self):
    return self._row[0]

  def to_dict(self, columns: List[str] = None):
    return self.row(columns=columns)

  def tolist(self, cols) -> List[object]:
    return [self.__getitem__(c) for c in cols]

  def row(self, columns: List[str] = None) -> Dict[str, object]:
    cols = set(self._columns if columns is None else columns)
    return {c : self.__getitem__(c) for c in self._columns if c in cols}

  def __getitem__(self, key) -> object:
    # the df index of the row is at index 0
    try:
        if type(key) is list:
            ix = [self._columns.index(key) + 1 for k in key]
        else:
            ix = self._columns.index(key) + 1
        return self._row[ix]
    except BaseException as e:
        return None

  def __next__(self) -> 'DataFrameReader':
    if self.read():
        return self
    else:
        raise StopIteration

  def __iter__(self) -> 'DataFrameReader':
    return self

Qui peut être utilisé:

for row in DataFrameReader(df):
  print(row.my_column_name)
  print(row.to_dict())
  print(row['my_column_name'])
  print(row.tolist())

Et préserve le mappage des valeurs / noms pour les lignes à itérer. Évidemment, c'est beaucoup plus lent que d'utiliser apply et Cython comme indiqué ci-dessus, mais c'est nécessaire dans certaines circonstances.


0

En bref

  • Utilisez la vectorisation si possible
  • Si l'opération ne peut pas être vectorisée - utilisez des compréhensions de liste
  • Si vous avez besoin d'un seul objet représentant une ligne entière - utilisez des itertuples
  • Si ce qui précède est trop lent - essayez swifter.apply
  • Si c'est encore trop lent - essayez la routine Cython

Détails dans cette vidéo

Référence Référence de l'itération sur les lignes d'un DataFrame pandas

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.