Quel est le meilleur moyen d'appliquer une fonction sur l'indice d'un Pandas DataFrame
??) J'utilise actuellement cette approche verbeuse:
pd.DataFrame({"Month": df.reset_index().Date.apply(foo)})
où Date
est le nom de l'index et foo
est le nom de la fonction que j'applique.
Comme suggéré par HYRY dans les commentaires, Series.map est le chemin à parcourir ici. Il suffit de définir l’index sur la série résultante.
Exemple simple:
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
Comme l'a souligné @OP. l'appel df.index.map(str.lower)
renvoie un tableau numpy. Cela est dû au fait que les index de la base de données sont basés sur des tableaux numpy, et non sur Series.
La seule façon de transformer l’indice en une série est de créer une série à partir de celle-ci.
pd.Series(df.index.map(str.lower))
La classe Index
sous-classe maintenant le StringAccessorMixin
, ce qui signifie que vous pouvez effectuer l'opération ci-dessus comme suit
df.index.str.lower()
Cela produit toujours un objet Index, pas une série.
En supposant que vous souhaitiez créer une colonne dans DataFrame actuel, appliquez votre fonction "foo" à l'index. Tu pourrais écrire ...
df['Month'] = df.index.map(foo)
Pour générer la série seule, vous pouvez plutôt faire ...
pd.Series({x: foo(x) for x in foo.index})
Beaucoup de réponses renvoient l'index sous forme de tableau, ce qui perd des informations sur le nom de l'index, etc. (bien que vous puissiez faire pd.Series(index.map(myfunc), name=index.name)
). Cela ne fonctionnera pas non plus pour un MultiIndex.
La façon dont j'ai travaillé avec ceci est d'utiliser "renommer":
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
La seule astuce, c'est que votre index doit avoir des étiquettes uniques n/b différentes niveaux multi-index, mais peut-être qu'une personne plus intelligente que moi sait comment contourner cela. Pour moi, cela fonctionne 95% du temps.