working4coins
working4coins

Reputation: 2027

Geometric progression using Python / Pandas / Numpy (without loop and using recurrence)

I'd like to implement a geometric progression using Python / Pandas / Numpy.

Here is what I did:

N = 10
n0 = 0
n_array = np.arange(n0, n0 + N, 1)
u = pd.Series(index = n_array)
un0 = 1
u[n0] = un0
for n in u.index[1::]:
    #u[n] = u[n-1] + 1.2 # arithmetic progression
    u[n] = u[n-1] * 1.2 # geometric progression
print(u)

I get:

0    1.000000
1    1.200000
2    1.440000
3    1.728000
4    2.073600
5    2.488320
6    2.985984
7    3.583181
8    4.299817
9    5.159780
dtype: float64

I wonder how I could avoid to use this for loop.

I had a look at https://fr.wikipedia.org/wiki/Suite_g%C3%A9om%C3%A9trique and found that u_n can be expressed as: u_n = u_{n_0} * q^{n-n_0}

So I did that

n0 = 0
N = 10
n_array = np.arange(n0, n0 + N, 1)
un0 = 1
q = 1.2
u = pd.Series(map(lambda n: un0 * q ** (n - n0), n_array), index = n_array)

That's ok... but I'm looking for a way to define it in a recurrent way like

u_n0 = 1
u_n = u_{n-1} * 1.2

But I don't see how to do it using Python / Pandas / Numpy... I wonder if it's possible.

Upvotes: 6

Views: 7987

Answers (6)

Bill
Bill

Reputation: 11613

I think @Ashish's solution with np.cumprod is the simplest but if you are willing to define a generator somewhere then this is probably the most computationally efficient solution:

def geometric_series_generator(x, r, n):
    """Generate a geometric series of length n, starting
    at x and increasing by the ratio r.
    """

    for i in range(n):
        yield x
        x = x*r

N = 10
u0 = 1
r = 1.2
gen = geometric_series_generator(u0, r, N)
geom_series = np.fromiter(gen, float, count=N)
print(pd.Series(geom_series, index=np.arange(0, N, 1)))

Output:

0    1.000000
1    1.200000
2    1.440000
3    1.728000
4    2.073600
5    2.488320
6    2.985984
7    3.583181
8    4.299817
9    5.159780
dtype: float64

Upvotes: 0

Jo Ja
Jo Ja

Reputation: 273

Itertools helps:

from itertools import accumulate
import operator
import pandas as pd

d, f, n = 1.2, 1, 10  # degree, first element, number
pd.Series([* accumulate([f]+[d] * (n-1), func = operator.mul)])

result is:

0     1.000000
1     1.510000
2     2.280100
3     3.442951
4     5.198856
5     7.850273
6    11.853912
7    17.899406
8    27.028104
9    40.812437
dtype: float64

Upvotes: 0

ilmarinen
ilmarinen

Reputation: 5697

Use numpy.logspace

>>> import numpy
>>> N=10
>>> u=numpy.logspace(0,N,num=N, base=1.2, endpoint=False)
>>> print u
[ 1.          1.2         1.44        1.728       2.0736      2.48832
  2.985984    3.5831808   4.29981696  5.15978035]

Upvotes: 9

Ashish
Ashish

Reputation: 739

Here is how it works for me in a Pandas series:

N = 10
n0 = 0
n_array = np.arange(n0, n0 + N, 1)
u = pd.Series(index = n_array)
u[n0] = 1
q = 1.2
# option 1:
u = pd.Series(u[n0]*q**(u.index.values - n0), index = n_array)
# or option 2 with cumprod
u[1:] = q
u = u.cumprod()

Upvotes: 2

Jaime
Jaime

Reputation: 67427

Another possibility, that is probably more computationally efficient than using exponentiation:

>>> N, un0, q = 10, 1, 1.2
>>> u = np.empty((N,))
>>> u[0] = un0
>>> u[1:] = q
>>> np.cumprod(u)
array([ 1.        ,  1.2       ,  1.44      ,  1.728     ,  2.0736    ,
        2.48832   ,  2.985984  ,  3.5831808 ,  4.29981696,  5.15978035])

Upvotes: 12

Dmitry Markin
Dmitry Markin

Reputation: 1205

Just defining u(u0, q, n) function should work:

def u(u0, q, n):
    return u0 if n==0 else q*u(u0, q, n-1)

Upvotes: 0

Related Questions