在DataFrame索引上应用功能


79

在Pandas的索引上应用函数的最佳方法是什么DataFrame?目前,我正在使用这种冗长的方法:

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

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


6
df.index.map(foo)工作?
HYRY 2013年

1
它“有效”,但是它返回一个numpy数组而不是Pandas Series。
Alex Rothberg 2013年

1
您的最终目标是什么?您可以将数组传递给DataFrame构造函数。或执行类似操作pd.Series(df.index).apply(foo)
Roman Pekar

这完全取决于功能是什么...
Andy Hayden

1
从@HYRY以下,如果你只是想修改现有的数据框,你可以做的指数df.index = df.index.map(foo)

Answers:


95

正如HYRY在评论中所建议的那样,Series.map是前往此处的方法。只需将索引设置为结果序列即可。

简单的例子:

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数组。这是因为数据框指数基于numpy的阵列,而不是系列。

使索引成为系列的唯一方法是从中创建系列。

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

警告

Index类现在的子类StringAccessorMixin,这意味着你可以做以上操作如下

df.index.str.lower()

这仍然会产生一个Index对象,而不是Series。


1
用多指标,你可以,如果你想在你的函数,例如使用这两个项目使用切片x[0]x[1]
Elliott

3
较短的方法df.index.map(str.lower)
零时

1
@JohnGalt感谢您指出。它不仅更短,而且更快,因为str.lower是经过编译的cython函数,而我编写的lambda函数不是。
firelynx

12

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

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

要单独生成系列,您可以...

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

1
不建议在pandas / numpy echo系统中使用for循环。这是非常低效的内存,很容易因较大的数据集而崩溃。
firelynx15年

3

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

我使用此方法的方式是使用“重命名”:

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

唯一的窍门是您的索引需要具有不同的多重索引级别的唯一标签,但是也许比我更聪明的人知道如何解决这个问题。对我来说,这有95%的时间有效。


2

您始终to_series()可以根据自己的偏好/需要使用其方法,然后使用apply或来转换索引map

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

以上所有内容均可直接分配给的新列或现有列df

df["column"] = ret

只是为了完整性:pd.Index.mappd.Series.mappd.Series.apply所有的操作元素明智的。我经常使用mapdicts或代表的查询pd.Seriesapply之所以通用,是因为您可以将任何函数与附加args或一起传递kwargsapply和之间的差异map将在此SO线程中进一步讨论。我不知道为什么pd.Index.apply被省略。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.