2014-04-28 22 views
61

Ho un frame di dati panda che assomiglia a questo (la sua una bella grande)Aggiornamento un dataframe in panda, mentre l'iterazione riga per riga

  date  exer exp  ifor   mat 
1092 2014-03-17 American M 528.205 2014-04-19 
1093 2014-03-17 American M 528.205 2014-04-19 
1094 2014-03-17 American M 528.205 2014-04-19 
1095 2014-03-17 American M 528.205 2014-04-19  
1096 2014-03-17 American M 528.205 2014-05-17 

ora vorrei per scorrere riga per riga e come vado attraverso ogni riga, il valore di ifor in ogni riga può cambiare in base ad alcune condizioni e ho bisogno di cercare un altro dataframe.

Ora, come si aggiorna mentre si itera. Ho provato alcune cose che nessuno di loro ha funzionato.

for i, row in df.iterrows(): 
    if <something>: 
     row['ifor'] = x 
    else: 
     row['ifor'] = y 

    df.ix[i]['ifor'] = x 

Nessuno di questi approcci sembra funzionare. Non vedo i valori aggiornati nel dataframe.

+1

Penso che si desidera 'df.ix [i, 'IFOR']'. 'df.ix [i] ['ifor']' è problematico perché è indicizzato a catena (che non è affidabile nei panda). –

+0

Potete fornire l'altro frame e il ''. Se il tuo codice può essere vettorializzato dipenderà da queste cose. In generale, evita 'iterrows'. Nel tuo caso, dovresti * sicuramente * evitarlo poiché ogni riga sarà un 'oggetto' dtype 'Serie'. –

+0

Sarebbe meglio creare una maschera booleana per la condizione, aggiornare tutte quelle righe e quindi impostare il resto sull'altro valore – EdChum

risposta

10

È necessario assegnare il valore df.ix[i, 'exp']=X o df.loc[i, 'exp']=X anziché df.ix[i]['ifor'] = x.

In caso contrario si sta lavorando su una visione, e dovrebbe ottenere un riscaldamento:

-c:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead

Ma certamente, ciclo probabilmente dovrebbe meglio essere sostituito da qualche algoritmo vettorializzare per fare il pieno utilizzo di DataFrame come @Phillip Cloud suggerito.

66

È possibile assegnare i valori nel ciclo utilizzando df.set_value:

for i, row in df.iterrows(): 
    ifor_val = something 
    if <condition>: 
    ifor_val = something_else 
    df.set_value(i,'ifor',ifor_val) 

se non è necessario i valori di riga si può semplicemente effettuare un'iterazione sugli indici di df, ma ho mantenuto la for-loop originale nel caso in cui hai bisogno del valore di riga per qualcosa non mostrato qui.

+3

Vedere http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame .iterrows.html, secondo punto: "Non si dovrebbe mai modificare qualcosa che si sta iterando" –

+13

Non sono sicuro che lo si legge esattamente nello stesso modo. Se si guarda nel mio pseudo codice, faccio la modifica sul dataframe, non sul valore dall'iteratore. Il valore iteratore viene utilizzato solo per l'indice del valore/oggetto. Quello che fallirà è row ['ifor'] = some_thing, per le ragioni menzionate nella documentazione. – rakke

+1

Grazie per il chiarimento. –

5

Un metodo che è possibile utilizzare è itertuples(), itera su righe DataFrame come namedtuples, con valore di indice come primo elemento della tupla. Ed è molto più veloce rispetto a iterrows(). Per itertuples(), ogni row contiene il suo Index nel DataFrame ed è possibile utilizzare loc per impostare il valore.

for row in df.itertuples(): 
    if <something>: 
     df.loc[row.Index, 'ifor'] = x 
    else: 
     df.loc[row.Index, 'ifor'] = x 

    df.loc[row.Index, 'ifor'] = x 
2

Pandas DataFrame oggetto deve essere pensato come una serie di serie. In altre parole, dovresti pensarci in termini di colonne. Il motivo per cui questo è importante è perché quando si utilizza pd.DataFrame.iterrows si sta iterando attraverso le righe come Serie. Ma questi sono non la serie che il frame di dati sta memorizzando e quindi sono nuove serie che vengono create per te durante l'iterazione. Ciò implica che quando si tenta di assegnarli, tali modifiche non si rifletteranno nel frame di dati originale.

Ok, ora che è fuori strada: cosa facciamo?

Suggerimenti prima di questo post sono:

  1. pd.DataFrame.set_value è deprecated as of Pandas version 0.21
  2. pd.DataFrame.ix è deprecated
  3. pd.DataFrame.loc va bene, ma can work on array indexers e si può fare meglio

mia raccomandazione.210 Usa pd.DataFrame.at

for i in df.index: 
    if <something>: 
     df.at[i, 'ifor'] = x 
    else: 
     df.at[i, 'ifor'] = y 

Si può anche cambiare questo:

for i in df.index: 
    df.at[i, 'ifor'] = x if <something> else y 
0
for i, row in df.iterrows(): 
    if <something>: 
     df.at[i, 'ifor'] = x 
    else: 
     df.at[i, 'ifor'] = y 
Problemi correlati