Ich habe ein DataFrame
von Pandas:
import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df
Ausgabe:
c1 c2
0 10 100
1 11 110
2 12 120
Jetzt möchte ich die Zeilen dieses Frames durchlaufen. Für jede Zeile möchte ich über den Namen der Spalten auf deren Elemente (Werte in Zellen) zugreifen können. Zum Beispiel:
for row in df.rows:
print row['c1'], row['c2']
Ist das bei Pandas möglich?
Ich fand das ähnliche Frage . Aber es gibt mir nicht die Antwort, die ich brauche. Beispielsweise wird dort empfohlen, Folgendes zu verwenden:
for date, row in df.T.iteritems():
oder
for row in df.iterrows():
Aber ich verstehe nicht, was das Objekt row
ist und wie ich damit arbeiten kann.
DataFrame.iterrows ist ein Generator, der sowohl Index als auch Zeile liefert
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
Überlegen Sie zunächst, ob Sie wirklich über Zeilen in einem DataFrame iterieren müssen . Siehe diese Antwort für Alternativen.
Wenn Sie immer noch über Zeilen iterieren müssen, können Sie die folgenden Methoden verwenden. Beachten Sie einige wichtige Vorsichtsmaßnahmen , die in keiner der anderen Antworten erwähnt werden.
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()
soll schneller sein als iterrows()
Beachten Sie jedoch laut Dokumentation (Pandas 0.24.2 im Moment):
iterrows: dtype
stimmt möglicherweise nicht von Zeile zu Zeile überein
Da iterrows für jede Zeile eine Reihe zurückgibt, werden keine D-Typen in den Zeilen beibehalten (D-Typen werden in den Spalten für DataFrames beibehalten). Um dtypes beim Durchlaufen der Zeilen beizubehalten, ist es besser, itertuples () zu verwenden, die namedtuples der Werte zurückgeben und die im Allgemeinen viel schneller sind als iterrows ().
iterrows: Ändern Sie keine Zeilen
Sie sollten niemals etwas ändern , worüber Sie iterieren. Es ist nicht garantiert, dass dies in allen Fällen funktioniert. Abhängig von den Datentypen gibt der Iterator eine Kopie und keine Ansicht zurück, und das Schreiben darauf hat keine Auswirkung.
Verwenden Sie stattdessen DataFrame.apply () :
new_df = df.apply(lambda x: x * 2)
itertupel:
Die Spaltennamen werden in Positionsnamen umbenannt, wenn sie ungültige Python Bezeichner sind, wiederholt werden oder mit einem Unterstrich beginnen. Bei einer großen Anzahl von Spalten (> 255) werden reguläre Tupel zurückgegeben.
Siehe Pandas-Dokumentation zur Iteration für weitere Einzelheiten.
Sie sollten df.iterrows()
verwenden. Die zeilenweise Iteration ist jedoch nicht besonders effizient, da Serienobjekte erstellt werden müssen.
Während iterrows()
eine gute Option ist, kann itertuples()
manchmal viel schneller sein:
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
Wie kann ich in Pandas über Zeilen in einem DataFrame iterieren?
Die Iteration in pandas ist ein Anti-Pattern. Dies sollten Sie nur tun, wenn Sie alle anderen Möglichkeiten ausgeschöpft haben. Sie sollten keine Funktion mit "iter
" im Namen für mehr als ein paar tausend Zeilen in Betracht ziehen, sonst müssen Sie sich an eine Menge des Wartens gewöhnen .
Möchten Sie einen DataFrame drucken? Verwenden Sie DataFrame.to_string()
.
Möchten Sie etwas berechnen? Suchen Sie in diesem Fall nach Methoden in dieser Reihenfolge (Liste geändert von hier ):
for
Schleife)DataFrame.apply()
: i) Reduzierungen, die in Cython durchgeführt werden können, ii) Iteration im Raum pythonDataFrame.itertuples()
und iteritems()
DataFrame.iterrows()
iterrows
und itertuples
(beide erhalten viele Stimmen bei der Beantwortung dieser Frage) sollten in sehr seltenen Fällen verwendet werden, z nützlich zum.
Appell an die Behörde
Die Dokumentseite bei Iteration hat ein riesiges rotes Warnfeld mit der Aufschrift:
Das Durchlaufen von pandas Objekten ist im Allgemeinen langsam. In vielen Fällen ist es nicht erforderlich, manuell über die Zeilen zu iterieren [...].
Eine gute Anzahl grundlegender Operationen und Berechnungen werden von pandas "vektorisiert" (entweder durch NumPy oder durch cythonisierte Funktionen). Dies umfasst Arithmetik, Vergleiche, (die meisten) Verkleinerungen, Umformen (wie z. B. Schwenken), Verknüpfungen und Groupby-Operationen. Durchsuchen Sie die Dokumentation zu Essential Basic Functionality , um eine geeignete vektorisierte Methode für Ihr Problem zu finden.
Wenn es keine gibt, können Sie Ihre eigenen mit custom Cython-Erweiterungen schreiben.
Listenverständnisse sollten Ihre nächste Anlaufstelle sein, wenn 1) keine vektorisierte Lösung verfügbar ist, 2) die Leistung wichtig, aber nicht wichtig genug ist, um den Aufwand für die Cythonisierung Ihres Codes zu bewältigen, und 3) Sie versuchen, eine elementweise Transformation durchzuführen auf Ihrem Code. Es gibt ein eine gute Menge an Beweisen , um darauf hinzuweisen, dass das Listenverständnis für viele gängige pandas Aufgaben ausreichend schnell (und manchmal sogar schneller) ist.
Die Formel ist einfach,
# 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]
Wenn Sie Ihre Geschäftslogik in eine Funktion einkapseln können, können Sie ein Listenverständnis verwenden, das sie aufruft. Durch die Einfachheit und Geschwindigkeit von Raw Python können Sie beliebig komplexe Dinge zum Funktionieren bringen.
Lassen Sie uns den Unterschied anhand eines einfachen Beispiels demonstrieren, bei dem zwei pandas Spalten A + B
hinzugefügt werden. Dies ist eine vektorisierbare Operation, so dass es leicht ist, die Leistung der oben diskutierten Methoden gegenüberzustellen.
Referenzcode zu Ihrer Information
Ich sollte jedoch erwähnen, dass es nicht immer so geschnitten und trocken ist. Manchmal lautet die Antwort auf "Was ist die beste Methode für eine Operation?" "Es hängt von Ihren Daten ab." Mein Rat ist, verschiedene Ansätze für Ihre Daten zu testen, bevor Sie sich für einen entscheiden.
10 Minuten zu Pandas und Grundlegende Funktionalität - Nützliche Links, die Sie in pandas und seine Bibliothek von vektorisierten */cythonisierten Funktionen einführen.
Enhancing Performance - Ein Leitfaden aus den Dokumenten zur Verbesserung der Standardoperationen pandas
Sind for-Schleifen in pandas wirklich schlecht? Wann sollte es mich interessieren? - Eine ausführliche Beschreibung meiner Listenverständnisse und ihrer Eignung für verschiedene Operationen (hauptsächlich mit nicht numerischen Daten) )
Wann sollte ich jemals pandas apply () in meinem Code verwenden wollen? - apply
ist langsam (aber jetzt so langsam wie die iter*
-Familie. Es gibt jedoch Situationen, in denen man apply
als Serienalternative betrachten kann (oder sollte), insbesondere in einigen GroupBy
Operationen).
* Pandas Zeichenfolgenmethoden werden in dem Sinne "vektorisiert", dass sie in der Reihe angegeben sind, jedoch auf jedes Element angewendet werden. Die zugrunde liegenden Mechanismen sind immer noch iterativ, da Zeichenfolgenoperationen von Natur aus schwer zu vektorisieren sind.
Sie können auch df.apply()
verwenden, um Zeilen zu durchlaufen und auf mehrere Spalten für eine Funktion zuzugreifen.
def valuation_formula(x, y):
return x * y * 0.5
df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
Sie können die Funktion df.iloc wie folgt verwenden:
for i in range(0, len(df)):
print df.iloc[i]['c1'], df.iloc[i]['c2']
Ich suchte nach Wie man Zeilen UND Spalten durchläuft und endete hier so:
for i, row in df.iterrows():
for j, column in row.iteritems():
print(column)
Sie können Ihren eigenen Iterator schreiben, der namedtuple
implementiert.
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)
Dies ist direkt vergleichbar mit pd.DataFrame.itertuples
. Ich möchte die gleiche Aufgabe effizienter erledigen.
Für den angegebenen Datenrahmen mit meiner Funktion:
list(myiter(df))
[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]
Oder mit pd.DataFrame.itertuples
:
list(df.itertuples(index=False))
[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]
Ein umfassender Test
Wir testen, ob alle Spalten verfügbar sind und ob die Spalten untergeordnet sind.
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);
Um alle Zeilen in einem dataframe
zu schleifen, können Sie Folgendes verwenden:
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]
Manchmal ist ein nützliches Muster:
# 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)
Was in ... endet:
{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}
Um alle Zeilen einer dataframe
und verwenden Werte jeder Zeile bequemerweise zu durchlaufen, kann namedtuples
in ndarray
s konvertiert werden. Zum Beispiel:
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
Iterieren über die Zeilen:
for row in df.itertuples(index=False, name='Pandas'):
print np.asarray(row)
ergebnisse in:
[ 1. 0.1]
[ 2. 0.2]
Beachten Sie, dass bei index=True
, der Index wird als erstes Element des Tupels hinzugefügt, was für einige Anwendungen unerwünscht sein kann.
Zum Anzeigen und Ändern von Werten würde ich iterrows()
verwenden. In einer for-Schleife und unter Verwendung des Tupel-Entpackens (siehe Beispiel: i, row
) verwende ich row
, um nur den Wert anzuzeigen, und verwende i
mit der loc
-Methode, wenn Ich möchte Werte ändern. Wie in den vorherigen Antworten angegeben, sollten Sie hier nichts ändern, worüber Sie iterieren.
for i, row in df.iterrows():
if row['A'] == 'Old_Value':
df.loc[i,'A'] = 'New_value'
Hier ist das row
in der Schleife eine Kopie dieser Zeile und keine Ansicht davon. Daher sollten Sie NICHT so etwas wie row['A'] = 'New_Value'
schreiben, da dies den DataFrame nicht verändert. Sie können jedoch i
und loc
verwenden und den DataFrame angeben, der die Arbeit erledigt.
Sie können auch numpy
indizieren, um eine noch höhere Geschwindigkeit zu erzielen. Es iteriert nicht wirklich, funktioniert aber für bestimmte Anwendungen viel besser als Iteration.
subset = row['c1'][0:5]
all = row['c1'][:]
Sie können es auch in ein Array umwandeln. Diese Indizes/Auswahlen sollen sich bereits wie Numpy-Arrays verhalten, aber ich bin auf Probleme gestoßen und musste sie besetzen
np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file
Warum komplizieren die Dinge?
Einfach.
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']
Es gibt so viele Möglichkeiten, die Zeilen in pandas Datenrahmen zu durchlaufen. Ein sehr einfacher und intuitiver Weg ist:
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]])
In diesem Beispiel wird iloc verwendet, um jede Ziffer im Datenrahmen zu isolieren.
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])