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.
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
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.
for index, row in df.iterrows():
print row["c1"], row["c2"]
for row in df.itertuples(index=True, name='Pandas'):
print getattr(row, "c1"), getattr(row, "c2")
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.
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.
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
Comment parcourir les lignes d'un DataFrame dans les pandas?
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 ):
for
)DataFrame.apply()
: i) Réductions pouvant être effectuées en cython, ii) Itération dans l'espace pythonDataFrame.itertuples()
et iteritems()
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 [...].
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 .
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.
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.
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.
10 Minutes to pandas , et Fonctionnalités de base essentielles - Liens utiles qui vous présentent pandas et sa bibliothèque de fonctions vectorisées */cythonisées.
Amélioration des performances - Introduction à la documentation sur l’amélioration des opérations standard pandas
Les boucles for pandas sont-elles vraiment mauvaises? Quand dois-je m'en soucier? - un texte détaillé que je résume sur la compréhension des listes et leur pertinence pour diverses opérations (principalement celles impliquant des données non numériques )
Quand devrais-je jamais utiliser pandas apply () dans mon code? - apply
est lent (mais maintenant aussi lent que la famille iter*
. Il existe cependant des situations dans lesquelles on peut (ou devrait) considérer apply
comme une alternative en série, en particulier dans certaines opérations GroupBy
.
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.
Vous pouvez également utiliser df.apply()
pour parcourir les lignes et accéder à plusieurs colonnes pour une fonction.
def valuation_formula(x, y):
return x * y * 0.5
df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
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']
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)
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);
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]
for ind in df.index:
print df['c1'][ind], df['c2'][ind]
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}
Pour boucler toutes les lignes d'une dataframe
et tiliser les valeurs de chaque ligne de manière pratique, namedtuples
peuvent être converties en ndarray
s. 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.
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.
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
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']
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]])
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])