I rewrote irr to use the iterative solver instead of polynomial roots so that it can also handle large arrays. For 3000 values, I had to kill the current np.irr since I didn't want to wait longer than 10 minutes When writing the test, I found that npv is missing a "when" keyword, for the case when the first payment is immediate, i.e. in the present, and that broadcasting has problems:
np.npv(0.05, np.array([[1,1],[1,1]])) array([ 1.9047619 , 1.81405896]) np.npv(0.05, np.array([[1,1],[1,1],[1,1]]))
Traceback (most recent call last): File "<pyshell#82>", line 1, in <module> np.npv(0.05, np.array([[1,1],[1,1],[1,1]])) File "C:\Programs\Python25\Lib\site-packages\numpy\lib\financial.py", line 449, in npv return (values / (1+rate)**np.arange(1,len(values)+1)).sum(axis=0) ValueError: shape mismatch: objects cannot be broadcast to a single shape -------------------------- Here is the changed version, that only looks for one root. I added an optional starting value as keyword argument (as in open office) but didn't make any other changes: def irr(values, start=None): """ Return the Internal Rate of Return (IRR). This is the rate of return that gives a net present value of 0.0. Parameters ---------- values : array_like, shape(N,) Input cash flows per time period. At least the first value would be negative to represent the investment in the project. Returns ------- out : float Internal Rate of Return for periodic input values. Examples -------- >>> np.irr([-100, 39, 59, 55, 20]) 0.2809484211599611 """ p = np.poly1d(values[::-1]) pd1 = np.polyder(p) if start is None: r = 0.99 # starting value, find polynomial root in neighborhood else: r = start # iterative solver for discount factor for i in range(10): r = r - p(r)/pd1(r) ## #res = np.roots(values[::-1]) ## # Find the root(s) between 0 and 1 ## mask = (res.imag == 0) & (res.real > 0) & (res.real <= 1) ## res = res[mask].real ## if res.size == 0: ## return np.nan rate = 1.0/r - 1 if rate.size == 1: rate = rate.item() return rate def test_irr(): v = [-150000, 15000, 25000, 35000, 45000, 60000] assert_almost_equal(irr(v), 0.0524, 2) nper = 300 #Number of periods freq = 5 #frequency of payment v = np.zeros(nper) v[1:nper+1:freq] = 1 # periodic payment v[0] = -4.3995180296393199 assert_almost_equal(irr(v), 0.05, 10) nper = 3000 #Number of periods freq = 5 #frequency of payment v = np.zeros(nper) v[1:nper+1:freq] = 1 # periodic payment v[0] = -4.3995199643479603 assert_almost_equal(irr(v), 0.05, 10) If this looks ok, I can write a proper patch. Josef