Was ist der beste Weg, um eine Funktion auf den Index eines Pandas anzuwenden DataFrame
? Derzeit verwende ich diesen ausführlichen Ansatz:
pd.DataFrame({"Month": df.reset_index().Date.apply(foo)})
Wo Date
ist der Name des Index und foo
ist der Name der Funktion, die ich anwende.
df.index.map(foo)
?pd.Series(df.index).apply(foo)
df.index = df.index.map(foo)
Antworten:
Wie bereits von HYRY in den Kommentaren vorgeschlagen, ist Series.map der richtige Weg. Stellen Sie einfach den Index auf die resultierende Reihe ein.
Einfaches Beispiel:
df = pd.DataFrame({'d': [1, 2, 3]}, index=['FOO', 'BAR', 'BAZ']) df d FOO 1 BAR 2 BAZ 3 df.index = df.index.map(str.lower) df d foo 1 bar 2 baz 3
Index! = Serie
Wie von @OP hervorgehoben. Der
df.index.map(str.lower)
Aufruf gibt ein numpy-Array zurück. Dies liegt daran , Dataframe - Indizes werden auf numpy Arrays basieren, nicht - Serie.Die einzige Möglichkeit, den Index in eine Serie umzuwandeln, besteht darin, daraus eine Serie zu erstellen.
Vorbehalt
Die
Index
Klasse unterteilt jetzt dieStringAccessorMixin
, was bedeutet, dass Sie die obige Operation wie folgt ausführen könnenDies erzeugt immer noch ein Indexobjekt, keine Serie.
quelle
x[0]
undx[1]
.df.index.map(str.lower)
Angenommen, Sie möchten eine Spalte in Ihrem aktuellen DataFrame erstellen, indem Sie Ihre Funktion "foo" auf den Index anwenden. Du könntest schreiben ...
df['Month'] = df.index.map(foo)
Um die Serie alleine zu generieren, könnten Sie stattdessen ...
pd.Series({x: foo(x) for x in foo.index})
quelle
Viele Antworten geben den Index als Array zurück, wodurch Informationen über den Indexnamen usw. verloren gehen (obwohl Sie dies tun könnten
pd.Series(index.map(myfunc), name=index.name)
). Es funktioniert auch nicht für einen MultiIndex.Die Art und Weise, wie ich damit gearbeitet habe, ist die Verwendung von "Umbenennen":
mix = pd.MultiIndex.from_tuples([[1, 'hi'], [2, 'there'], [3, 'dude']], names=['num', 'name']) data = np.random.randn(3) df = pd.Series(data, index=mix) print(df) num name 1 hi 1.249914 2 there -0.414358 3 dude 0.987852 dtype: float64 # Define a few dictionaries to denote the mapping rename_dict = {i: i*100 for i in df.index.get_level_values('num')} rename_dict.update({i: i+'_yeah!' for i in df.index.get_level_values('name')}) df = df.rename(index=rename_dict) print(df) num name 100 hi_yeah! 1.249914 200 there_yeah! -0.414358 300 dude_yeah! 0.987852 dtype: float64
Der einzige Trick dabei ist, dass Ihr Index eindeutige Bezeichnungen mit verschiedenen Multiindex-Ebenen haben muss, aber vielleicht weiß jemand, der klüger als ich ist, wie man das umgeht. Für meine Zwecke funktioniert dies in 95% der Fälle.
quelle
Sie können einen Index jederzeit mit seiner
to_series()
Methode konvertieren und dann entwederapply
odermap
entsprechend Ihren Vorlieben / Anforderungen.ret = df.index.map(foo) # Returns pd.Index ret = df.index.to_series().map(foo) # Returns pd.Series ret = df.index.to_series().apply(foo) # Returns pd.Series
Alle oben genannten Punkte können direkt einer neuen oder vorhandenen Spalte zugeordnet werden
df
:df["column"] = ret
Nur der Vollständigkeit halber:
pd.Index.map
,pd.Series.map
undpd.Series.apply
alle arbeiten elementweise. Ich verwende oftmap
Lookups, die durchdicts
oder dargestellt werdenpd.Series
.apply
ist allgemeiner, weil Sie jede Funktion zusammen mit zusätzlichenargs
oder übergeben könnenkwargs
. Die Unterschiede zwischenapply
undmap
werden in diesem SO-Thread weiter erläutert . Ich weiß nicht, warumpd.Index.apply
weggelassen wurde.quelle