Graphing n iterations of a function- Python

陌路散爱 提交于 2019-12-05 07:39:55

问题


I'm studying dynamical systems, particularly the logistic family g(x) = cx(1-x), and I need to iterate this function an arbitrary amount of times to understand its behavior. I have no problem iterating the function given a specific point x_0, but again, I'd like to graph the entire function and its iterations, not just a single point. For plotting a single function, I have this code:

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt

def logplot(c, n = 10):
    dt = .001
    x = np.arange(0,1.001,dt)
    y = c*x*(1-x)
    plt.plot(x,y)
    plt.axis([0, 1, 0, c*.25 + (1/10)*c*.25])
    plt.show()

I suppose I could tackle this by the lengthy/daunting method of explicitly creating a list of the range of each iteration using something like the following:

def log(c,x0):
    return c*x0*(1-x)

def logiter(c,x0,n):
    i = 0
    y = []
    while i <= n:
        val = log(c,x0)
        y.append(val)
        x0 = val
        i += 1
    return y

But this seems really cumbersome and I was wondering if there were a better way. Thanks


回答1:


Some different options

This is really a matter of style. Your solution works and is not very difficult to understand. If you want to go on on those lines, then I would just tweak it a bit:

def logiter(c, x0, n):
    y = []
    x = x0
    for i in range(n):
        x = c*x*(1-x)
        y.append(x)

    return np.array(y)

The changes:

  • for loop is easier to read than a while loop
  • x0 is not used in the iteration (this adds one more variable, but it is mathematically easier to understand; x0 is a constant)
  • the function is written out, as it is a very simple one-liner (if it weren't, its name should be changed to be something else than log, which is very easy to confuse with logarithm)
  • the result is converted into a numpy array. (Just what I usually do, if I need to plot something)

In my opinion the function is now legible enough.

You might also take an object-oriented approach and create a logistic function object:

class Logistics():
    def __init__(self, c, x0):
        self.x = x0
        self.c = c

    def next_iter(self):
        self.x = self.c * self.x * (1 - self.x)
        return self.x

Then you may use this:

 def logiter(c, x0, n):
    l = Logistics(c, x0)
    return np.array([ l.next_iter() for i in range(n) ])

Or if you may make it a generator:

def log_generator(c, x0):
    x = x0
    while True:
        x = c * x * (1-x)
        yield x

def logiter(c, x0, n):
    l = log_generator(c, x0)
    return np.array([ l.next() for i in range(n) ])

If you need performance and have large tables, then I suggest:

def logiter(c, x0, n):
    res = np.empty((n, len(x0)))
    res[0] = c * x0 * (1 - x0)
    for i in range(1,n):
        res[i] =  c * res[i-1] * (1 - res[i-1])
    return res    

This avoids the slowish conversion into np.array and some copying of stuff around. The memory is allocated only once, and the expensive conversion from a list into an array is avoided.

(BTW, if you returned an array with the initial x0 as the first row, the last version would look cleaner. Now the first one has to be calculated separately if copying the vector around is desired to be avoided.)


Which one is best? I do not know. IMO, all are readable and justified, it is a matter of style. However, I speak only very broken and poor Pythonic, so there may be good reasons why still something else is better or why something of the above is not good!

Performance

About performance: With my machine I tried the following:

logiter(3.2, linspace(0,1,1000), 10000)

For the first three approaches the time is essentially the same, approximately 1.5 s. For the last approach (preallocated array) the run time is 0.2 s. However, if the conversion from a list into an array is removed, the first one runs in 0.16 s, so the time is really spent in the conversion procedure.

Visualization

I can think of two useful but quite different ways to visualize the function. You mention that you will have, say, 100 or 1000 different x0's to start with. You do not mention how many iterations you want to have, but maybe we will start with just 100. So, let us create an array with 100 different x0's and 100 iterations at c = 3.2.

data = logiter(3.6, np.linspace(0,1,100), 100)

In a way a standard method to visualize the function is draw 100 lines, each of which represents one starting value. That is easy:

import matplotlib.pyplot as plt

plt.plot(data)
plt.show()

This gives:

Well, it seems that all values end up oscillating somewhere, but other than that we have only a mess of color. This approach may be more useful, if you use a narrower range of values for x0:

data = logiter(3.6, np.linspace(0.8,0.81,100), 100)

you may color-code the starting values by e.g.:

color1 = np.array([1,0,0])
color2 = np.array([0,0,1])
for i,k in enumerate(np.linspace(0, 1, data.shape[1])):
    plt.plot(data[:,i], '.', color=(1-k)*color1 + k*color2)

This plots the first columns (corresponding to x0 = 0.80) in red and the last columns in blue and uses a gradual color change in between. (Please note that the more blue a dot is, the later it is drawn, and thus blues overlap reds.)

However, it is possible to take a quite different approach.

data = logiter(3.6, np.linspace(0,1,1000), 50)
plt.imshow(data.T, cmap=plt.cm.bwr, interpolation='nearest', origin='lower',extent=[1,21,0,1], vmin=0, vmax=1)
plt.axis('tight')
plt.colorbar()

gives:

This is my personal favourite. I won't spoil anyone's joy by explaining it too much, but IMO this shows many peculiarities of the behaviour very easily.




回答2:


Here's what I was aiming for; an indirect approach to understanding (by visualization) the behavior of initial conditions of the function g(c, x) = cx(1-x):

def jam(c, n):

    x = np.linspace(0,1,100)
    y = c*x*(1-x)
    for i in range(n):
        plt.plot(x, y)
        y = c*y*(1-y)

    plt.show()



来源:https://stackoverflow.com/questions/24481636/graphing-n-iterations-of-a-function-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!