Подходящая кривая, где каждая точка является решением ОДУ

У меня есть следующий код:

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import random

def dose(y, t, b, s, c, p, i):
    target, infectious, virus = y
    dydt = [-b*target*virus, b*target*virus - s*infectious, (1/(i+1))*p*infectious - c*virus]
    return dydt


b = 0.00001
s = 4
c = 4
p = 2000000
D = np.logspace(-3, 3, 7)
mylist = []

y0 = [1, 0, 0.01]
t = np.linspace(0, 60, 1000)
for i in D:
    sol = odeint(dose, y0, t, args=(b, s, c, p, i))
    #plt.plot(t, sol[:, 0], label='D = ' + str(i))
    V = sol[:, 2]
    mylist.append(V[48]/0.01950269536785707)


def add_noise(d, noise_pct):
    return [x + random.gauss(0, noise_pct * x) for x in d]

mat = np.array(mylist)

mylist2 = add_noise(mylist, 0.05)
mat2 = np.array(mylist2)
plt.plot(D, mat2)

plt.xscale('log')
#plt.plot(t, sol[:, 2], 'r', label='virus')
plt.legend(loc='best')
plt.xlabel('time')
plt.grid()
#plt.show()
print(D)
print(mat2)

Теперь D и mat2 содержат значения x и y, которые я хотел бы использовать для соответствия решению моей исходной системы ОДУ в функции дозе. Я также хотел бы построить новую встроенную функцию.

Как бы я это сделал?

Чтобы уточнить, я добавил ошибку от 5% до 7 точек данных из исходного графика и получил np.array значений x и y, для которого я хочу найти наиболее подходящую кривую, которая следует тем же дифференциальным уравнениям, что и оригинальный график.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
99
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Давайте немного переформулируем вашу проблему, чтобы сделать ее более эффективной и удобной.

import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate, optimize

Мы пишем динамику вашей системы, чтобы она соответствовала новому интерфейсу решателя solve_ivp :

def dose(t, y, b, s, c, p, d):
    target, infectious, virus = y
    return np.array([
        -b * target * virus,
        b * target * virus - s * infectious,
        (1. / (d + 1.)) * p * infectious - c * virus
    ])

Теперь мы пишем функцию модели, чтобы ее сигнатура была совместима с Curve_fit, мы также применяем упрощение при решении ОДУ, чтобы улучшить временную сложность алгоритма:

def model(D, b, s, c, p):
    solutions = []
    for d in D:
        solution = integrate.solve_ivp(
            dose, [0, 5], y0=[1, 0, 0.01],
            t_eval=[2.8828828828828827], # Translating np.linspace(0, 60, 1000)[48]
            args=(b, s, c, p, d)
        )
        data = solution.y[2, 0] / 0.01950269536785707  # I'm intrigued by this part of the your code I translated
        solutions.append(data)
    return np.array(solutions)

Теперь мы генерируем некоторый синтетический набор данных:

b = 0.00001
s = 4
c = 4
p = 2000000
p0 = (b, s, c, p)

np.random.seed(12345)
D = np.logspace(-3, 3, 20)
z = model(D, b, s, c, p)
s = np.ones_like(z) * 0.05
n = s * np.random.normal(size=s.size) * z
zn = z + n

И выполняем регулировку:

popt, pcov = optimize.curve_fit(
    model, D, zn, p0=[1e-5, 1, 1, 1e6],
    method = "trf", bounds=(0, np.inf),
    sigma=s, absolute_sigma=True
)

# (array([1.98458777e-05, 3.39383754e+00, 4.55115392e+00, 1.00007348e+06]),
#  array([[ 8.35308599e-10, -3.25230641e-03,  3.73469971e-03,
#          -5.22169803e-11],
#         [-3.25230641e-03,  1.28672442e+04, -1.47634805e+04,
#           2.06436797e-04],
#         [ 3.73469971e-03, -1.47634805e+04,  1.69398903e+04,
#          -2.36868204e-04],
#         [-5.22169803e-11,  2.06436797e-04, -2.36868204e-04,
#           3.31209815e-12]]))

Параметры по порядку одинаковы, приспособленность хорошая:

Dlog = np.logspace(-3, 3, 200)
fig, axe = plt.subplots()
axe.scatter(D, zn, label = "Data")
axe.semilogx(Dlog, model(Dlog, *popt), label = "Fit")
axe.semilogx(Dlog, model(Dlog, *p0), "--", label = "Model")
axe.legend()
axe.grid()

Это показывает, как технически выполнить регрессию. Обратите внимание, что ошибки s и c очень высоки, что, вероятно, объясняет, почему мы не можем восстановить исходные параметры.

Кроме того, кажется, что множественные комбинации параметров могут привести к эквивалентной пригодности: регрессированный и исходный параметр дают одну и ту же кривую.

но у меня уже есть данные

user1134699 11.07.2024 15:49

Ну, у нас нет ваших данных и вопрос немного расплывчатый. Вы проверяли ответ? С какой проблемой вы столкнулись? Хотите соответствовать реальным данным, опубликуйте их без проблем. Не то, что вы ожидаете, без проблем, будьте более конкретны. Ваше здоровье

jlandercy 11.07.2024 15:59

нет, это работает нормально

user1134699 11.07.2024 16:32

это здорово, спасибо

user1134699 11.07.2024 19:40

как мне рассчитать ARE для параметров b,s,c,p

user1134699 18.07.2024 18:47

Другие вопросы по теме