如何在 RC 类中使用 match.call()?

How to use match.call() inside an RC class?

提问人:MKJ 提问时间:10/2/2023 更新时间:10/2/2023 访问量:53

问:

我已经编写了自己的小线性回归类,类似于 lm,并希望让它打印“函数调用”。我查看了 lm 代码并找到了 match.call(),但我相信这只能工作,因为 lm 是通过函数定义的。我正在使用一个 RC 类,它通过 initialize 函数进行初始化。我想使用并在初始化函数中定义创建我的函数。我知道 TRUE 是 expand.dots 的默认值,但无论哪种方式,它似乎都没有这样做。当我打电话时,我得到.有谁知道为什么它给了我......1, ..2,而不是我的输入?谢谢!linreg_mod <- linreg(formula=Petal.Length ~ Species, data=iris).self$call <<- match.call(expand.dots=TRUE)linreg_mod$call.Object$initialize(formula = ..1, data = ..2)

R 哎呀 LM

评论

1赞 Konrad Rudolph 10/2/2023
仅供参考,R 的 RC 对象系统基本上已经过时,并且已被 R6 系统取代。就所有意图和目的而言,R6 是 RC 的现代高级版本。
0赞 SamR 10/2/2023
@KonradRudolph在我的回答中,有类型.我认为正确的做法是简单地计算 a ,而不是 ,它(我认为)将强制转换为 a,然后查看搜索路径。但是由于对使用普遍犹豫不决,我选择了,尽管我想不出在这种情况下不使用的实际原因。你有意见吗?args$datanameeval()nameget()namecharactereval()get()eval()
1赞 Konrad Rudolph 10/2/2023
@SamR我会使用标准评估来获得,即 (实际上有点奇怪,没有更直接的方法来获得一个特定的论点;这感觉像是一个疏忽:可以说应该有效)。但是在 和 之间,我总是使用 ,因为它是功能较弱的操作(因此更具描述性且不易出错)。事实上,它的语义非常接近 R 解析名称的方式。(续...datalist(...)$data......elt('data')eval()get()get()get()
0赞 Konrad Rudolph 10/2/2023
@SamR......也就是说,在这里行不通!因为不是一个名字。这是一个任意表达式(可以是名称,但不一定是名称)。因此,在这种情况下,您必须使用 - 但一定要在正确的范围内进行评估!Plain 会在函数范围内评估参数,这是不正确的。您需要使用 (或 )。get()args$dataeval()eval()eval.parent()eval(envir = parent.frame())
1赞 Konrad Rudolph 10/2/2023
@SamR尝试 .linreg(Petal.Length ~ Species, data = head(iris))

答:

4赞 SamR 10/2/2023 #1

您应该能够以通常的方式与引用类一起使用。下面是一个最小的示例:match.call()

lm_wrapper <- setRefClass("lm_wrapper", methods = list(
    match_call_demo = function(...) {
        # This method is just to demonstrate the output
        # of match.call() and not required in your class
        as.list(match.call())
    },
    linreg = function(...) {
        # The actual regression method
        args  <- as.list(match.call())
        lm(formula = args$formula, data = eval.parent(args$data))
    }
))

然后,你可以用你的参数来调用它。首先,让我们调用演示来显示 的输出。请注意,我在这里使用了它,因为它会更容易解析各个参数。正如 R 语言定义所述:match.call()as.list()

调用对象的组件使用类似列表的语法进行访问,实际上可以使用 和as.listas.call

lm_model$match_call_demo(formula = Petal.Length ~ Species, data = iris)
# [[1]]
# lm_model$linreg

# $formula
# Petal.Length ~ Species

# $data
# iris

请注意,使用此方法时,有必要在父框架中 eval() 参数,在本例中为全局环境。我最初习惯于这样做。但是,如果参数是 ,例如 ,则有效,但如果参数是我们想要计算的调用,则不起作用,例如 。感谢康拉德·鲁道夫(Konrad Rudolph)对此的评论args$dataget()nameirishead(iris)

为了运行模型,我们可以简单地将列表的相关对象提供给参数。

lm_model$linreg(formula = Petal.Length ~ Species, data = iris)
# Call:
# lm(formula = args$formula, data = eval.parent(args$data))

# Coefficients:
#       (Intercept)  Speciesversicolor   Speciesvirginica  
#             1.462              2.798              4.090  

请注意,或者,也许最好,您也可以采纳康拉德·鲁道夫(Konrad Rudolph)的建议,即使用标准评估。

lm_wrapper <- setRefClass("lm_wrapper", methods = list(
    linreg = function(...) {
        lm(formula = list(...)$formula, data = list(...)$data)
    }
))

我找不到大量关于 RC 的文档。Hadley Wickham 的 Advanced R 的 Reference classes 一章包含更多信息,尽管它似乎是草稿形式。Wickham 建议 R6 比 RC 更可取,原因有很多,其中之一是 R6 有全面的文档。

评论

1赞 MKJ 10/2/2023
感谢您的全面回答!事实上,RC 的文档非常少......我也会研究 R6 类,谢谢!