Pandas中的牛顿法

1 投票
1 回答
804 浏览
提问于 2025-04-18 13:24

我正在尝试使用scipy.newton方法来优化一个pandas数据框。

首先,我创建数据框的代码如下。 接下来,创建一个叫做Px的函数。 然后,再创建另一个函数YieldCalc,在这个函数里我使用scipy.newton来优化,找到使得Px等于0的Rate值。最后,我想把这个值添加到一个新的列'Yield'中,但遇到了以下错误。任何帮助都将非常感激。提前谢谢大家。

from pandas import *
import pandas as pd
from scipy import *
import scipy
import timeit   
#In:
#Creating Dataframe
df = DataFrame(list([100,2,34.1556,9,100]))
df = DataFrame.transpose(df)
df = df.rename(columns={0:'Face',1:'Freq',2:'N',3:'C',4:'Mkt_Price'})
df2= df
df = concat([df, df2])
df

#Out:
Face  Freq    N          C  Mkt_Price
100    2     34.1556     9    100
100    2     34.1556     9    100


#In:
Face = df['Face']
Freq = df['Freq']
N = df['N']
C = df['C']
Mkt_Price = df['Mkt_Price']


def Px(Rate):
    return Mkt_Price - (Face * ( 1 + Rate / Freq ) ** ( - N ) + ( C / Rate ) * ( 1 - (1 + ( Rate / Freq )) ** -N ) )

def YieldCalc():
    return scipy.optimize.newton(Px, .1, tol=.0001, maxiter=100)
df['Yield'] = YieldCalc()

错误/输出:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-89-f4961d3f817b> in <module>()
     12 def YieldCalc(Rate):
     13     return scipy.optimize.newton(Px, .1, tol=.0001, maxiter=100)
---> 14 df['Yield'] = YieldCalc(.05)

<ipython-input-89-f4961d3f817b> in YieldCalc(Rate)
     11 
     12 def YieldCalc(Rate):
---> 13     return scipy.optimize.newton(Px, .1, tol=.0001, maxiter=100)
     14 df['Yield'] = YieldCalc(.05)

C:\Users\rebortz\Anaconda\lib\site-packages\scipy\optimize\zeros.pyc in newton(func, x0, fprime, args, tol, maxiter, fprime2)
    145         q1 = func(*((p1,) + args))
    146         for iter in range(maxiter):
--> 147             if q1 == q0:
    148                 if p1 != p0:
    149                     msg = "Tolerance of %s reached" % (p1 - p0)

C:\Users\rebortz\Anaconda\lib\site-packages\pandas\core\generic.pyc in __nonzero__(self)
    674         raise ValueError("The truth value of a {0} is ambiguous. "
    675                          "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
--> 676                          .format(self.__class__.__name__))
    677 
    678     __bool__ = __nonzero__

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

1 个回答

1

这里的关键在于,从 df['Face'] 得到的不是一个单独的值,也不是一个数组,而是和 pandas 这个库有关系的东西。

你可以按照建议,使用 .values 来获取原始数据,然后把这些数据传递给一个函数。

另外,pandas 的数据框还有一个 .apply 方法,可以让你把一个函数应用到每一行或每一列。

我在你发的代码最后加了以下内容(先把出问题的那一行注释掉)

def Foo(thing, Rate):
    return thing[0]*Rate

df['Yield'] = df.apply(Foo,axis=1,args=(0.1,))
df.head()

在这里,.apply 方法会把函数 Foo 传递给 df 中某一行的所有条目,作为一个系列,同时也传递参数 0.1。这里的轴设置决定了是按行处理(axis=0 是按列处理)。

只需要调整一下 Px,让它接受 'Rate' 和来自 df 的值系列(这个顺序)。然后让 YieldCalc 也接受这个系列。此外,在调用 newton 时,你需要使用 args= 来传递这个值系列给 Px,这样它在寻找零点时才能用到。

整个流程应该是:

.applydf 中提取一行,生成一个系列 thing,然后把它传递给 YieldCalc。接着,YieldCalcPx(Rate,thing) 上运行 newton 来找到 Rate 的值为 0。最后,所有这些结果都会被放到你新的 Yield 列中。

撰写回答