将函数应用于数据框的元素

时间:2017-04-19 09:20:05

标签: python performance pandas numpy vectorization

假设我有以下数据框df

              1      3
Scenario1  0.001   0.05
Scenario2  0.003   0.01
Scenario3  0.001   0.042
Scenario4  0.09    0.006
Scenario5  0.02    0.04

假设这些是利率和期间,我想计算年金。

如果你不熟悉它,我想我只想应用这个公式:

    def computeAnnuity(r,n):
        return (1-(1+r)**-n)/r

我怎样才能得到一个数据框,其中我为每个元素计算了之前函数的值?

我想做点什么

df.applymap(computeAnnuity)

r作为返回(df中的每个元素),并将n作为列'数据帧的名称(即1和3)。但是我不知道如何在没有循环或循环的情况下以有效的方式做到这一点。

换句话说,给你一个Scenario1时期1的实际例子,其中有0.001我想要(1-(1+0.001)**-1)/0.001,或者,例如,对于Scenario4时期3,我有0.006我想要(1-(1+0.006)**-3)/0.006。我想为数据框中的每个元素(以高效自动的方式:使用该函数)执行此操作。

2 个答案:

答案 0 :(得分:3)

我认为你需要apply

def computeAnnuity(r,n):
    return (1-(1+r)**-n)/r

df1 = df.apply(lambda x: computeAnnuity(x, x.name))
print (df1)
                  1         3
Scenario1  0.999001  2.723248
Scenario2  0.997009  2.940985
Scenario3  0.999001  2.764591
Scenario4  0.917431  2.964357
Scenario5  0.980392  2.775091

print ((1-(1+0.001)**-1)/0.001)
0.9990009990008542

答案 1 :(得分:2)

对于性能(因为我们在这里寻找效率),我建议使用基于NumPy的方法,使用broadcasting -

a = df.values
N = df.columns.values.astype(int)
df_out = pd.DataFrame((1-(1+a)**-N)/a, columns=df.columns, index=df.index)

示例输入,输出 -

In [41]: df
Out[41]: 
               1      3
Scenario1  0.001  0.050
Scenario2  0.003  0.010
Scenario3  0.001  0.042
Scenario4  0.090  0.006
Scenario5  0.020  0.040

In [42]: df_out
Out[42]: 
                  1         3
Scenario1  0.999001  2.723248
Scenario2  0.997009  2.940985
Scenario3  0.999001  2.764591
Scenario4  0.917431  2.964357
Scenario5  0.980392  2.775091

使用numexpr模块进一步提升

查看所涉及的计算,我们似乎正在处理基于powerdivision的操作。这些可以与numexpr模块一起使用,以进一步提升性能。

因此,我们会有两种方法,如此 -

import numexpr as ne

def numpy_app(df):
    a = df.values
    N = df.columns.values.astype(int)
    return pd.DataFrame((1-(1+a)**-N)/a, columns=df.columns, index=df.index)

def numpy_numexpr_app(df):
    a = df.values
    N = df.columns.values.astype(int)
    return pd.DataFrame(ne.evaluate('(1-(1+a)**-N)/a'), \
                            columns=df.columns, index=df.index)

更大的数据集上的运行时测试 -

In [75]: names = np.random.choice(10000,5000, replace=0)

In [76]: df = pd.DataFrame(np.random.rand(5000,5000), columns=list(names))

# @jezrael's solution using df.apply
In [77]: %timeit df.apply(lambda x: computeAnnuity(x, int(x.name)))
1 loops, best of 3: 3.54 s per loop

In [78]: %timeit numpy_app(df)
1 loops, best of 3: 1.99 s per loop

In [79]: %timeit numpy_numexpr_app(df)
1 loops, best of 3: 393 ms per loop