在数据框架索引中应用函数

在熊猫 DataFrame的索引上应用函数的最佳方法是什么? Currently I am using this verbose approach:

pd.DataFrame({"Month": df.reset_index().Date.apply(foo)})

其中 Date是索引的名称,foo是我正在应用的函数的名称。

106826 次浏览

正如 HYRY 在评论中已经建议的,系列,地图是这里的方式。只需将索引设置为结果序列即可。

举个简单的例子:

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

索引! = 系列

正如@OP 所指出的,df.index.map(str.lower)调用返回一个 numpy 数组。 This is because dataframe indices based on numpy arrays, not Series.

将索引转换为 Series 的唯一方法是从中创建 Series。

pd.Series(df.index.map(str.lower))

注意

Index类现在是 StringAccessorMixin的子类,这意味着您可以执行以下操作

df.index.str.lower()

这仍然会生成 Index 对象,而不是 Series。

假设您希望通过将函数“ foo”应用于索引,在当前 DataFrame 中创建一个列。你可以写..。

df['Month'] = df.index.map(foo)

要单独生成这个系列,你可以改为..。

pd.Series({x: foo(x) for x in foo.index})

很多答案都以数组的形式返回 Index,这会丢失索引名称等信息(尽管您可以使用 pd.Series(index.map(myfunc), name=index.name))。它也不适用于 MultiIndex。

我处理这个问题的方法是使用“ rename”:

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

唯一的诀窍是你的索引需要有唯一的标签 b/w 不同的多索引级别,但也许有人比我更聪明知道如何绕过这一点。在我看来,这种方法95% 都有效。

您可以使用其 to_series()方法转换索引,然后根据需要转换 applymap

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

All of the above can be assigned directly to a new or existing column of df:

df["column"] = ret

仅仅为了完整性: pd.Series.map2、 pd.Series.map3和 pd.Series.map4都是按照元素操作的。我经常使用 map来应用由 dictspd.Series表示的查找。apply更通用,因为可以传递任何函数以及其他 argskwargs。在 pd.Series.map5中进一步讨论了 applymap之间的差异。我不知道为什么遗漏了 pd.Series.map1。