访问pandas.Series.apply中的索引

可以说我有一个MultiIndex系列s

 >>> s values ab 1 2 0.1 3 6 0.3 4 4 0.7 

我想应用一个使用该行索引的函数:

 def f(x): # conditions or computations using the indexes if x.index[0] and ...: other = sum(x.index) + ... return something 

我如何做s.apply(f)这样的function? build议进行这种操作的方法是什么? 我期望获得一个新的系列,这个函数的值应用在每行和相同的MultiIndex上。

我不相信apply可以访问索引; 它将每行视为一个numpy对象,而不是一个Series,如你所见:

 In [27]: s.apply(lambda x: type(x)) Out[27]: ab 1 2 <type 'numpy.float64'> 3 6 <type 'numpy.float64'> 4 4 <type 'numpy.float64'> 

为了避开这个限制,将索引提升到列,应用你的函数,并用原始索引重新创build一个Series。

 Series(s.reset_index().apply(f, axis=1).values, index=s.index) 

其他的方法可能会使用s.get_level_values ,在我看来,这通常会有点难看,或者s.iterrows() ,这可能会比较慢 – 也许取决于f含义。

把它作为一个框架,如果你想要的话返回标量(所以结果是一个系列)

build立

 In [11]: s = Series([1,2,3],dtype='float64',index=['a','b','c']) In [12]: s Out[12]: a 1 b 2 c 3 dtype: float64 

打印function

 In [13]: def f(x): print type(x), x return x ....: In [14]: pd.DataFrame(s).apply(f) <class 'pandas.core.series.Series'> a 1 b 2 c 3 Name: 0, dtype: float64 <class 'pandas.core.series.Series'> a 1 b 2 c 3 Name: 0, dtype: float64 Out[14]: 0 a 1 b 2 c 3 

既然你可以在这里返回任何东西,只要返回标量(通过name属性访问索引)

 In [15]: pd.DataFrame(s).apply(lambda x: 5 if x.name == 'a' else x[0] ,1) Out[15]: a 5 b 2 c 3 dtype: float64 

可能会发现使用where而不是在这里apply更快:

 In [11]: s = pd.Series([1., 2., 3.], index=['a' ,'b', 'c']) In [12]: s.where(s.index != 'a', 5) Out[12]: a 5 b 2 c 3 dtype: float64 

你也可以使用numpy风格的逻辑/function的任何部分:

 In [13]: (2 * s + 1).where((s.index == 'b') | (s.index == 'c'), -s) Out[13]: a -1 b 5 c 7 dtype: float64 In [14]: (2 * s + 1).where(s.index != 'a', -s) Out[14]: a -1 b 5 c 7 dtype: float64 

我build议testing的速度(因为效率与应用程序将取决于function)。 虽然,我发现apply更具可读性

如果使用DataFrame.apply()而不是Series.apply(),则可以在函数内部作为参数访问整行。

 def f1(row): if row['I'] < 0.5: return 0 else: return 1 def f2(row): if row['N1']==1: return 0 else: return 1 import pandas as pd import numpy as np df4 = pd.DataFrame(np.random.rand(6,1), columns=list('I')) df4['N1']=df4.apply(f1, axis=1) df4['N2']=df4.apply(f2, axis=1)