Cum să iterați peste rândurile dintr-un DataFrame în Pandas (Programare, Python, Pandas, Dataframe)

Roman a intrebat.

Am un DataFrame din Pandas:

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

Output:

   c1   c2
0  10  100
1  11  110
2  12  120

Acum vreau să iteratez peste rândurile din acest cadru. Pentru fiecare rând vreau să pot accesa elementele sale (valorile din celule) după numele coloanelor. De exemplu:

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

Este posibil să se facă acest lucru în Pandas?

Am găsit această întrebare similară. Dar nu îmi oferă răspunsul de care am nevoie. De exemplu, acolo se sugerează să se folosească:

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

sau

for row in df.iterrows():

Dar eu nu înțeleg ce înseamnă row obiect și cum pot lucra cu el.

Comentarii

  • Df.iteritems() iterează pe coloane și nu pe rânduri. Prin urmare, pentru a face iterația pe rânduri, trebuie să transpuneți (T), ceea ce înseamnă că schimbați rândurile și coloanele una în cealaltă (reflectați pe diagonală). Ca urmare, atunci când utilizați df.T.iteritems(), iterați efectiv dataframe-ul original pe rândurile sale –  > Por Stefan Gruenwald.
  • 66

  • Spre deosebire de ceea ce spune cs95, există motive perfect întemeiate pentru a dori să iterați peste un dataframe, astfel încât noii utilizatori nu ar trebui să se simtă descurajați. Un exemplu este dacă doriți să executați un cod folosind ca intrare valorile fiecărui rând. De asemenea, dacă dataframe-ul dvs. este rezonabil de mic (de exemplu, mai puțin de 1000 de elemente), performanța nu este cu adevărat o problemă. –  > Por oulenz.
  • @cs95 Mie mi se pare că dataframe-urile sunt formatul de tabel preferat în Python. Astfel, ori de câte ori doriți să citiți un csv, sau aveți o listă de dicte ale căror valori doriți să le manipulați, sau doriți să efectuați operații simple de join, groupby sau window, utilizați un dataframe, chiar dacă datele dvs. sunt relativ mici. –  > Por oulenz.
  • @cs95 Nu, dar acest lucru a fost un răspuns la „utilizarea unui DataFrame deloc”. Ceea ce vreau să spun este că acesta este motivul pentru care cineva poate avea datele sale într-un dataframe. Dacă doriți apoi, de exemplu, să rulați un script pentru fiecare linie de date, trebuie să iterați peste acel cadru de date. –  > Por oulenz.
  • 25

  • Îl susțin pe @oulenz. Din câte îmi dau seama pandas este alegerea de bază pentru citirea unui fișier csv, chiar dacă setul de date este mic. Este pur și simplu mai ușor de programat pentru a manipula datele cu API-uri -.  > Por Pentru totdeauna.
26 răspunsuri
waitingkuo

DataFrame.iterrows este un generator care produce atât indexul, cât și rândul (ca o Serie):

import pandas as pd

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

for index, row in df.iterrows():
    print(row['c1'], row['c2'])
10 100
11 110
12 120

Comentarii

    272

  • Notă: „Deoarece iterrows returnează o serie pentru fiecare rând, acesta nu păstrează dtypurile între rânduri.” De asemenea, „Puteți nu trebuie să modificați niciodată ceva peste care iterați.” Conform documentația pandas 0.19.1 –  > Por viddik13.
  • @viddik13 aceasta este o notă excelentă, mulțumesc. Din această cauză am dat peste un caz în care valori numerice precum 431341610650 unde sunt citite ca 4.31E+11. Există o modalitate de a păstra dtypes? –  > Por Aziz Alto.
  • 35

  • @AzizAlto folosiți itertuples, , așa cum se explică mai jos. Vezi și pandas.pydata.org/pandas-docs/stable/generated/… –  > Por Axel.
  • 126

  • Nu utilizați iterrows. Itertuples este mai rapid și păstrează tipul de date. Mai multe informații –  > Por James L..
  • Adus de la documentația: „Iterarea printre obiectele pandas este în general lentă. În multe cazuri, iterarea manuală peste rânduri nu este necesară[…]”. Răspunsul dvs. este corect (în contextul întrebării), dar nu menționează acest lucru nicăieri, deci nu este unul foarte bun. –  > Por cs95.
cs95

Cum să iterați peste rândurile dintr-un DataFrame în Pandas?

Răspuns: NU*!

Iterarea în Pandas este un anti-pattern și este ceva ce ar trebui să faceți numai atunci când ați epuizat orice altă opțiune. Nu ar trebui să folosiți nicio funcție cu „iter” în numele său pentru mai mult de câteva mii de rânduri, altfel va trebui să vă obișnuiți cu o funcție mult de așteptare.

Doriți să imprimați un DataFrame? Utilizați DataFrame.to_string().

Doriți să calculați ceva? În acest caz, căutați metode în această ordine (listă modificată de aici):

  1. Vectorizare
  2. Cython rutine
  3. List Comprehensions (vanilla for buclă)
  4. DataFrame.apply(): i) Reducții care pot fi efectuate în Cython, ii) Iterarea în spațiul Python
  5. DataFrame.itertuples() și iteritems()
  6. DataFrame.iterrows()

iterrows și itertuples (ambele primind multe voturi în răspunsurile la această întrebare) ar trebui utilizate în circumstanțe foarte rare, cum ar fi generarea de obiecte de rânduri/nametuple pentru procesarea secvențială, care este într-adevăr singurul lucru pentru care aceste funcții sunt utile.

Apel la autoritate

Pagina de documentație privind iterația are o casetă de avertizare roșie uriașă care spune:

Iterarea printre obiectele pandas este, în general, lentă. În multe cazuri, iterarea manuală peste rânduri nu este necesară […].

* De fapt, este un pic mai complicat decât „nu”. df.iterrows() este răspunsul corect la această întrebare, dar „vectorizează-ți operațiile” este cel mai bun. Voi admite că există circumstanțe în care iterația nu poate fi evitată (de exemplu, unele operațiuni în care rezultatul depinde de valoarea calculată pentru rândul anterior). Cu toate acestea, este nevoie de o anumită familiaritate cu biblioteca pentru a ști când. Dacă nu sunteți sigur că aveți nevoie de o soluție iterativă, probabil că nu aveți nevoie. PS: Pentru a afla mai multe despre motivul pentru care am scris acest răspuns, treceți la final.


Mai rapid decât Looping: Vectorizarea, Cython

Un număr bun de operații și calcule de bază sunt „vectorizate” de pandas (fie prin NumPy, fie prin funcții Cythonized). Aceasta include aritmetica, comparațiile, (majoritatea) reducerilor, remodelarea (cum ar fi pivotarea), îmbinările și operațiile de grupare. Răsfoiți documentația privind Funcționalități de bază esențiale pentru a găsi o metodă vectorizată potrivită pentru problema dumneavoastră.

Dacă nu există niciuna, nu ezitați să vă scrieți propria metodă folosind metode personalizate extensii Cython.


Următorul lucru cel mai bun: Comprehensiunile de liste*

List comprehensions ar trebui să fie următoarea soluție la care să apelați dacă 1) nu există o soluție vectorizată disponibilă, 2) performanța este importantă, dar nu suficient de importantă pentru a vă chinui să vă cythonizați codul și 3) încercați să efectuați o transformare a codului în funcție de elemente. Există o cantitate bună de dovezi care sugerează că înțelegerile de liste sunt suficient de rapide (și chiar uneori mai rapide) pentru multe sarcini comune ale Pandas.

Formula este simplă,

# 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'])]

Dacă vă puteți încapsula logica de afaceri într-o funcție, puteți utiliza o înțelegere de listă care să o apeleze. Puteți face ca lucruri arbitrar de complexe să funcționeze prin simplitatea și viteza codului Python brut.

Atenționări

Înțelegerile de liste presupun că datele dvs. sunt ușor de prelucrat – ceea ce înseamnă că tipurile de date sunt coerente și că nu aveți NaN-uri, dar acest lucru nu poate fi garantat întotdeauna.

  1. Prima este mai evidentă, dar atunci când aveți de-a face cu NaN-uri, preferați metodele pandas încorporate, dacă acestea există (deoarece acestea au o logică mult mai bună de gestionare a cazurilor de colț) sau asigurați-vă că logica dvs. de afaceri include o logică adecvată de gestionare a NaN-urilor.
  2. Atunci când aveți de-a face cu tipuri de date mixte, ar trebui să iterați peste zip(df['A'], df['B'], ...) în loc de df[['A', 'B']].to_numpy() deoarece acesta din urmă actualizează implicit datele la cel mai comun tip. De exemplu, dacă A este numeric și B este un șir de caractere, to_numpy() va transforma întreaga matrice în șir de caractere, ceea ce s-ar putea să nu fie ceea ce vă doriți. Din fericire, zipping-ul coloanelor împreună este cea mai simplă soluție de rezolvare a acestui aspect.

*Milimetrul poate varia din motivele prezentate în secțiunea avertismente de mai sus.


Un exemplu evident

Să demonstrăm diferența cu un exemplu simplu de adăugare a două coloane pandas A + B. Aceasta este o operație vectorizabilă, astfel încât va fi ușor de comparat performanța metodelor discutate mai sus.

Codul de analiză comparativă, pentru referință. Linia din partea de jos măsoară o funcție scrisă în numpandas, un stil de Pandas care se amestecă puternic cu NumPy pentru a stoarce performanța maximă. Scrierea codului numpandas ar trebui evitată dacă nu știți ce faceți. Rămâneți la API atunci când puteți (de exemplu, preferați vec în loc de vec_numpy).

Ar trebui să menționez, totuși, că nu este întotdeauna atât de simplu. Uneori, răspunsul la întrebarea „care este cea mai bună metodă pentru o operațiune” este „depinde de datele dumneavoastră”. Sfatul meu este să testați diferite abordări pe datele dvs. înainte de a vă decide asupra uneia.


Lecturi suplimentare

  • 10 minute pentru pandas, , și Funcționalități de bază esențiale – Link-uri utile care vă introduc în Pandas și în biblioteca sa de funcții vectorizate*/cythonizate.

  • Îmbunătățirea performanțelor – Un îndrumar din documentație privind îmbunătățirea operațiilor standard Pandas

  • Sunt buclele for loop în pandas cu adevărat rele? Când ar trebui să-mi pese? – un articol detaliat scris de mine despre înțelegerea listelor și adecvarea lor pentru diverse operații (în principal cele care implică date nenumerice)

  • Când ar trebui să (nu) doresc să folosesc pandas apply() în codul meu?apply este lent (dar nu la fel de lent ca iter* familie. Cu toate acestea, există situații în care se poate (sau ar trebui) să se ia în considerare apply ca o alternativă serioasă, în special în anumite GroupBy operațiuni).

* Metodele de șiruri de caractere Pandas sunt „vectorizate”, în sensul că sunt specificate pe serie, dar operează pe fiecare element. Mecanismele subiacente sunt încă iterative, deoarece operațiile cu șiruri de caractere sunt în mod inerent greu de vectorizat.


De ce am scris acest răspuns

O tendință comună pe care o observ la noii utilizatori este de a pune întrebări de forma „Cum pot itera peste df-ul meu pentru a face X?”. Arătând codul care apelează iterrows() în timp ce face ceva în interiorul unui for buclă. Iată de ce. Un utilizator nou al bibliotecii, care nu a fost introdus în conceptul de vectorizare, își va imagina probabil codul care îi rezolvă problema ca fiind o iterație peste datele lor pentru a face ceva. Neștiind cum să itereze peste un DataFrame, primul lucru pe care îl face este să caute pe Google și ajunge aici, la această întrebare. Apoi văd răspunsul acceptat care le spune cum să facă acest lucru, închid ochii și rulează acest cod fără să se întrebe dacă nu cumva iterația este lucrul corect.

Scopul acestui răspuns este de a-i ajuta pe noii utilizatori să înțeleagă că iterația nu este neapărat soluția pentru orice problemă și că ar putea exista soluții mai bune, mai rapide și mai idiomatice și că merită să investească timp pentru a le explora. Nu încerc să pornesc un război al iterației vs. vectorizării, dar vreau ca noii utilizatori să fie informați atunci când dezvoltă soluții la problemele lor cu această bibliotecă.

Comentarii

  • Rețineți că există avertismente importante cu iterrows și itertuples. Consultați acest răspuns și documentația pandas pentru mai multe detalii. –  > Por viddik13.
  • 56

  • Acesta este singurul răspuns care se concentrează pe tehnicile idiomatice pe care ar trebui să le folosești cu pandas, ceea ce îl face cel mai bun răspuns pentru această întrebare. Învățarea de a obține corect răspuns cu corect cod (în loc de corect răspuns cu codul greșit cod – adică ineficient, nu se scalează, prea adaptat la date specifice) reprezintă o mare parte din învățarea pandas (și a datelor în general). –  > Por LinkBerest.
  • Cred că sunteți nedrept față de buclele for, totuși, având în vedere că sunt doar puțin mai lente decât înțelegerea listelor în testele mele. Șmecheria este să faci o buclă peste zip(df['A'], df['B']) în loc de df.iterrows(). –  > Por Noapte nepieritoare.
  • În secțiunea List Comprehensions, exemplul „iterație pe mai multe coloane” necesită o atenționare: DataFrame.values va converti fiecare coloană într-un tip de date comun. DataFrame.to_numpy() face și acest lucru. Din fericire, putem folosi zip cu orice număr de coloane. –  > Por David Wasserman.
  • @Dean Primesc acest răspuns destul de des și, sincer, mă confundă. Totul se rezumă la formarea unor obiceiuri bune. „Datele mele sunt mici și performanța nu contează, așa că utilizarea acestui antipattern poate fi scuzată” …? Când într-o zi performanța chiar va conta, îți vei mulțumi pentru că ți-ai pregătit din timp instrumentele potrivite. –  > Por cs95.
viddik13

Mai întâi gândiți-vă dacă aveți cu adevărat nevoie de iterați peste rândurile dintr-un DataFrame. Consultați acest răspuns pentru alternative.

Dacă totuși aveți nevoie să iterați peste rânduri, puteți utiliza metodele de mai jos. Rețineți că unele avertismente importante care nu sunt menționate în niciunul dintre celelalte răspunsuri.

itertuples() se presupune că este mai rapid decât iterrows()

Dar fiți atenți, conform documentației (pandas 0.24.2 în acest moment):

  • iterrows: dtype s-ar putea să nu se potrivească de la un rând la altul

    Deoarece iterrows returnează o serie pentru fiecare rând, acesta nu păstrează dtypes între rânduri (dtypes se păstrează între coloane pentru DataFrames). Pentru a păstra dtipurile în timpul iterației peste rânduri, este mai bine să se utilizeze itertuples(), care returnează un set de valori numite și care este, în general, mult mai rapid decât iterrows().

  • iterrows: Nu modificați rândurile

    Trebuie să nu modificați niciodată ceva peste care faceți iterație. Nu se garantează că acest lucru funcționează în toate cazurile. În funcție de tipurile de date, iteratorul returnează o copie și nu o vizualizare, iar scrierea în el nu va avea niciun efect.

    Utilizați DataFrame.apply() în schimb:

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

    Numele coloanelor vor fi redenumite în nume de poziție dacă sunt identificatori Python nevalabili, se repetă sau încep cu o subliniere. În cazul unui număr mare de coloane (>255), sunt returnate tuple obișnuite.

A se vedea documentația pandas privind iterația pentru mai multe detalii.

Comentarii

  • Doar o mică întrebare din partea cuiva care citește acest fir de discuție la atât de mult timp după ce a fost finalizat: cum se compară df.apply() cu itertuples din punct de vedere al eficienței? –  > Por Raul Guarini.
  • Notă: puteți, de asemenea, să spuneți ceva de genul for row in df[['c1','c2']].itertuples(index=True, name=None): pentru a include doar anumite coloane în iteratorul de rânduri. –  > Por Brian Burns.
  • În loc de getattr(row, "c1"), , puteți utiliza doar row.c1. –  > Por viraptor.
  • Sunt sigur în proporție de 90% că dacă folosiți getattr(row, "c1") în loc de row.c1, , pierdeți orice avantaj de performanță al itertuples, , iar dacă chiar trebuie să ajungeți la proprietate printr-un șir de caractere, ar trebui să folosiți iterrows în schimb. –  > Por Noctiphobia.
  • Am dat peste această întrebare pentru că, deși știam că există split-apply-combine, tot am într-adevăr aveam nevoie să iterate peste un DataFrame (așa cum se precizează în întrebare). Nu toată lumea are luxul de a se perfecționa cu numba și cython (aceeași documentație spune că „Întotdeauna merită să optimizați mai întâi în Python”). Am scris acest răspuns pentru a-i ajuta pe alții să evite problemele (uneori frustrante), deoarece niciunul dintre celelalte răspunsuri nu menționează aceste avertismente. A induce pe cineva în eroare sau a spune „așa trebuie să faci” nu a fost niciodată intenția mea. Am îmbunătățit răspunsul. –  > Por viddik13.
Wes McKinney

Ar trebui să folosiți df.iterrows(). Deși iterarea rând cu rând nu este deosebit de eficientă, deoarece Series trebuie să fie create obiecte.

Comentarii

  • Este mai rapid decât să convertiți DataFrame într-un array numpy (prin .values) și să operați direct pe array? Am avut aceeași problemă, dar am ajuns să convertesc într-o matrice numpy și apoi să folosesc cython. –  > Por vgoklani.
  • @vgoklani Dacă iterarea rând cu rând este ineficientă și aveți un array numpy fără obiect, atunci aproape sigur că utilizarea array-ului numpy brut va fi mai rapidă, în special pentru array-uri cu multe rânduri. ar trebui să evitați iterarea peste rânduri, cu excepția cazului în care trebuie neapărat să –  > Por Phillip Cloud.
  • Am făcut câteva teste privind consumul de timp pentru df.iterrows(), df.itertuples() și zip(df[‘a’], df[‘b’]) și am postat rezultatul în răspunsul la o altă întrebare: stackoverflow.com/a/34311080/2142098 –  > Por Richard Wong.
e9t

În timp ce iterrows() este o opțiune bună, uneori itertuples() poate fi mult mai rapidă:

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

Comentarii

  • O mare parte din diferența de timp din cele două exemple pare să se datoreze faptului că se pare că folosiți indexarea bazată pe etichete pentru comanda .iterrows() și indexarea bazată pe numere întregi pentru comanda .itertuples(). –  > Por Alex.
  • Pentru un cadru de date bazat pe date financiare (timestamp și 4x float), itertuples este de 19,57 ori mai rapid decât iterrows pe calculatorul meu. Numai for a,b,c in izip(df["a"],df["b"],df["c"]: este aproape la fel de rapid. –  > Por harbun.
  • Puteți explica de ce este mai rapid? –  > Por Abe Miessler.
  • @AbeMiessler iterrows() casetează fiecare rând de date într-o serie, în timp ce itertuples()nu o face. –  > Por miradulo.
  • Rețineți că ordinea coloanelor este de fapt nedeterminată, deoarece df este creat dintr-un dicționar, astfel încât row[1] se poate referi la oricare dintre coloane. După cum se dovedește, totuși, timpii sunt aproximativ aceiași pentru coloanele de numere întregi față de cele de float. –  > Por Brian Burns.
cheekybastard

De asemenea, puteți utiliza df.apply() pentru a itera peste rânduri și a accesa mai multe coloane pentru o funcție.

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

Comentarii

  • Este df[‘price’] se referă la un nume de coloană din cadrul de date? Încerc să creez un dicționar cu valori unice din mai multe coloane dintr-un fișier csv. Am folosit logica dvs. pentru a crea un dicționar cu chei și valori unice și am primit o eroare care spune TypeError: („‘Series’ objects are mutable, therefore they cannot be hashed”, u’occurred at index 0′) –  > Por SRS.
  • Cod: df[‘Workclass’] = df.apply(lambda row: dic_update(row), axis=1) sfârșit de linie id = 0 sfârșit de rând def dic_update(row): if row not in dic: dic[row] = id id = id + 1 –  > Por SRS.
  • Nu contează, am înțeles. Am schimbat linia de apelare a funcției în df_new = df[‘Workclass’].apply(același lucru) –  > Por SRS.
  • Dacă axa este implicită la 0, este cel mai rău –  > Por zthomas.nc.
  • Observați că apply nu „itera” peste rânduri, ci aplică o funcție în funcție de rând. Codul de mai sus nu ar funcționa dacă într-adevăr faceți aveți nevoie de iterații și indecși, de exemplu atunci când comparați valori pe rânduri diferite (în acest caz nu puteți face altceva decât să iterați). –  > Por gented.
PJay

Puteți utiliza funcția df.iloc după cum urmează:

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

Comentarii

  • Știu că ar trebui să se evite acest lucru în favoarea iterrows sau itertuples, dar ar fi interesant de știut de ce. Aveți vreo idee? –  > Por rocarvaj.
  • Aceasta este singura tehnică validă pe care o cunosc dacă doriți să păstrați tipurile de date și, de asemenea, să faceți referire la coloane prin nume. itertuples păstrează tipurile de date, dar scapă de orice nume care nu-i place. iterrows face opusul. –  > Por Ken Williams.
  • Am petrecut ore întregi încercând să mă descurc printre idiosincrasiile structurilor de date pandas pentru a face ceva simplu ȘI expresiv. Acest lucru are ca rezultat un cod lizibil. –  > Por Sean Anderson.
  • În timp ce for i in range(df.shape[0]) ar putea să accelereze puțin această abordare, pentru aplicația mea este încă de aproximativ 3,5 ori mai lentă decât abordarea iterrows() de mai sus. –  > Por Kim Miller.
  • La bazele de date mari, această metodă pare mai bună, deoarece my_iter = df.itertuples() necesită de două ori mai multă memorie și mult timp pentru a le copia. iterrows(). –  > Por Bastiaan.
Romain Capron

Cum să iterați eficient

Dacă chiar trebuie să iterați un cadru de date Pandas, probabil că veți dori să evitați să utilizați iterrows(). Există diferite metode și metoda obișnuită iterrows() este departe de a fi cea mai bună. itertuples() poate fi de 100 de ori mai rapidă.

Pe scurt:

  • Ca regulă generală, utilizați df.itertuples(name=None). În special, atunci când aveți un număr fix de coloane și mai puțin de 255 de coloane. A se vedea punctul (3)
  • În caz contrar, utilizați df.itertuples() cu excepția cazului în care coloanele dvs. au caractere speciale, cum ar fi spații sau „-„. A se vedea punctul (2)
  • Este posibil să se utilizeze itertuples() chiar dacă dataframe-ul dumneavoastră are coloane ciudate, folosind ultimul exemplu. A se vedea punctul (4)
  • Utilizați numai iterrows() dacă nu puteți utiliza soluțiile anterioare. A se vedea punctul (1)

Diferite metode pentru a itera peste rândurile dintr-un dataframe Pandas:

Generați un cadru de date aleatoriu cu un milion de rânduri și 4 coloane:

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

1) Metoda obișnuită iterrows() este convenabil, dar al naibii de lent:

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) Metoda implicită itertuples() este deja mult mai rapidă, dar nu funcționează cu nume de coloane precum My Col-Name is very Strange (ar trebui să evitați această metodă dacă coloanele dvs. se repetă sau dacă un nume de coloană nu poate fi pur și simplu convertit într-un nume de variabilă 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) Metoda implicită itertuples() folosind name=None este și mai rapidă, dar nu este foarte convenabilă, deoarece trebuie să definiți o variabilă pentru fiecare coloană.

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) În cele din urmă, metoda numită itertuples() este mai lent decât punctul anterior, dar nu trebuie să definiți o variabilă pentru fiecare coloană și funcționează cu nume de coloane precum 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))

Ieșire:

         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

Acest articol este o comparație foarte interesantă între iterrows și itertuples

Comentarii

  • O explicație excelentă! mulțumesc -.  > Por Kedar Joshi.
Lucas B

Am căutat Cum să iterăm pe rânduri și coloane și am ajuns aici așa:

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

Comentarii

  • Atunci când este posibil, ar trebui să evitați utilizarea iterrows(). Am explicat de ce în răspunsul Cum să iterați eficient –  > Por Romain Capron.
piRSquared

Puteți să vă scrieți propriul iterator care să implementeze 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)

Acesta este direct comparabil cu pd.DataFrame.itertuples. Scopul meu este de a efectua aceeași sarcină cu mai multă eficiență.


Pentru dataframe-ul dat cu funcția mea:

list(myiter(df))

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

Sau cu 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 cuprinzător
Testăm punerea la dispoziție a tuturor coloanelor și subsetul coloanelor.

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

Comentarii

  • Pentru cei care nu vor să citească codul: linia albastră este intertuples, , linia portocalie este o listă a unui iterator prin intermediul unui bloc yield. interrows nu este comparat. –  > Por James L..
Grag2015
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]

Comentarii

  • cum este performanța acestei opțiuni atunci când este utilizată pe un cadru de date mare (milioane de rânduri, de exemplu)? –  > Por Bazyli Debowski.
  • Sincer, nu știu exact, cred că, în comparație cu cel mai bun răspuns, timpul scurs va fi aproximativ același, deoarece ambele cazuri utilizează construcția „for”-ului. Dar memoria poate fi diferită în unele cazuri. –  > Por Grag2015.
  • Aceasta este o indexare înlănțuită. Nu folosiți acest lucru! –  > Por cs95.
Pedro Lobito

Pentru a face o buclă cu toate rândurile dintr-un dataframe puteți utiliza:

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

Comentarii

  • Aceasta este o indexare înlănțuită. Nu vă recomand să faceți acest lucru. –  > Por cs95.
  • @cs95 Ce ați recomanda în schimb? –  > Por Pedro Lobito.
  • Dacă doriți să faceți acest lucru să funcționeze, apelați df.columns.get_loc pentru a obține poziția de indexare întreagă a coloanei data (în afara buclei), apoi utilizați un singur apel de indexare iloc în interiorul acesteia. –  > Por cs95.
Zach

Uneori, un model util este:

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

Care are ca rezultat:

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

Inginer fără herpes

Pentru a face o buclă cu toate rândurile dintr-un dataframe și folosiți valorile din fiecare rând în mod convenabil, , namedtuples pot fi convertite în ndarrays. De exemplu:

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

Iterarea peste rânduri:

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

are ca rezultat:

[ 1.   0.1]
[ 2.   0.2]

Vă rugăm să rețineți că dacă index=True, , indexul este adăugat ca prim element al tuplei, , ceea ce poate fi nedorit pentru anumite aplicații.

Hossein

Atât pentru vizualizarea, cât și pentru modificarea valorilor, aș folosi iterrows(). Într-o buclă for și prin utilizarea despachetării tuplelor (a se vedea exemplul: i, row), eu folosesc row pentru a vizualiza doar valoarea și folosesc i cu loc atunci când vreau să modific valorile. Așa cum s-a spus în răspunsurile anterioare, aici nu trebuie să modificați ceva peste care iterați.

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

Aici, metoda row din buclă este o copie a acelui rând, și nu o vizualizare a acestuia. Prin urmare, NU ar trebui să scrieți ceva de genul row['A'] = 'New_Value', , nu va modifica DataFrame. Cu toate acestea, puteți utiliza i și loc și să specificați DataFrame pentru a face treaba.

Zeitgeist

Există o modalitate de a itera arunca rânduri în timp ce se obține în schimb un DataFrame, și nu o serie. Nu văd pe nimeni care să menționeze că puteți trece indexul ca o listă pentru ca rândul să fie returnat ca un DataFrame:

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

Observați utilizarea parantezelor duble. Aceasta returnează un DataFrame cu un singur rând.

Comentarii

  • Acest lucru a fost foarte util pentru a obține al n-lea cel mai mare rând dintr-un cadru de date după sortare. Vă mulțumim! –  > Por Jason Harrison.
bug_spray

cs95 arată că vectorizarea Pandas depășește cu mult alte metode Pandas pentru a calcula lucruri cu cadre de date.

Am vrut să adaug că, dacă mai întâi convertiți dataframe-ul într-o serie NumPy și apoi folosiți vectorizarea, este chiar mai rapid decât vectorizarea dataframe-ului Pandas, (și asta include și timpul pentru a o transforma din nou într-o serie de dataframe-uri).

Dacă adăugați următoarele funcții la codul de referință al lui cs95, acest lucru devine destul de evident:

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]

shubham ranjan

Există atât de multe moduri de a itera peste rândurile din dataframe-ul Pandas. Un mod foarte simplu și intuitiv este:

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

artoby

Pe scurt

  • Utilizați vectorizarea dacă este posibil
  • Dacă operațiunea nu poate fi vectorizată – utilizați înțelegerea listelor
  • Dacă aveți nevoie de un singur obiect care să reprezinte un rând întreg – utilizați itertuplele
  • Dacă cele de mai sus sunt prea lente – încercați swifter.apply
  • Dacă este în continuare prea lent – încercați rutina Cython

Reper de referință

François B.

Cel mai simplu mod este să folosiți apply funcția

def print_row(row):
   print row['c1'], row['c2']

df.apply(lambda row: print_row(row), axis=1)

James L.

De asemenea, puteți face indexarea NumPy pentru o viteză și mai mare. Nu este chiar iterație, dar funcționează mult mai bine decât iterația pentru anumite aplicații.

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

Este posibil să doriți, de asemenea, să o transformați într-o matrice. Aceste indexări/selecții ar trebui să se comporte deja ca niște array-uri NumPy, dar am întâmpinat probleme și a trebuit să le transform în array-uri

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

mjr2000

Acest exemplu utilizează iloc pentru a izola fiecare cifră din cadrul de date.

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

morganics

Unele biblioteci (de exemplu, o bibliotecă Java interop pe care o folosesc eu) necesită ca valorile să fie transmise rând pe rând, de exemplu, în cazul transmiterii de date în flux. Pentru a replica natura de streaming, eu „transmit” valorile din cadrul de date unul câte unul, am scris mai jos, ceea ce îmi este util din când în când.

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

Care poate fi folosit:

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

Și păstrează corespondența valori/ nume pentru rândurile care sunt iterate. Evident, este mult mai lent decât utilizarea aplicației și a lui Cython, așa cum se indică mai sus, dar este necesar în anumite circumstanțe.

imanzabet

Împreună cu răspunsurile excelente din acest post, voi propune Divide și învinge abordare, nu scriu acest răspuns pentru a desființa celelalte răspunsuri excelente, ci pentru a le completa cu o altă abordare care a funcționat eficient pentru mine. Aceasta are doi pași de splitting și merging cadrul de date pandas:

PROS de Divide și cucerește:

  • Nu este nevoie să utilizați vectorizarea sau alte metode pentru a transforma tipul de dataframe în alt tip
  • Nu este nevoie să vă cibernetizați codul, ceea ce în mod normal vă ia timp suplimentar.
  • Ambele iterrows() și itertuples() în cazul meu au avut aceeași performanță pe întregul cadru de date.
  • Depinde de alegerea ta de feliere index, veți putea accelera exponențial iterația. Cu cât este mai mare index, , cu atât mai rapid este procesul de iterație.

CONSTANTE ale metodei Divide și cucerește:

  • Nu ar trebui să aveți dependență asupra procesului de iterație pentru același cadru de date și diferite slice. Înseamnă că dacă doriți să citiți sau să scrieți din alte slice, este posibil să fie dificil de făcut acest lucru.

=================== Divide și cucerește abordarea =================

Pasul 1: Împărțirea/împărțirea

În acest pas, vom împărți iterația pe întregul cadru de date. Gândiți-vă că veți citi un fișier csv în pandas df, apoi veți itera peste el. În cazul în care am 5.000.000 de înregistrări și îl voi împărți în 100.000 de înregistrări.

NOTĂ: Trebuie să reiterez ca și alte analize de timp de execuție explicate în celelalte soluții din această pagină, „numărul de înregistrări” are o proporție exponențială de „timp de execuție” la căutarea pe df. Pe baza benchmark-ului pe datele mele, iată rezultatele:

Number of records | Iteration per second
========================================
100,000           | 500 it/s
500,000           | 200 it/s
1,000,000         | 50 it/s
5,000,000         | 20 it/s

Etapa 2: Fuziunea

Acesta va fi un pas ușor, trebuie doar să fuzionați toate fișierele csv scrise într-un singur cadru de date și să le scrieți într-un fișier csv mai mare.

Iată codul de probă:

# Step 1 (Splitting/Slicing)
import pandas as pd
df_all = pd.read_csv('C:/KtV.csv')
df_index = 100000
df_len = len(df)
for i in range(df_len // df_index + 1):
    lower_bound = i * df_index 
    higher_bound = min(lower_bound + df_index, df_len)
    # splitting/slicing df (make sure to copy() otherwise it will be a view
    df = df_all[lower_bound:higher_bound].copy()
    '''
    write your iteration over the sliced df here
    using iterrows() or intertuples() or ...
    '''
    # writing into csv files
    df.to_csv('C:/KtV_prep_'+str(i)+'.csv')



# Step 2 (Merging)
filename='C:/KtV_prep_'
df = (pd.read_csv(f) for f in [filename+str(i)+'.csv' for i in range(ktv_len // ktv_index + 1)])
df_prep_all = pd.concat(df)
df_prep_all.to_csv('C:/KtV_prep_all.csv')

Referință:

Mod eficient de iterație peste datafreame

Concatenarea fișierelor csv într-un singur Dataframe Pandas

JohnE

Așa cum multe răspunsuri de aici subliniază corect și clar, în general nu ar trebui să încercați să faceți bucle în pandas, ci mai degrabă să scrieți cod vectorizat. Dar întrebarea rămâne dacă ar trebui să scrieți NICIODATĂ bucle în pandas și, dacă da, care este cel mai bun mod de a face bucle în aceste situații.

Cred că există cel puțin o situație generală în care buclele sunt adecvate: atunci când trebuie să calculați o funcție care depinde de valorile din alte rânduri într-o manieră oarecum complexă. În acest caz, codul de buclă este adesea mai simplu, mai ușor de citit și mai puțin predispus la erori decât codul vectorizat. Codul în buclă ar putea fi chiar mai rapid, de asemenea.

Voi încerca să arăt acest lucru cu un exemplu. Să presupunem că doriți să faceți o sumă cumulativă a unei coloane, dar să o resetați ori de câte ori o altă coloană este egală cu zero:

import pandas as pd
import numpy as np

df = pd.DataFrame( { 'x':[1,2,3,4,5,6], 'y':[1,1,1,0,1,1]  } )

#   x  y  desired_result
#0  1  1               1
#1  2  1               3
#2  3  1               6
#3  4  0               4
#4  5  1               9
#5  6  1              15

Acesta este un exemplu bun în care ați putea scrie cu siguranță o singură linie de pandas pentru a realiza acest lucru, deși nu este deosebit de ușor de citit, mai ales dacă nu sunteți deja destul de experimentat cu pandas:

df.groupby( (df.y==0).cumsum() )['x'].cumsum()

Acest lucru va fi suficient de rapid pentru majoritatea situațiilor, deși ați putea, de asemenea, să scrieți un cod mai rapid evitând groupby, dar va fi probabil și mai puțin ușor de citit.

Alternativ, ce-ar fi dacă am scrie acest lucru ca o buclă? Ați putea face ceva de genul următor cu numpy:

import numba as nb     

@nb.jit(nopython=True)  # optional
def custom_sum(x,y):
    x_sum = x.copy()
    for i in range(1,len(df)):
        if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]
    return x_sum

df['desired_result'] = custom_sum( df.x.to_numpy(), df.y.to_numpy() )

Desigur, există un pic de supraîncărcare necesară pentru a converti coloanele DataFrame în matrici numpy, dar bucata de cod de bază este doar o singură linie de cod pe care ați putea-o citi chiar dacă nu știți nimic despre pandas sau numpy:

if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]

Și acest cod este de fapt mai rapid decât codul vectorizat. În câteva teste rapide cu 100 000 de rânduri, codul de mai sus este de aproximativ 10 ori mai rapid decât abordarea groupby. Rețineți că o cheie a vitezei de acolo este numba, care este opțiuni. Fără linia „@nb.jit”, codul de buclă este de fapt de aproximativ 10 ori mai lent decât abordarea groupby.

În mod clar, acest exemplu este suficient de simplu încât probabil că veți prefera o singură linie de pandas decât să scrieți o buclă, cu cheltuielile aferente. Cu toate acestea, există versiuni mai complexe ale acestei probleme pentru care lizibilitatea sau viteza abordării cu buclă numpy/numba are probabil sens.

dna-data

De ce nu folosiți df.iloc[] ? De exemplu, folosind dataframe ‘rows_df’ :

ORpentru a obține valorile dintr-un anumit rând, puteți converti dataframe-ul în ndarray.apoi selectați valorile rândului și coloanei astfel

Comentarii

  • Luați în considerare posibilitatea de a nu posta codul în imagini, ci ca text într-un bloc de cod. –  > Por Scratte.