web-dev-qa-db-fra.com

Comment parcourir les lignes d'un DataFrame dans les pandas?

J'ai un DataFrame de pandas:

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

Sortie:

   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 dans les pandas?

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

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

ou

for row in df.iterrows():

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

1368
Roman

DataFrame.iterrows est un générateur qui génère à la fois un index et une 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
1916
waitingkuo

Commencez par considérer si vous devez vraiment 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 supposé être plus rapide que iterrows()

Mais sachez que, selon les docs (pandas 0.24.2 pour le moment):

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

    Comme iterrows renvoie une série pour chaque ligne, il ne conserve pas les types de données dans les lignes (les types de données sont préservés dans les colonnes de DataFrames). Pour conserver les types en tout en parcourant les lignes, il est préférable d’utiliser itertuples (), qui renvoie les éléments nommés des valeurs et qui est généralement beaucoup plus rapide que iterrows ().

  • iterrows: ne modifie pas les lignes

    Vous devriez ne jamais modifier quelque chose que vous parcourez. 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 son écriture n'aura aucun effet.

    Utilisez DataFrame.apply () à la place:

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

    Les noms de colonne seront renommés en noms de position s’ils sont des identificateurs non valides Python, répétés ou commencent par un trait de soulignement. Avec un grand nombre de colonnes (> 255), les nuplets ordinaires sont renvoyés.

Voir pandas docs on iteration pour plus de détails.

295
viddik13

Vous devriez utiliser df.iterrows() . Bien que l'itération ligne par ligne ne soit pas particulièrement efficace dans la mesure où des objets Série doivent être créés.

186
Wes McKinney

Bien que iterrows() soit une bonne option, parfois itertuples() peut ê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
142
e9t

Comment parcourir les lignes d'un DataFrame dans les pandas?

Réponse: NE PAS!

L'itération dans pandas est un anti-modèle, et vous ne devriez le vouloir que lorsque vous avez épuisé toutes les autres options possibles. Vous ne devriez pas envisager d'utiliser une fonction avec "iter" dans son nom pour autre chose que quelques milliers de lignes, sinon vous devrez vous habituer à un lot d'attendre.

Voulez-vous imprimer un DataFrame? Utilisez DataFrame.to_string() .

Voulez-vous calculer quelque chose? Dans ce cas, recherchez les méthodes dans cet ordre (liste modifiée de here ):

  1. Vectorisation
  2. Routines Cython
  3. Liste des compréhensions (boucle Vanilla for)
  4. DataFrame.apply() : i) Réductions pouvant être effectuées en cython, ii) Itération dans l'espace python
  5. DataFrame.itertuples() et iteritems()
  6. DataFrame.iterrows()

iterrows et itertuples (recevant de nombreux votes en réponse à cette question) devraient être utilisés dans de très rares circonstances, telles que la génération d'objets de rangée/d'échantillons de noms pour le traitement séquentiel, qui est en réalité la seule chose que ces fonctions sont utile pour.

Appel à l'autorité
La page de la documentation sur itération a une énorme boîte d’avertissement rouge qui dit:

Itérer à travers pandas objets est généralement lent. Dans de nombreux cas, une itération manuelle sur les lignes n'est pas nécessaire [...].


Plus rapide que le bouclage: Vectorisation , Cython

Un bon nombre d'opérations et de calculs de base sont "vectorisés" par pandas (soit via NumPy, soit via des fonctions Cythonisées). Cela inclut l'arithmétique, les comparaisons, (la plupart) les réductions, le remodelage (comme le pivotement), les jointures et les opérations groupby. Parcourez la documentation sur Fonctionnalités de base essentielles pour trouver une méthode vectorisée adaptée à votre problème.

S'il n'y en a pas, n'hésitez pas à écrire le vôtre en utilisant custom extensions de cython .


Meilleure chose à faire: Comprendre la liste

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 pour passer au travers de la cythonisation de votre code, et 3) vous essayez d'effectuer une transformation élémentaire. sur votre code. Il y a bonne quantité de preuves pour suggérer que la compréhension de la liste est suffisamment rapide (et même parfois plus rapide) pour de nombreuses tâches courantes 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
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].values]

Si vous pouvez encapsuler votre logique métier dans une fonction, vous pouvez utiliser une liste de compréhension qui l'appelle. Vous pouvez faire fonctionner des choses arbitrairement complexes grâce à la simplicité et à la rapidité du python brut.


Un exemple évident

Montrons la différence avec un exemple simple d’ajout de deux pandas colonnes 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.

enter image description here

Code d'analyse comparative, pour votre référence.

Je devrais mentionner, cependant, que ce n'est pas toujours cette coupe 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.


Références

Les méthodes de chaîne * Pandas sont "vectorisées" dans le sens où elles sont spécifiées dans la série, mais fonctionnent sur chaque élément. Les mécanismes sous-jacents sont toujours itératifs, car les opérations sur les chaînes de caractères sont difficiles à vectoriser.

123
cs95

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

docs: 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)
79
cheekybastard

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']
67
PJay

Je cherchais Comment itérer sur les lignes ET les colonnes et terminé ici alors:

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

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 disponibilité de toutes les colonnes et leur sous-configuration.

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

enter image description here

enter image description here

16
piRSquared

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

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
13
Pedro Lobito
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
13
Grag2015

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 résulte en:

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

Pour boucler toutes les lignes d'une dataframe et tiliser les valeurs de chaque ligne de manière pratique, namedtuples peuvent être converties en ndarrays. Par exemple:

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

Itérant sur les lignes:

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.

6
KutalmisB

Pour visualiser et modifier les valeurs, je voudrais utiliser iterrows(). Dans une boucle for et en utilisant la décompression de Tuple (voir l'exemple: i, row), j'utilise le row pour afficher uniquement la valeur et utilise i avec la méthode loc lorsque Je veux modifier les valeurs. Comme indiqué dans les réponses précédentes, vous ne devez pas modifier ici quelque chose que vous parcourez.

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

Ici, la row dans la boucle est une copie de cette ligne et non une vue. Par conséquent, vous ne devriez PAS écrire quelque chose comme row['A'] = 'New_Value', cela ne modifiera pas le DataFrame. Cependant, vous pouvez utiliser i et loc et spécifier le DataFrame pour effectuer le travail.

2
HKRC

Vous pouvez également faire numpy indexation pour des accélérations encore plus grandes. Ce n'est pas vraiment itératif mais fonctionne beaucoup mieux que l'itération pour certaines applications.

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

Vous voudrez peut-être aussi le lancer dans un tableau. Ces index/sélections sont supposés agir comme des tableaux Numpy mais j’ai rencontré des problèmes et j’avais besoin de

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

Pourquoi compliquer les choses?

Facile.

import pandas as pd
import numpy as np

# Here is an example dataframe
df_existing = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))
for idx,row in df_existing.iterrows():
    print row['A'],row['B'],row['C'],row['D']
1
Justin Malinchak

Il y a tellement de façons de parcourir les lignes de pandas dataframe. Un moyen très simple et intuitif 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]])
1
shubham ranjan

Cet exemple utilise iloc pour isoler chaque chiffre du bloc 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
mjr2000