'ValueError: f(a) and f(b) must have different sign
I have a dataframe with columns Date, cash, rate, name. When I try to groupby by name then I am able to find the value of XIRR but when I try to groupby by rate then the error comes as
File "C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\zeros.py", line 519, in brentq r = _zeros._brentq(f,a,b,xtol,rtol,maxiter,args,full_output,disp)
ValueError: f(a) and f(b) must have different signs"
def xnpv(rate, values, dates):
if rate <= -1.0:
return float('inf')
d0 = dates.min() # or min(dates)
return sum([ vi / (1.0 + rate)**((di - d0).days / 365.0) for vi, di in zip(values, dates)])
def xirr(values, dates):
try:
return scipy.optimize.newton(lambda r: xnpv(r, values, dates), 0.0)
except RuntimeError: # Failed to converge?
return scipy.optimize.brentq(lambda r: xnpv(r, values, dates), -1.0, 1e10)
def f(x):
x["XNPV"] = xnpv(0.1, x["Cash"], x['Date'])
x["XIRR"] = xirr( x["Cash"], x['Date'])
return x
f2 = f1.groupby('RATE').apply(f)
Solution 1:[1]
The error message is fairly clear. From docs
Return float, a zero of f between a and b. f must be a continuous function, and [a,b] must be a sign changing interval.
The situation happens because brentq works on a modification of "bisection" root finding techniques, while newton method does not. Given the assurance that there exists a root between an interval (which implies the sign must change between the interval), brentq will always converge.
This is in contrast with the newton method, which does not suffer from the same requirements but can fail to converge as it works off of an initial root guess.
Bottom line
scipy.optimize.brentq(lambda r: xnpv(r, values, dates), -1.0, 1e10)
Here , the interval is being treated as [-1.0, 1e10], and the function must be evaluating to the same sign for both those values. You would need to provide an interval that has different values for f(a) and f(b) to guarantee that a root lies in between.
Solution 2:[2]
I figured out a resolution that worked for me regarding the same error. I believe the error is due to you have some extreme small number like 1.1e-33, that would cause trouble.
X_train = round(X_train,8)
solved my issue.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Jeremy Caney |
