I try to implement resuable and robust functions.
%matplotlib inline
import numpy as np
from urllib import request
def download(url):
response = request.urlopen(url)
data = response.read().decode("utf-8")
response.close()
lines = data.split("\n")
t_data = []
y_data = []
for line in lines:
if "time" in line:
continue
if line.strip(): # empty string is considered as False !
t, y = line.split(" ")
t_data.append(float(t))
y_data.append(float(y))
t_data = np.array(t_data)
y_data = np.array(y_data)
return t_data, y_data
import numpy as np
import scipy.optimize
import matplotlib.pyplot as pyplot
def logistic(t, K, P0, r):
"""
argument t: vector of time values
argument K: first parameter to fit
argument P0: second parameter to fit
argument r: third parameter to fit
returns: vector of y values corresponding to given parameters
"""
# enable next line to see how the fitting algorithm iteratively
# improves estimates for the parameters:
# print("K={:10.3e} P0={:10.3e} r={:10.3e}".format(K, P0, r))
ert = np.exp(r * t)
return K * P0 * ert / (K + P0 * (ert - 1))
def fit_logistic(t_data, y_data, K_start=None, P0_start=None, r_start=None):
assert len(t_data) > 0
assert len(t_data) == len(y_data)
# good starting values are important, if the user of the function has no
# idea about the expected parameters, we try to come up with an guess.
if K_start is None:
K_start = max(y_data) # estimate capacity
if P0_start is None:
P0_start = 0 # guessing here, don't know how to come up with an estimate
if r_start is None:
r_start = 1 # we assume as default that growth rate is not zero
p_start = np.array([K_start, P0_start, r_start])
# I use __ to indicate an unused variable:
parameters, __ = scipy.optimize.curve_fit(logistic, t_data, y_data, p_start)
return parameters
def plot_result(t_data, y_data, parameters):
"""we could also use separate arguments for K, P0, r. But so we have less function
arguments, and we group to a "meaningful entity".
"""
K, P0, r = parameters
pyplot.plot(t_data, y_data, "b*", label="measured")
pyplot.plot(t_data, logistic(t_data, K, P0, r), "green", label="fitted")
pyplot.legend(loc=2) # upper left corner
t_data, y_data = download("https://siscourses.ethz.ch/python_challenges/logistic_data.txt")
parameters = fit_logistic(t_data, y_data)
print(parameters)
plot_result(t_data, y_data, parameters)
pyplot.show()
The plot for the other data set looks broken:
t_data, y_data = download("https://siscourses.ethz.ch/python_challenges/logistic_data_multi.txt")
parameters = fit_logistic(t_data, y_data)
plot_result(t_data, y_data, parameters)
pyplot.show()
print(parameters)
plot
connects two consecutive pairs by a line in the given color. So what you see is that t_data
is not sorted:
print(np.all(t_data == np.sort(t_data)))
To sort two vectors at the same time there are two solutions:
np.argsort
does not sort the given data, but computes the permutation which would sort it:
permutation = np.argsort(t_data)
print(permutation)
t_data = t_data[permutation]
y_data = y_data[permutation]
print(np.all(t_data == np.sort(t_data)))
We also can use tuples.
To compare two tuples, the first element dominates, if first elements are the same, the second element dominates, and so on
print((0, 1, 2) < (1, 2, 3))
print((0, 1, 2) < (0, 2, 3))
So the next lines will also sort t_data
and y_data
according to the order of t_data
:
data = zip(t_data , y_data)
data = sorted(data)
t_data = np.array([t for (t, y) in data])
y_data = np.array([y for (t, y) in data])
print(np.all(t_data == np.sort(t_data)))
Now the plot looks fine:
plot_result(t_data, y_data, parameters)
pyplot.show()