是否可以在 R simmer 模拟运行时“动态”修改数据帧?我需要它来模拟预约安排

问题描述 投票:0回答:1

我正在为一家诊所构建预约安排模拟。这个想法是,随着模拟的运行,当患者到达系统时,他们会请求与医生预约。然后他们必须等到预约的时间。

对于问题的细节,我有:

模拟运行21个时间单位(小时) 有 6 名患者到达,时间为 1、2、3、4、5 和 6 医生检查一位病人正好需要1个时间单位(小时) 可用预约时段为 1、2、3、4、5、11、12、14、15、19 和 20

我的想法是使用一个名为

df_appointment_slots
的小标题来跟踪每个患者的插槽分配。这不仅仅是一个监测活动,因为患者只能选择未分配的时间段。

第一个代码定义了模拟中可用的预约空档。理想情况下,随着模拟的进行,代表时间段的每一行都会将其

assigned
列更新为
TRUE
,并且在患者 ID 属性之后为
patient_id

library(simmer)
library(tidyverse)

df_appointment_slots = tibble(sim_time = df_appointment_slots = tibble(
  sim_time = c(1,2,3,4,5,11,12,14,15,19,20),
  assigned = rep(FALSE, length(sim_time)),
  patient_id = rep(NA, length(sim_time)))

在此功能中,我有几个预约分配方案,为了举例,我想将每个患者随机分配到可用的预约时段。在我的实际应用程序中,遵循更复杂的规则,因此我需要它位于我可以修改的函数中。

assign_appointment = function(env, env_now ,df = df_appointment_slots){
 p_id = function(){get_attribute(env, "patient_id")}
  
 #Randomly select an available time slot after current simulation time.
 df_assigned = df %>% 
   filter(assigned == FALSE,
          sim_time >= env_now) %>% 
   slice_sample() %>% 
    mutate(assigned = TRUE, patient_id = p_id) 
 
  #If there are no available time slots then the patient takes other    trajectory and leaves the system
  
  if(nrow(df_assigned) == 0){
    return(-1)
#We will check later that if this function returns a value of -1
#instead of using it for a timeout, we decide to change trajectory
#and make the patient leave the system. 
  }
   
  #df_updated switches the assigned time slot into the original df_appointment slots. If there is a better way to do this i'm open to ideas.

  df_updated = df %>% 
    anti_join(df_assigned, by="sim_time") %>% 
    rbind(df_assigned) %>% 
    arrange(sim_time)
  
  
  #Results of the function
  #We want to update de dataframe that is outside of this scope and of the simulation. That way next patient can't be assigned to a time_slot that is already assigned.
                    
  df_appointment_slots <<- df_updated 
  
  # We return the appointment time
  return(df_assigned$sim_time)
}

最后但并非最不重要的,这是模拟

clinic = simmer("Clinic") 

patient_trajectory <-
  trajectory("Patient_trajectory") %>% 
  
  #We assign a id to each patient
  set_attribute("patient_id", 1, mod = "+") %>% 

  #Appointment assignment
  set_attribute("appointment_time",
                assign_appointment(env = clinic,
                                   env_now = simmer::now(clinic),
                                   df = df_appointment_slots)) %>% 
  
  #If assign_appointment returns -1 then there are no more time_slots available and the patient leaves the system
  
  branch(
    option = function() {ifelse(get_attribute("appointment_time") == -1, 1,2)},
    continue = c(T, F),
    trajectory("leave_system") %>% 
      log_("There was no appointment slot available")
    ) %>% 
  
  #If the appointment was succesfully scheduled then the patient waits until the appointment time
  
  log_("The patient waits for the appointment") %>% 
  timeout(
    function(){get_attribute("appointment_time") - simmer::now(clinic)}) %>%
  
  #After waiting, the patient seizes the doctor for 1 hour
  seize("doctor") %>% 
  timeout(1) %>% 
  release("doctor")
  
clinic %>%
  add_generator("Patient", patient_trajectory, at(1,2,3,4,5,6)) %>% 
  run(until = 21)

当然我收到以下错误:

Error in `mutate()`:
i In argument: `patient_id = p_id`.
Caused by error:
! `patient_id` must be a vector, not a function.

它告诉我

p_id = function(){get_attribute(env, "patient_id")}
函数中的
assign_appointment
正在保存为函数,并且不会在模拟过程中动态评估它,以便我可以将患者 ID 保存在
df_appointment_slots
标题中。

我还担心我从根本上误解了 R Simmer 库及其功能。如果有更好的方法以完全可定制的方式动态指定患者的时间段,我愿意接受建议。

r simulation schedule appointment
1个回答
2
投票

我在模拟内部函数的评估方面遇到了麻烦。我刚刚确认将

assign_appointment()
封装在
set_attribute()
处的无名函数中可以按预期工作。每次调用 allocate_appointment 时,名为
df_appointment_slots
的数据帧都会按预期更新。

所以,是的,这是我必须做的小修正。

#Appointment assignment
  set_attribute("appointment_time",function(){
                assign_appointment(p_id = get_attribute(clinic, "patient_id"),
                                   env_now = simmer::now(clinic),
                                   df = df_appointment_slots)}) %>% 

所以回答我自己的问题:是的,可以在模拟运行时更新数据帧。

© www.soinside.com 2019 - 2024. All rights reserved.