¿Cuál es la mejor manera de aplicar una función sobre el índice de un Pandas DataFrame
? Actualmente estoy usando este enfoque detallado:
pd.DataFrame({"Month": df.reset_index().Date.apply(foo)})
donde Date
es el nombre del índice y foo
es el nombre de la función que estoy aplicando.
df.index.map(foo)
el trabajo?pd.Series(df.index).apply(foo)
df.index = df.index.map(foo)
Respuestas:
Como ya sugirió HYRY en los comentarios, Series.map es el camino a seguir aquí. Simplemente establezca el índice en la serie resultante.
Ejemplo 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
Índice! = Serie
Como lo señaló @OP. la
df.index.map(str.lower)
llamada devuelve una matriz numpy. Esto se debe a que los índices de marcos de datos se basan en matrices numerosas, no en series.La única forma de convertir el índice en una serie es crear una serie a partir de él.
pd.Series(df.index.map(str.lower))
Consideración
La
Index
clase ahora subclasificaStringAccessorMixin
, lo que significa que puede realizar la operación anterior de la siguiente maneradf.index.str.lower()
Esto todavía produce un objeto Index, no una Serie.
fuente
x[0]
yx[1]
.df.index.map(str.lower)
Suponiendo que desea hacer una columna en su DataFrame actual aplicando su función "foo" al índice. Podrías escribir ...
df['Month'] = df.index.map(foo)
Para generar la serie solo, podría hacer ...
pd.Series({x: foo(x) for x in foo.index})
fuente
Muchas respuestas devuelven el índice como una matriz, que pierde información sobre el nombre del índice, etc. (aunque podría hacerlo
pd.Series(index.map(myfunc), name=index.name)
). Tampoco funcionará para un MultiIndex.La forma en que trabajé con esto es usar "renombrar":
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
El único truco con esto es que su índice debe tener etiquetas únicas en blanco y negro con diferentes niveles de múltiples índices, pero tal vez alguien más inteligente que yo sepa cómo solucionarlo. Para mis propósitos, esto funciona el 95% del tiempo.
fuente
Siempre puede convertir un índice usando su
to_series()
método, y luegoapply
omap
, según sus preferencias / necesidades.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
Todo lo anterior se puede asignar directamente a una columna nueva o existente de
df
:df["column"] = ret
Simplemente para la corrección:
pd.Index.map
,pd.Series.map
ypd.Series.apply
todos funcionan elemento a elemento. A menudo usomap
para aplicar búsquedas representadas pordicts
opd.Series
.apply
es más genérico porque puede pasar cualquier función junto con adicionalargs
okwargs
. Las diferencias entreapply
ymap
se discuten más en este hilo SO . No sé por quépd.Index.apply
se omitió.fuente