Come eseguire l'iterazione su righe in un DataFrame in Panda?


1954

Ho un DataFramepanda:

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

Produzione:

   c1   c2
0  10  100
1  11  110
2  12  120

Ora voglio scorrere le righe di questo frame. Per ogni riga voglio poter accedere ai suoi elementi (valori nelle celle) in base al nome delle colonne. Per esempio:

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

È possibile farlo in Panda?

Ho trovato questa domanda simile . Ma non mi dà la risposta di cui ho bisogno. Ad esempio, si consiglia di utilizzare:

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

o

for row in df.iterrows():

Ma non capisco quale sia l' rowoggetto e come posso lavorarci.


11
Df.iteritems () scorre su colonne e non su righe. Pertanto, per farlo scorrere su righe, devi trasporre (la "T"), il che significa che devi cambiare righe e colonne l'una nell'altra (rifletti sulla diagonale). Di conseguenza, si esegue l'iterazione effettiva del frame di dati originale sulle sue righe quando si utilizza df.T.iteritems ()
Stefan Gruenwald,

12
Se sei nuovo di questo thread e sei un principiante dei panda, NON ITERARE !! L'iterazione sui frame di dati è un anti-pattern e qualcosa che non dovresti fare a meno che tu non voglia abituarti a molte attese. A seconda di ciò che stai cercando di fare, ci sono forse alternative molto migliori . iter*le funzioni dovrebbero essere utilizzate in circostanze molto rare. Anche correlati .
cs95

19
Contrariamente a quanto afferma cs95, ci sono ragioni perfettamente valide per voler iterare su un frame di dati, quindi i nuovi utenti non devono scoraggiarsi. Un esempio è se si desidera eseguire un codice utilizzando i valori di ogni riga come input. Inoltre, se il tuo frame di dati è ragionevolmente piccolo (ad es. Meno di 1000 articoli), le prestazioni non sono realmente un problema.
oulenz,

1
@oulenz: Se per qualche strana ragione vuoi volare di fronte all'utilizzo dell'API per lo scopo per cui è stato progettato (trasformazioni di dati ad alte prestazioni), allora sii mio ospite. Ma almeno, non usare iterrows, ci sono modi migliori di iterare su un DataFrame, potresti anche iterare su un elenco di elenchi a quel punto. Se sei nel punto in cui non stai facendo altro che iterare su DataFrames, non c'è davvero alcun vantaggio nell'usare un DataFrame (supponendo che iterare su di esso sia l'unica cosa che stai facendo con esso). Solo il mio 2c.
cs95,

8
Io secondo @oulenz. Per quanto ne so pandasè la scelta di lettura di un file CSV anche se il set di dati è piccolo. È semplicemente più facile programmare per manipolare i dati con le API
Chris,

Risposte:


2640

DataFrame.iterrows è un generatore che produce sia indice che riga

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
Nota: "Poiché i passaggi precedenti restituiscono una serie per ogni riga, non preserva i tipi di dati tra le righe." Inoltre, "Non dovresti mai modificare qualcosa su cui stai ripetendo". Secondo i panda 0.19.1 docs
viddik13

3
@ viddik13 è un'ottima nota, grazie. Per questo motivo mi sono imbattuto in un caso in cui valori numerici come 431341610650dove letto come 4.31E+11. Esiste un modo per preservare i tipi?
Aziz Alto,

26
@AzizAlto use itertuples, come spiegato di seguito. Vedi anche pandas.pydata.org/pandas-docs/stable/generated/…
Axel

101
Non usare iterrows. Itertuples è più veloce e conserva il tipo di dati. Ulteriori informazioni
James L.,

11
Dalla documentazione : "L'iterazione attraverso gli oggetti Panda è generalmente lenta. In molti casi, non è necessaria l'iterazione manuale sulle righe [...]". La tua risposta è corretta (nel contesto della domanda) ma non ne parla da nessuna parte, quindi non è molto buona.
cs95,

464

Come eseguire l'iterazione su righe in un DataFrame in Panda?

Risposta: NON * !

L'iterazione nei panda è un anti-schema, ed è qualcosa che dovresti fare solo quando hai esaurito ogni altra opzione. Non dovresti usare nessuna funzione con " iter" nel suo nome per più di qualche migliaio di righe o dovrai abituarti a molte attese.

Vuoi stampare un DataFrame? Usa DataFrame.to_string().

Vuoi calcolare qualcosa? In tal caso, cerca i metodi in questo ordine (elenco modificato da qui ):

  1. vettorializzazione
  2. Routine cython
  3. Comprensioni elenco ( forloop vaniglia )
  4. DataFrame.apply(): i) Riduzioni che possono essere eseguite in cython, ii) Iterazione nello spazio pitone
  5. DataFrame.itertuples() e iteritems()
  6. DataFrame.iterrows()

iterrowse itertuples(entrambi ricevendo molti voti in risposta a questa domanda) dovrebbero essere usati in circostanze molto rare, come la generazione di oggetti riga / nametuples per l'elaborazione sequenziale, che è davvero l'unica cosa per cui queste funzioni sono utili.

Ricorso all'Autorità
La pagina dei documenti sull'iterazione ha un enorme riquadro rosso che dice:

L'iterazione attraverso gli oggetti Panda è generalmente lenta. In molti casi, non è necessario scorrere manualmente le righe [...].

* In realtà è un po 'più complicato di "non farlo". df.iterrows()è la risposta corretta a questa domanda, ma "vettorializzare le tue operazioni" è la migliore. Concederò che ci sono circostanze in cui non è possibile evitare l'iterazione (ad esempio, alcune operazioni in cui il risultato dipende dal valore calcolato per la riga precedente). Tuttavia, ci vuole un po 'di familiarità con la biblioteca per sapere quando. Se non sei sicuro di aver bisogno di una soluzione iterativa, probabilmente non lo fai. PS: Per saperne di più sulla mia logica per aver scritto questa risposta, salta in fondo.


Più veloce di Looping: Vettorizzazione , Cython

Un buon numero di operazioni e calcoli di base sono "vettorializzati" dai panda (tramite NumPy o tramite funzioni Cythonized). Ciò include aritmetica, confronti, (la maggior parte) riduzioni, rimodellamento (come il pivot), join e operazioni di groupby. Consulta la documentazione sulla funzionalità di base essenziale per trovare un metodo vettoriale adeguato per il tuo problema.

Se non esiste, sentiti libero di scrivere il tuo usando le estensioni personalizzate di cython .


Prossima cosa migliore: elenchi Comprensioni *

La comprensione dell'elenco dovrebbe essere il prossimo punto di riferimento se 1) non è disponibile una soluzione vettoriale, 2) le prestazioni sono importanti, ma non abbastanza importanti da superare la seccatura del citonizzare il codice e 3) stai cercando di eseguire una trasformazione elementally sul tuo codice. Vi è una buona quantità di prove che suggeriscono che la comprensione dell'elenco è sufficientemente veloce (e talvolta anche più veloce) per molte attività panda comuni.

La formula è semplice,

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

Se è possibile incapsulare la propria logica aziendale in una funzione, è possibile utilizzare una comprensione dell'elenco che la chiama. Puoi far funzionare le cose arbitrariamente complesse attraverso la semplicità e la velocità del raw Python.

Le
comprensioni dell'elenco di avvertenze presuppongono che i tuoi dati siano facili da lavorare: ciò significa che i tuoi tipi di dati sono coerenti e non hai NaN, ma questo non può sempre essere garantito.

  1. Il primo è più ovvio, ma quando si ha a che fare con NaN, preferire i metodi panda incorporati se esistono (perché hanno una logica di gestione dei case ad angolo molto migliore) o assicurarsi che la propria logica aziendale includa la logica di gestione NaN appropriata.
  2. Quando si ha a che fare con tipi di dati misti, è necessario ripetere l'iterazione zip(df['A'], df['B'], ...)anziché eseguire df[['A', 'B']].to_numpy()l'upgrade implicito dei dati al tipo più comune. Ad esempio, se A è numerico e B è stringa, to_numpy()eseguirà il cast dell'intero array su stringa, che potrebbe non essere quello desiderato. Fortunatamente zipeseguire il ping delle colonne insieme è la soluzione più semplice a questo.

* YMMV per i motivi indicati nella sezione Avvertenze sopra.


Un esempio ovvio

Dimostriamo la differenza con un semplice esempio di aggiunta di due colonne di panda A + B. Questa è un'operazione vettoriale, quindi sarà facile contrastare le prestazioni dei metodi discussi sopra.

inserisci qui la descrizione dell'immagine

Codice di benchmarking, per riferimento.

Devo dire, tuttavia, che non è sempre così secco e asciutto. A volte la risposta a "qual è il metodo migliore per un'operazione" è "dipende dai tuoi dati". Il mio consiglio è di testare diversi approcci sui dati prima di stabilirne uno.


Ulteriori letture

* I metodi stringa Pandas sono "vettorializzati", nel senso che sono specificati sulla serie ma operano su ciascun elemento. I meccanismi sottostanti sono ancora iterativi, poiché le operazioni sulle stringhe sono intrinsecamente difficili da vettorializzare.


Perché ho scritto questa risposta

Una tendenza comune che noto ai nuovi utenti è quella di porre domande nel modulo "come posso iterare sul mio df per fare X?". Mostra il codice che chiama iterrows()mentre si fa qualcosa all'interno di un ciclo for. Ecco perché. Un nuovo utente della biblioteca che non è stato introdotto al concetto di vettorializzazione probabilmente immaginerà il codice che risolve il loro problema mentre scorre i propri dati per fare qualcosa. Non sapendo come scorrere un DataFrame, la prima cosa che fanno è Google e finire qui, a questa domanda. Vedono quindi la risposta accettata che dice loro come fare e chiudono gli occhi ed eseguono questo codice senza mai prima interrogarsi se l'iterazione non è la cosa giusta da fare.

Lo scopo di questa risposta è aiutare i nuovi utenti a capire che l'iterazione non è necessariamente la soluzione per ogni problema e che potrebbero esistere soluzioni migliori, più veloci e più idiomatiche, e che vale la pena dedicare tempo a esplorarle. Non sto cercando di iniziare una guerra di iterazione contro la vettorializzazione, ma voglio che i nuovi utenti siano informati quando sviluppano soluzioni ai loro problemi con questa libreria.


24
Questa è l'unica risposta che si concentra sulle tecniche idiomatiche che si dovrebbero usare con i panda, rendendola la migliore risposta a questa domanda. Imparare a ottenere la risposta giusta con il codice giusto (invece della risposta giusta con il codice sbagliato - cioè inefficiente, non scalabile, troppo adatto a dati specifici) è una parte importante dell'apprendimento dei panda (e dei dati in generale).
LinkBerest,

3
Penso che tu sia ingiusto con il ciclo for, però, visto che sono solo un po 'più lenti della comprensione dell'elenco nei miei test. Il trucco è ricorrere al loop zip(df['A'], df['B'])anziché df.iterrows().
Imperishable Night,

2
@ImperishableNight Assolutamente no; lo scopo di questo post non è denunciare l'iterazione in generale, ma denunciare in modo specifico l'uso iterrows()e denunciare implicitamente l'iterazione se e quando esistono alternative migliori. fori loop da soli sono OK, ma le comprensioni degli elenchi sono migliori se si eseguono in modo iterativo trasformazioni basate su elementi.
cs95,

1
@sdbbs c'è, usa sort_values ​​per ordinare i tuoi dati, quindi chiama to_string () sul risultato.
cs95,

1
In Comprensioni elenco, l'esempio "iterando su più colonne" richiede un avvertimento: DataFrame.valuesconvertirà ogni colonna in un tipo di dati comune. DataFrame.to_numpy()fa anche questo. Fortunatamente possiamo usare zipcon qualsiasi numero di colonne.
David Wasserman,

397

Innanzitutto considera se hai davvero bisogno di iterare su righe in un DataFrame. Vedi questa risposta per alternative.

Se è ancora necessario scorrere le righe, è possibile utilizzare i metodi seguenti. Nota alcune avvertenze importanti che non sono menzionate in nessuna delle altre risposte.

itertuples() dovrebbe essere più veloce di iterrows()

Ma attenzione, secondo i documenti (panda 0.24.2 al momento):

  • iterrows: dtypepotrebbe non corrispondere da una riga all'altra

    Dato che in precedenza restituisce una serie per ogni riga, non conserva i dtype tra le righe (i dtype vengono conservati tra le colonne per DataFrames). Per preservare i dtype durante l'iterazione sulle righe, è meglio usare itertuples () che restituisce le nametuple dei valori e che è generalmente molto più veloce di iterrows ()

  • iterrows: non modificare le righe

    Non dovresti mai modificare qualcosa su cui stai ripetendo. Questo non è garantito per funzionare in tutti i casi. A seconda dei tipi di dati, l'iteratore restituisce una copia e non una vista e la scrittura su di essa non avrà alcun effetto.

    Utilizzare invece DataFrame.apply () :

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

    I nomi delle colonne verranno rinominati in nomi posizionali se sono identificatori Python non validi, ripetuti o iniziano con un carattere di sottolineatura. Con un numero elevato di colonne (> 255), vengono restituite tuple regolari.

Vedi i documenti di Panda sull'iterazione per maggiori dettagli.


4
Solo una piccola domanda da qualcuno che legge questo thread così a lungo dopo il suo completamento: come df.apply () si confronta con itertuples in termini di efficienza?
Raul Guarini,

4
Nota: puoi anche dire qualcosa come for row in df[['c1','c2']].itertuples(index=True, name=None):includere solo determinate colonne nell'iteratore di righe.
Brian Burns,

12
Invece di getattr(row, "c1"), puoi usare solo row.c1.
viraptor,

1
Sono sicuro al 90% che se si utilizza getattr(row, "c1")invece di row.c1, si perde qualsiasi vantaggio prestazionale di itertuples, e se in realtà è necessario raggiungere la proprietà tramite una stringa, è necessario utilizzare invece iterrows.
Noctiphobia,

3
Mi sono imbattuto in questa domanda perché, sebbene sapessi che esiste una divisione-applica-combina, avevo ancora davvero bisogno di iterare su un DataFrame (come afferma la domanda). Non tutti hanno il lusso di migliorare numbae cython(gli stessi documenti dicono che "Vale sempre la pena ottimizzare prima in Python"). Ho scritto questa risposta per aiutare gli altri a evitare problemi (a volte frustranti) poiché nessuna delle altre risposte menziona questi avvertimenti. Indurre in errore chiunque o dire "è la cosa giusta da fare" non è mai stata mia intenzione. Ho migliorato la risposta.
viddik13,

201

Si dovrebbe usare df.iterrows(). Sebbene l'iterazione riga per riga non sia particolarmente efficiente poiché Seriesè necessario creare oggetti.


12
È più veloce della conversione di DataFrame in un array numpy (tramite .values) e di operare direttamente sull'array? Ho lo stesso problema, ma ho finito con la conversione in una matrice numpy e poi usando cython.
vgoklani,

12
@vgoklani Se l'iterazione riga per riga è inefficiente e si dispone di un array numpy non oggetto, quasi sicuramente l'utilizzo dell'array numpy grezzo sarà più veloce, specialmente per array con molte righe. dovresti evitare di scorrere le righe a meno che non sia assolutamente necessario
Phillip Cloud,

7
Ho fatto un po 'di test sul consumo di tempo per df.iterrows (), df.itertuples () e zip (df [' a '], df [' b ']) e ho pubblicato il risultato nella risposta di un altro domanda: stackoverflow.com/a/34311080/2142098
Richard Wong,

154

Mentre iterrows()è una buona opzione, a volte itertuples()può essere molto più veloce:

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
Gran parte della differenza di tempo nei tuoi due esempi sembra dovuta al fatto che sembra che tu stia utilizzando l'indicizzazione basata su etichette per il comando .iterrows () e l'indicizzazione basata su numeri interi per il comando .itertuples ().
Alex,

2
Per un dataframe basato su dati finanziari (timestamp e 4x float), itertuples è 19,57 volte più veloce di quello che si verifica sulla mia macchina. Solo for a,b,c in izip(df["a"],df["b"],df["c"]:è quasi altrettanto veloce.
Harbun,

7
Puoi spiegare perché è più veloce?
Abe Miessler,

4
@AbeMiessler iterrows()inscatola ogni riga di dati in una serie, mentre itertuples()non lo fa.
miradulo,

3
Si noti che l'ordine delle colonne è in realtà indeterminato, perché dfè stato creato da un dizionario, quindi row[1]potrebbe riferirsi a una qualsiasi delle colonne. Come risulta però i tempi sono all'incirca gli stessi per le colonne intere e float.
Brian Burns,

88

È inoltre possibile utilizzare df.apply()per scorrere le righe e accedere a più colonne per una funzione.

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)

Il df ['prezzo'] si riferisce al nome di una colonna nel frame di dati? Sto cercando di creare un dizionario con valori univoci da diverse colonne in un file CSV. Ho usato la tua logica per creare un dizionario con chiavi e valori univoci e ho ricevuto un errore che indicava TypeError: ("Gli oggetti 'Serie' sono mutabili, quindi non possono essere sottoposti a hash", u'occors all'indice 0 ')
SRS

Codice: df ['Workclass'] = df.apply (riga lambda: dic_update (riga), asse = 1) end of line id = 0 end of line def dic_update (row): se la riga non è in dic: dic [row] = id id = id + 1
SRS

Non importa, ho capito. Modificata la linea di chiamata della funzione in df_new = df ['Workclass']. Apply (stessa cosa)
SRS

2
Avere l'asse predefinito su 0 è il peggiore
zthomas.nc,

9
Si noti che applynon "iteratite" su righe, piuttosto applica una funzione per riga. Il codice di cui sopra non funzionerebbe se davvero fai iterazioni necessità e indici, per esempio quando si confrontano i valori in diversi file (in questo caso si può fare nulla, ma l'iterazione).
gented

82

È possibile utilizzare la funzione df.iloc come segue:

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

1
So che si dovrebbe evitare questo a favore di iterrows o itertuples, ma sarebbe interessante sapere perché. qualche idea?
rocarvaj,

12
Questa è l'unica tecnica valida che conosco se si desidera preservare i tipi di dati e fare riferimento anche alle colonne per nome. itertuplesconserva i tipi di dati, ma elimina qualsiasi nome non gli piaccia. iterrowsfa il contrario.
Ken Williams,

6
Ho passato ore a cercare di superare le idiosincrasie delle strutture di dati dei panda per fare qualcosa di semplice ed espressivo. Ciò si traduce in un codice leggibile.
Sean Anderson,

Mentre for i in range(df.shape[0])potrebbe accelerare un po 'questo approccio, è ancora circa 3,5 volte più lento dell'approccio iterrows () sopra per la mia applicazione.
Kim Miller,

Su Datafrmes di grandi dimensioni questo sembra migliore in quanto my_iter = df.itertuples()richiede il doppio della memoria e un sacco di tempo per copiarlo. lo stesso per iterrows().
Bastiaan,

33

Stavo cercando Come iterare su righe e colonne e sono finito qui così:

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

18

Puoi scrivere il tuo iteratore che implementa 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)

Questo è direttamente paragonabile a pd.DataFrame.itertuples. Sto mirando a svolgere lo stesso compito con maggiore efficienza.


Per il dato frame di dati con la mia funzione:

list(myiter(df))

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

O con 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 completo
Proviamo a rendere disponibili tutte le colonne e a sottoimpostarle.

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

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


2
Per le persone che non vogliono leggere il codice: la linea blu è intertuples, la linea arancione è un elenco di un iteratore attraverso un blocco di rendimento. interrowsnon è confrontato.
James L.,

18

Come iterare in modo efficiente?

Se devi davvero iterare un frame di dati Panda, probabilmente vorrai evitare di usare iterrows () . Esistono diversi metodi e il solito iterrows()è lungi dall'essere il migliore. itertuples () può essere 100 volte più veloce.

In breve:

  • Come regola generale, utilizzare df.itertuples(name=None). In particolare, quando hai un numero fisso di colonne e meno di 255 colonne. Vedi punto (3)
  • Altrimenti, usa df.itertuples()tranne se le tue colonne hanno caratteri speciali come spazi o '-'. Vedi punto (2)
  • È possibile utilizzare itertuples()anche se il tuo frame di dati ha strane colonne usando l'ultimo esempio. Vedi punto (4)
  • Utilizzare solo iterrows()se non è possibile utilizzare le soluzioni precedenti. Vedi punto (1)

Metodi diversi per scorrere le righe in un frame di dati Panda:

Genera un frame di dati casuale con un milione di righe e 4 colonne:

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

1) Il solito iterrows()è comodo ma dannatamente lento:

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) L'impostazione predefinita itertuples()è già molto più veloce ma non funziona con nomi di colonna come My Col-Name is very Strange(dovresti evitare questo metodo se le tue colonne vengono ripetute o se un nome di colonna non può essere semplicemente convertito in un nome di variabile 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) L'impostazione predefinita itertuples()usando name = None è ancora più veloce ma non molto conveniente in quanto devi definire una variabile per colonna.

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) Infine, il nome itertuples()è più lento del punto precedente ma non è necessario definire una variabile per colonna e funziona con nomi di colonna come 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))

Produzione:

         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

Questo articolo è un confronto molto interessante tra iterrows e itertuples


14

Per dataframeeseguire il loop di tutte le righe in un è possibile utilizzare:

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

1
Si tratta di indicizzazione concatenata. Non consiglio di farlo.
cs95,

@ cs95 Cosa consiglieresti invece?
CONvid19,

Se vuoi farlo funzionare, chiama df.columns.get_loc per ottenere la posizione dell'indice intero della colonna della data (fuori dal ciclo), quindi usa una singola chiamata di indicizzazione iloc all'interno.
cs95,

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

1
come sono le prestazioni di questa opzione se utilizzata su un grande dataframe (ad esempio milioni di righe)?
Bazyli Debowski,

Onestamente, non lo so esattamente, penso che rispetto alla migliore risposta, il tempo trascorso sarà più o meno lo stesso, perché entrambi i casi usano la costruzione "per". Ma la memoria potrebbe essere diversa in alcuni casi.
Grag2015,

4
Si tratta di indicizzazione concatenata. Non usare questo!
cs95,

7

A volte un modello utile è:

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

Che si traduce in:

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

6

Per eseguire il ciclo continuo di tutte le righe in a dataframee utilizzare i valori di ogni riga in modo conveniente , è namedtuplespossibile convertire in ndarrays. Per esempio:

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

Iterando sulle righe:

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

risulta in:

[ 1.   0.1]
[ 2.   0.2]

Si noti che se index=True, l'indice viene aggiunto come primo elemento della tupla , che possono essere indesiderabili per alcune applicazioni.


5

C'è un modo per iterare le righe di lancio mentre si ottiene in cambio un DataFrame e non una serie. Non vedo nessuno menzionare che è possibile passare l'indice come un elenco per la riga da restituire come DataFrame:

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

Nota l'uso di doppie parentesi. Ciò restituisce un DataFrame con una singola riga.


Ciò è stato molto utile per ottenere l'ennesima riga più grande in un frame di dati dopo l'ordinamento. Grazie!
Jason Harrison,

3

Per visualizzare e modificare i valori, vorrei usare iterrows(). In un ciclo for e usando il disimballaggio della tupla (vedi l'esempio:) i, row, uso rowsolo per visualizzare il valore e uso icon il locmetodo quando voglio modificare i valori. Come indicato nelle risposte precedenti, qui non è necessario modificare qualcosa su cui si sta ripetendo.

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

Qui il rownel ciclo è una copia di quella riga, e non una sua vista. Pertanto, NON dovresti scrivere qualcosa del genere row['A'] = 'New_Value', non modificherà il DataFrame. Tuttavia, è possibile utilizzare ie locspecificare DataFrame per eseguire il lavoro.


2

So di essere in ritardo per la risposta, ma volevo solo aggiungere la risposta di @ cs95 sopra, che credo dovrebbe essere la risposta accettata. Nella sua risposta, mostra che la vettorializzazione dei panda supera di gran lunga altri metodi di panda per il calcolo di cose con i frame di dati.

Volevo aggiungere che se prima converti il ​​frame di dati in un array numpy e poi usi la vettorializzazione, è anche più veloce della vettorializzazione di dataframe panda (e questo include il tempo per trasformarlo in una serie di frame di dati).

Se aggiungi le seguenti funzioni al codice di riferimento di @ cs95, questo diventa abbastanza evidente:

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]

inserisci qui la descrizione dell'immagine


1

Puoi anche eseguire l' numpyindicizzazione per accelerazioni ancora maggiori. Non è realmente iterativo ma funziona molto meglio dell'iterazione per alcune applicazioni.

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

Puoi anche lanciarlo su un array. Si presume che questi indici / selezioni si comportino già come matrici Numpy, ma ho riscontrato problemi e ho dovuto eseguire il cast

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

1

Esistono molti modi per scorrere le righe nel frame di dati Panda. Un modo molto semplice ed intuitivo è:

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

Questo esempio usa iloc per isolare ogni cifra nel frame di dati.

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

Alcune librerie (ad es. Una libreria di interoperabilità Java che utilizzo) richiedono che i valori vengano passati in una riga alla volta, ad esempio se si trasmettono dati in streaming. Per replicare la natura dello streaming, eseguo lo "streaming" dei valori dei miei frame di dati uno per uno, ho scritto quanto segue, che di tanto in tanto è utile.

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

Quale può essere usato:

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

E conserva la mappatura dei valori / nomi per le righe da iterare. Ovviamente, è molto più lento rispetto all'utilizzo di apply e Cython come indicato sopra, ma è necessario in alcune circostanze.


0

In breve

  • Usa la vettorializzazione se possibile
  • Se l'operazione non può essere vettorializzata, utilizzare la comprensione dell'elenco
  • Se hai bisogno di un singolo oggetto che rappresenti l'intera riga, usa itertuples
  • Se quanto sopra è troppo lento, prova swifter.apply
  • Se è ancora troppo lento, prova la routine Cython

Dettagli in questo video

Prova delle prestazioni Benchmark dell'iterazione su righe in un DataFrame di Panda

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.