web-dev-qa-db-fra.com

Appliquer une fonction sur l'index DataFrame

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

Date est le nom de l'index et foo est le nom de la fonction que j'applique.

58
Alex Rothberg

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

Index! = Série

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

Caveat

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.

74
firelynx

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})
7
suraj747

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.

3
choldgraf