【问题标题】:Apply function to elements of dataframe将功能应用于数据框的元素
【发布时间】:2017-09-15 10:20:59
【问题描述】:

假设我有以下数据框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)。但是我不知道如何在不循环或不循环的情况下以有效的方式做到这一点。

换句话说,为场景 1 周期 1 提供一个实际示例,其中有 0.001 我想要 (1-(1+0.001)**-1)/0.001,或者,例如,对于场景 4 周期 3,我有 0.006 我想要 (1-(1+0.006)**-3)/0.006。我想对数据框中的每个元素都执行此操作(以一种高效且自动的方式:使用该函数)。

【问题讨论】:

    标签: python performance pandas numpy vectorization


    【解决方案1】:

    为了性能(因为我们在这里寻找效率),我建议使用基于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
    

    【讨论】:

      【解决方案2】:

      我觉得你需要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
      

      【讨论】:

        猜你喜欢
        • 2015-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-26
        • 2018-07-17
        • 1970-01-01
        • 2017-03-09
        相关资源
        最近更新 更多