![](/img/trans.png)
[英]R - deSolve package (ode function): change a matrix of parameters in SIR model according to time
[英]R- ode function (deSolve package): change the value of a parameter as a function of time
我正在嘗試使用 deSolve package 中的deSolve
ode
求解一階微分方程。 問題如下:葯物在某些時候(輸注時間)以恆定的輸注速率給葯,並以一級速率消除。 因此,該過程可以描述為:
if(t %in% Infusion_times){Infusion <- Infusion_rate} else{Infusion <- 0}
dC <- -Ke*C + Infusion
其中t
是時間, Infusion_times
是包含給葯時間的向量, C
是葯物的量, Ke
是其消除常數, Infusion
是一個變量,取輸液時的輸液速度值,以及否則值為 0。 因此,假設我們要施用 3 劑,從時間 0、24 和 40 開始,每次輸注持續兩個小時,假設我們希望deSolve
每 0.02 個單位時間計算一次答案。 例如,我們希望deSolve
求解 0 到 48 之間時間的微分方程,步長為 0.02 倍單位。 因此,我們為ode
function 指定時間的向量將是:
times <- seq(from = 0, to = 48, by = 0.02)
輸注時間由下式給出:
Infusion_times <- c(seq(from = 0, to = 2, by = 0.02), seq(from = 24, to = 26, by = 0.02),
seq(from = 40, to = 42, by = 0.02))
起初,我擔心問題可能出在浮點的比較中。 為了防止這種情況,我將兩個向量四舍五入到小數點后兩位:
times <- round(times, 2)
Infusion_times <- round(times, 2)
所以現在,希望所有的Infusion_times
都包含在times
向量中:
(sum(Infusion_times %in% times)/length(Infusion_times))*100
[1] 100
如您所見, Infusion_times
(100%) 中的所有值都包含在向量times
中,因此變量Infusion
應該在指定時間取值Infusion_rate
。 但是,當我們求解方程時,它不起作用。 讓我們證明它,但首先,讓我們指定ode
function 所需的其他值:
parameters <- c(Ke = 0.5)
amounts <- c(C = 0) #Initial value for drug is 0
Inf_rate <- 5
現在,讓我們根據需要編寫一個 function 說明變化率:
OneComp <- function(t, amounts, parameters){
with(as.list(c(amounts, parameters)),{
if(t %in% Infusion_times){Infuse =Inf_rate} else{Infuse = 0}
dC <- -Ke*C + Infuse
list(c(dC))})
}
For those who are not familiar with the deSolve
package, the argument t
of the function will state the times for which the equation should be integrated, amounts
will specify the initial value of C and parameters
will give the value of the parameters (in this case , 只是Ke
)。 現在,讓我們解方程:
out <- ode(func = OneComp, y = amounts, parms = parameters, times = times)
讓我們 plot 結果:
library(ggplot2)
ggplot(as.data.frame(out)) + geom_line(aes(x = times, y = C))
如果Infusion
總是等於 0,這與我們得到的結果完全相同。但是,請注意,如果我們只模擬單次劑量,並且我們要嘗試類似的方法,它會起作用:
OneComp <- function(t, amounts, parameters){
with(as.list(c(amounts, parameters)),{
if(t < 2){Infuse =Inf_rate} else{Infuse = 0}
dC <- -Ke*C + Infuse
list(c(dC))})
}
out <- ode(func = OneComp, y = amounts, parms = parameters, times = times)
ggplot(as.data.frame(out)) + geom_line(aes(x = times, y = C))
在這里,我們使變量Infuse
僅在時間小於 2 小時時才取Inf_rate
的值,並且有效! 因此,我對這些行為完全感到困惑。 這不是改變變量值的問題,也不是浮點數之間的比較問題......知道這些可能是什么嗎? 謝謝
大多數deSolve求解器使用自動內部時間步長,該時間步長會根據系統的粗糙度或平滑度自行調整。 The use of if
statements or if()
functions in the model function is not a good idea for two reasons: (i) the time steps may not be hit exactly and (2) the model function (ie the derivative) should ideally be continuous和可微分並避免逐步行為,即使求解器在這種情況下非常穩健。
deSolve package 為您的問題提供了兩種方法:“強制函數”和“事件”。 兩者都有其優點和缺點,但如果“事件”(例如注入)的時間與積分時間步相比非常短,則“事件”特別有用。
有關這方面的更多信息,請參見 deSolve幫助頁面?forcings
forcings 和?events
、 deSolve: Forcing functions and Events from the user,2017 Conference 以及 userR.2014 的幻燈片。
請檢查以下是否適合您:
library("deSolve")
OneComp <- function(t, y, parms){
with(as.list(c(y, parms)),{
dC <- -Ke * C
list(c(dC))
})
}
eventfunc <- function(t, y, parms) {
with(as.list(c(y, parms)),{
C + Inf_rate
})
}
parms <- c(Ke = 0.5, Inf_rate = 5)
y0 <- c(C = 0) # Initial value for drug is 0
Infusion_times <- c(seq(from = 0, to = 2, by = 0.02),
seq(from = 24, to = 26, by = 0.02),
seq(from = 40, to = 42, by = 0.02))
# time step can be made bigger to speedup simulation
times <- round(seq(from = 0, to = 48, by = .1) , 2)
# check that all events are in 'times', but no duplicates
# this check is also done by the solver and may print a warning
# to ensure that the user is very careful with this
unique_times <- cleanEventTimes(times, Infusion_times)
times <- sort(c(unique_times, Infusion_times))
out <- ode(func = OneComp, y = y0, parms = parms, times = times,
events = list(func = eventfunc, time = Infusion_times))
plot(out)
rug(Infusion_times)
兩條cleanEventTimes
行是確保模擬命中所有事件時間的一種可能方法。 它通常由求解器自動完成,並且可能會發出警告以提醒用戶對此要非常小心。
我使用“基礎”plot 和rug
來指示注射時間。
我有點想知道Infusion_times
和Inf_rate
這兩個術語。 在基於事件的方法中,在離散時間點將“數量”添加到 state 變量 C 中,而“速率”表示在時間間隔內連續添加。 這通常稱為強制 function。
強制 function 會更簡單並且數值更好。
我一直在為同樣的問題苦苦掙扎一段時間。 我試圖復制 IV 輸液,然后使用 deSolve package 而不是原始 Z20F35E630DAF44DBFA4C3F68F5399D8 中使用的 RxODE package 進行 PO 給葯。 我的解決方案是列出輸液時間,然后提取最大值:
tmp <- c()
for (i in seq(from = 1, to = Num.Doses, by = 1)) {
tmp[i] <- (i * Tau) - Tau
tmp2 <- seq(from = 0, to = 2, by = 0.1)
Inf.Times <- round(unlist(lapply(tmp, function(x, Add) x + tmp2)), 3)}
在這里, Num.Doses
設置為 5 次 IV 輸注。 Tau
(給葯間隔)是 24 小時, 0
是輸注開始時間, 2
是輸注結束時間(以小時為單位)。
Next I constructed a model, the full version of which is a multicompartment PKPD model from RxODE ( https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4728294/ ):
Model <- function(time, yini, parameters) {
with(as.list(c(yini, parameters)), {
Infusion <- ifelse(time %% Tau < Inf.Time & time <= max(Inf.Times), Dose / Inf.Time, 0)
C1 <- Central / V1
dDepot <- - (Ka * Depot)
dCentral <- (Ka * Depot) - (CL * C1) + Infusion
list(c(dDepot, dCentral))})}
我從 Andrew Booker 那里得到了Infusion <-
行的想法,如https://github.com/andrewooker/PopED/issues/11所示。 我將他的建議從if else
修改為ifelse
並在第 5 次輸液結束后合並一個硬停止, time <= max(Inf.Times)
否則 model 將不斷重新輸液。 這也允許我在使用 deSolve 運行 model 時使用事件表實現額外的非 IV 給葯:
Dose.Events <- data.frame(var = "Depot", time = c(120, 144, 168, 192, 216), value = Dose2, method = "add")
Times <- seq(from = 0, to = Tot.Hours, by = 1)
out <- ode(y = Ini.Con, times = Times, func = Model2, parms = Parms, events = list(data = Dose.Events))
當使用完整的 model 運行時,output 與在 RxODE 中使用原始代碼幾乎相同,更直接和“干凈”。 根據 AUC 判斷,差異很小,無花果相同到 6 位數。 我能夠復制 IV 輸液(第一組 5 個峰),還可以概括 PO 給葯(第二組 5 個峰)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.