尝试编写一个 S4 数据类,其中在槽中包含列表列表。这种在槽中的嵌套是如何完成的?

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

我正在尝试创建一个简单的 S4 类,它允许存储所有必要的参数,以生成半确定性数据合成集,以便另一组函数起作用。

最终,我的 R 包中将调用两个函数:

getDataModel(x)
setDataModel(...)

setDataModel(...)
(首先)将交互地询问用户参数来定义数据生成模型(也许结构是一个更好的术语?)
getDataModel(x)
将读取并解析模型对象,以供其他实际生成的函数使用吐出最终数据。 我认为我的问题是我可能试图过度模块化我的代码。

考虑这个 S4 级

setClass(
  "TimefitteR_Param_List",
  slots = list(
    intercept_offset = "numeric",
    intercept_noise = "numeric",
    slope_offset = "numeric",
    slope_noise = "numeric",
    curvature_offset = "numeric",
    curvature_noise = "numeric"
  ),
  prototype = list(
    intercept_offset = 1,
    intercept_noise = 1,
    slope_offset = 0,
    slope_noise = 1,
    curvature_offset = 0,
    curvature_noise = 1
  )
)

这完全按照预期工作,并在其自身调用时创建一个名为 list 的 6 个值。

但是,当我调用

document()
load_all()

时,下面的课程会光荣地失败
#' @include classes_param_model.R
setClass(
  "TimefitteR_Data_Model",
  slots = list(
    vars = "list",
    time_params = "list",
    base_params = "TimefitteR_Param_List",
    conditions_params = "list",
    predictors_params = "list"
  ),
  prototype = list(
    vars = list(
      time = "Time",
      conditions = list(class="factor", levels = c("Control", "Intervention")),
      predictors = list(
        Gender = list(class="factor", levels = c("Female","Male")),
        SES = list(class="factor", levels = c("Low","Moderate","High"))
      )
    ),
    time_params = list("from"=0,"length"=20,"step"=1),
    base_params = "TimefitterR_Param_List",
    conditions_params = "TimefitteR_Param_List",
    predictors_params = list(
      Gender = list("TimefitteR_Param_List"),
      SES = list("TimefitteR_Param_List","TimefitteR_Param_List")
    )
  ),
  contains = "TimefitteR_Param_List"
)
! Failed to load R/classes_data_model.R
Caused by error in `makePrototypeFromClassDef()`:
! in making the prototype for class “TimefitteR_Data_Model” elements of the prototype failed to match the corresponding slot class: base_params (class "TimefitteR_Param_List" ), conditions_params (class "list" )

我追求的是一个具有这种结构的对象(比如mod)

mod
  vars
    time <<character>>
    conditions <<factor with levels "Control" and "Intervention" by default>>
    predictors <<list could be any length including NULL>>
      Gender <<factor with levels "Female" & "Male" by default>>
      SES <<factor with levels "Low", "Moderate", & "High" by default>>
  time_params <<list of 3>>
    from <<numeric default 0>>
    length <<numeric default 20>>
    step <<numeric default 1>>
  base_params <<TimefitteR_Param_List>>
  conditions_params <<list of length(conditions-1) with each element a TimefitteR_Param_List>>
  conditions_params <<list of length(predictors-1) with each element a named list>>
    Gender <<list of length(Gender-1) with each element a TimefitteR_Param_List>>
    SES <<list of length(SES-1) with each element a TimefitteR_Param_List>>

我(可能)可以弄清楚如何通过调用

setDataModel(...)
来构建此数据结构作为返回对象(S3 对象??),但我希望使用 S4 类及其原型系统来构建这一切从简单的调用到
new("TimefitteR_Data_Model")

我认为(知道)问题在于我在原型语法中有列表列表,在插槽中有简单的非嵌套列表。但是,...

  1. 我应该如何管理嵌套?
  2. 是为每个子级别类型结构创建类然后@include 的首选解决方案吗?
  3. 我是否想得太多而错过了一些非常明显的东西?
如有任何帮助,我们将不胜感激。

r class-design r-s4
1个回答
0
投票
对于设计为嵌套列表的槽,您需要定义有效性方法来检查长度和组件是否满足您的要求。 检查的严格程度取决于您...

您可以从像这样的更简单的示例中汲取灵感:

setClass("param", slots = c(a = "numeric", b = "numeric"), prototype = list(a = 0, b = 1)) setClass("listOfParam", contains = "list", validity = function(object) { class. <- getClassDef("param") for (elt in object) if (!is(elt, class.)) return("component is not a \"param\" object") TRUE }) setClass("model", slots = c(simpleSlot = "param", nestedSlot = "listOfParam", anotherSlot = "numeric"), validity = function(object) { if (length(object@nestedSlot) != length(object@anotherSlot)) return("slots 'nestedSlot' and 'anotherSlot' do not have equal length") TRUE })
定义像

listOfParam

这样的“包装”类并不是严格必要的。  上述可以实现为:

setClass("param", slots = c(a = "numeric", b = "numeric"), prototype = list(a = 0, b = 1)) setClass("model", slots = c(simpleSlot = "param", nestedSlot = "list", anotherSlot = "numeric"), validity = function(object) { class. <- getClassDef("param") for (elt in object@nestedSlot) if (!is(elt, class.)) return("component of slot 'nestedSlot' is not a \"param\" object") if (length(object@nestedSlot) != length(object@anotherSlot)) return("slots 'nestedSlot' and 'anotherSlot' do not have equal length") TRUE })
    
© www.soinside.com 2019 - 2024. All rights reserved.