在DataFrame索引上应用函数

Ale*_*erg 62 python indexing dataframe pandas

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

pd.DataFrame({"Month": df.reset_index().Date.apply(foo)})
Run Code Online (Sandbox Code Playgroud)

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

fir*_*ynx 79

正如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
Run Code Online (Sandbox Code Playgroud)

索引!=系列

正如@OP所指出的那样.该df.index.map(str.lower)调用返回一个numpy数组.这是因为数据框指数基于numpy的阵列,而不是系列.

将索引编入系列的唯一方法是从中创建一个系列.

pd.Series(df.index.map(str.lower))
Run Code Online (Sandbox Code Playgroud)

警告

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

df.index.str.lower()
Run Code Online (Sandbox Code Playgroud)

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

  • 比较短的方式`df.index.map(str.lower)` (3认同)

小智 7

假设您希望通过将函数"foo"应用于索引来在当前DataFrame中创建列.你可以写......

df['Month'] = df.index.map(foo)
Run Code Online (Sandbox Code Playgroud)

要单独生成系列,你可以做...

pd.Series({x: foo(x) for x in foo.index})
Run Code Online (Sandbox Code Playgroud)

  • 强烈建议不要在 pandas/numpy 回声系统中使用 for 循环。它的内存效率非常低,并且很容易因较大的数据集而崩溃。 (2认同)

nor*_*ius 7

您可以使用其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
Run Code Online (Sandbox Code Playgroud)

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

df["column"] = ret
Run Code Online (Sandbox Code Playgroud)

只是为了完整性:pd.Index.mappd.Series.map并且pd.Series.apply都按元素操作。我经常使用或map表示的查找。更通用,因为您可以将任何函数与附加或. 和之间的区别在此 SO 线程中进一步讨论。不知道为什么被省略了。dictspd.Seriesapplyargskwargsapplymappd.Index.apply

  • 我发现第三个示例很有用,因为索引保留在返回的系列中。 (2认同)

cho*_*raf 6

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

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

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
Run Code Online (Sandbox Code Playgroud)

唯一的技巧是你的索引需要有不同的多索引级别的唯一标签,但也许比我更聪明的人知道如何解决这个问题。就我的目的而言,这在 95% 的情况下都有效。