标签: r-s3

如何在R中为自定义S3类编写ac()函数

我在R中编写一个S3类,它只是一个附加了一些属性的整数.如果x1和x2是这个类的对象(称之为"myclass"),那么我希望c(x1,x2)返回myclass对象的向量,原始类定义和属性保持不变.但是,c()的记录行为是删除属性,所以我似乎需要编写自己的c.myclass()方法.我的问题是,我该怎么做?

问题的一个例子:

myclass <- function(x, n) structure(x, class="myclass", n=n)
x1 <- myclass(1, 5)
x2 <- myclass(2, 6)
c(x1, x2)
[1] 1 2
Run Code Online (Sandbox Code Playgroud)

这里的结果只是类numeric的项向量,原来的n属性消失了.

查看各种包的代码,我有时会看到如下代码,其中我们需要保留class属性,但没有别的:

c.myclass <- function(..., recursive = F) {
    structure(c(unlist(lapply(list(...), unclass))), class="myclass")
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我也无法让这个工作.调用c.myclass(x1,x2)的结果是一个向量,其中向量本身具有类"myclass",但是向量中的每个项都有类numeric; 我真的希望向量中的每个项都有类"myclass".在实践中,我还需要升级此方法以保留其他属性(如myclass中的属性"n").

r r-s3

6
推荐指数
2
解决办法
643
查看次数

修改S3对象而不返回它?

我是 R 中面向对象编程的新手,并且正在努力解决如何正确编写修改对象的函数。

这个例子有效:

store1 <- list(
  apples=3,
  pears=4,
  fruits=7
)
class(store1) <- "fruitstore"
print.fruitstore <- function(x) {
  paste(x$apples, "apples and", x$pears, "pears", sep=" ")
}
print(store1)
addApples <- function(x, i) {
x$apples <- x$apples + i
x$fruits <- x$apples + x$pears
return(x)
}
store1 <- addApples(store1, 5)
print(store1)
Run Code Online (Sandbox Code Playgroud)

但我想应该有一种更干净的方法来做到这一点而不返回整个对象:

addApples(store1, 5)  # Preferable line...
store1 <- addApples(store1, 5)  # ...instead of this line
Run Code Online (Sandbox Code Playgroud)

在 R 中编写修改函数的正确方法是什么?“<<-”?

更新:感谢大家为 R 中的 OOP 编写的 Rosetta Stone。内容非常丰富。我试图解决的问题在流程方面非常复杂,因此参考类的刚性可能会给结构带来帮助。我希望我可以接受所有回复作为答案,而不仅仅是一个。

r r-s3

6
推荐指数
1
解决办法
1052
查看次数

在S3*data.frame上调度自定义方法

我想定义自己的行为(方法),用于将data.frame与新S3类的对象相乘.但我无法弄清楚如何让方法调度以找到我的方法.有办法吗?

首先,我定义S3对象'a'(oldClass"A")和'df'(oldClass"data.frame"):

a <- 4
oldClass(a) <- "A"
df <- data.frame(x=1:2,y=3:4)
Run Code Online (Sandbox Code Playgroud)

然后我使用trace(Ops.data.frame,edit = TRUE)在第一行添加print("Ops.data.frame").这样,我知道何时调用Ops.data.frame.这是一个演示:

a*df
# [1] "Ops.data.frame"
# x  y
# 1 4 12
# 2 8 16
Run Code Online (Sandbox Code Playgroud)

我可以为类"A"定义一个S3方法.

Ops.A <- function(e1, e2) {
  print("Ops.A")
  oldClass(e1) <- oldClass(e1)[oldClass(e1) != "A"]
  oldClass(e2) <- oldClass(e2)[oldClass(e2) != "A"]
  callGeneric(e1, e2)
}
Run Code Online (Sandbox Code Playgroud)

这被称为a而不是 df:

# This successfully calls Ops.A
a*a
# [1] "Ops.A"
# [1] 16

# But this throws an error
a*df
# Error in a * df : non-numeric argument …
Run Code Online (Sandbox Code Playgroud)

r r-s3

6
推荐指数
1
解决办法
270
查看次数

一次为环境分配多个值

给定一个环境x,一个方便的简写assign(x, value, envir = e)就是写e[[x]] <- value.目前,对于一次分配多个对象的子集运算符没有模拟:

> e = new.env(parent = emptyenv())
> e[["a"]] <- 1
> ls(e)
[1] "a"
> e[c("b", "c")] <- c(1,2)
Error in e[c("b", "c")] <- c(1, 2) : 
  object of type 'environment' is not subsettable
Run Code Online (Sandbox Code Playgroud)

我希望使用内置的S3功能来编写一个[<-.我注意到的第一个古怪的是,这两个[[<-[<-是原始的功能,尽管模仿S3功能:

> methods("[<-")
[1] [<-.data.frame  [<-.Date        [<-.environment [<-.factor      [<-.POSIXct     [<-.POSIXlt     [<-.raster*     [<-.ts* 
Run Code Online (Sandbox Code Playgroud)

通常,S3函数具有body只是调用的格式UseMethod.例如:

> summary
function (object, ...) 
UseMethod("summary")
<bytecode: 0x1a7c3a8>
<environment: namespace:base>
Run Code Online (Sandbox Code Playgroud)

除了赋值运算符是原始的,[[<- …

environment r r-s3

6
推荐指数
1
解决办法
201
查看次数

函数返回适用于对象的所有S3方法

有没有人放在一起/找到一个很好的方法来列出给定对象可用的所有S3方法?内置函数将为指定的类或指定的泛型函数提供所有可用的方法,但不为对象提供.methods()

我想到的一个例子是一个glm对象,它是(minor?)类,"glm"但也继承自"lm"

g <- glm(y~x,data=data.frame(x=1:10,y=1:10))
class(g)
## [1] "glm" "lm"
Run Code Online (Sandbox Code Playgroud)

类"lm"有35种方法,"glm"有22种方法.我对结合了结果的答案感兴趣

lapply(class(g),function(x) methods(class=x))
Run Code Online (Sandbox Code Playgroud)

以一种明智的方式,以便我可以立即看到(例如)有一个glm特定的方法add1,但是方法alias是从lm类继承的.

有人有一个光滑的方式来做到这一点,还是已经存在?

PS史蒂夫沃克的S3-S4参考类词汇表显示,它可以自动用于参考类,我们必须使用一个对象来获取方法(x$getRefClass()$methods()).

r r-s3

6
推荐指数
1
解决办法
180
查看次数

R S3 类 - 更改类并传递回相同的方法

我有一个关于在 R 中使用 S3 类执行某些操作的“正确”方法的问题。我想要做的是有一个方法可以更改类,然后在新类上调用相同的方法。像这样的东西:

my_func <- function(.x, ...) {
  UseMethod("my_func")
}

my_func.character <- function(.x, ...) {
  return(paste(".x is", .x, "of class", class(.x)))
}

my_func.numeric <- function(.x, ...) {
  .x <- as.character(.x)
  res <- my_func(.x) # this should call my_func.character
  return(res)
}
Run Code Online (Sandbox Code Playgroud)

这有效。当我执行以下操作时,我会character同时获得课程

> my_func("hello")
[1] ".x is hello of class character"
> my_func(1)
[1] ".x is 1 of class character"
Run Code Online (Sandbox Code Playgroud)

我的问题是:这是正确的方法吗?在转换类之后重新调用相同的方法(这一行res <- my_func(.x))感觉很奇怪。

我觉得NextMethod()一定是答案,但我读过很多关于它的文档(例如这个这个),但他们都讨论了这个事情,它跳到类列表中的下一个类,例如例如,data.frame直到matrix您拥有class(df) …

r r-s3

6
推荐指数
1
解决办法
297
查看次数

为什么在 `test_that()` 中加载的包在 `test_that()` 之外提供它们的方法,我该如何防止这种情况发生?

根据我的理解,放在里面的任何东西都test_that()应该被分隔开,这意味着如果我在 中加载一个包test_that(),它的函数和方法不应该在其他test_that()调用中可用。

\n

在下面的示例中,有 3 个(空)测试:

\n
    \n
  • 在第一个中,我们可以看到该方法as.matrix.get_predicted在命名空间中不可用。
  • \n
  • insight在第二个中,我加载提供了方法的包as.matrix.get_predicted。根据我的理解,此方法应该仅在本次调用中可用test_that()
  • \n
  • 在第三个中,我们可以看到该方法是可用的。
  • \n
\n
library(testthat)\n\ntest_that("foo 1", {\n  print("as.matrix.get_predicted" %in% methods(as.matrix))\n})\n#> [1] FALSE\n#> \xe2\x94\x80\xe2\x94\x80 Skip (???): foo 1 \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n#> Reason: empty test\n\ntest_that("foo 2", {\n  invisible(insight::get_parameters)\n})\n#> \xe2\x94\x80\xe2\x94\x80 Skip (???): foo 2 \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n#> Reason: empty test\n\ntest_that("foo 3", {\n  print("as.matrix.get_predicted" %in% methods(as.matrix))\n})\n#> [1] TRUE\n#> \xe2\x94\x80\xe2\x94\x80 Skip (???): foo 3 \xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n#> Reason: empty test\n
Run Code Online (Sandbox Code Playgroud)\n

这是为什么?有一些解决方法吗?

\n
\n

编辑:我正在寻找特定于 的解决方案 …

r r-s3 testthat

6
推荐指数
1
解决办法
311
查看次数

如何为 data.frame 子类扩展 rbind ?

我的问题是如何扩展rbind()子类data.frame?我似乎无法正确扩展rbind()以使用即使是非常简单的子类。以下示例演示了该问题:

子类和方法定义:

new_df2 <- function(x, ...)
{
  stopifnot(is.data.frame(x))
  structure(x, class = c("df2", "data.frame"), author = "some user")
}

rbind.df2 <- function(..., deparse.level = 1)
{
  NextMethod()
}
Run Code Online (Sandbox Code Playgroud)

我意识到rbind()在这种情况下扩展是不必要的,但我的宏伟计划是在我的子类上使用rbind.data.frame(),然后向其结果添加一些额外的检查/属性。

如果您调用以下命令,您会收到错误:Error in NextMethod() : generic function not specified

不起作用:

t1 <- data.frame(a = 1:12, b = month.abb)
t2 <- new_df2(t1)
rbind(t2, t2)
Run Code Online (Sandbox Code Playgroud)

我也尝试过使用NextMethod(generic = "rbind"),但在这种情况下,您会收到此错误:Error in NextMethod(generic = "rbind") : wrong value for .Method

也不起作用:

rbind.df2 …
Run Code Online (Sandbox Code Playgroud)

generics methods r rbind r-s3

5
推荐指数
1
解决办法
248
查看次数

坚持使用S3方法定义autoplot

我坚持定义S3方法autoplot.

我有以下(完整代码在这里):

#' Autoplot for bigobenchmark object
#'
#' @importFrom ggplot2 autoplot
#'
#' @param object
#'
#' @return A ggplot2 plot
#' @export
#'
#' @examples
#' # Create plot for benchmarks
#' library(ggplot2)
#' bench <- bigobenchmark(1:n, for(i in 1:n) for(i in 1:n) 1:n, args=seq(from=1, to=100, length.out = 50))
#' autoplot(bench)
autoplot.bigobenchmark <- function(object) {
  plt <- ggplot2::ggplot(data = object$benchmarks, ggplot2::aes(x=arg, y=mean, colour=expr))
  plt <- plt + ggplot2::geom_line()
  plt <- plt + ggplot2::geom_pointrange(aes(ymin=min, ymax=max)) …
Run Code Online (Sandbox Code Playgroud)

r r-s3 roxygen2 r-package

5
推荐指数
1
解决办法
191
查看次数

如何为未计算的赋值表达式定义 S3 方法?

\n

tl;drR CMD check当我为 S3 类实现泛型时会抱怨<-,因为它认为该函数是参数不正确的替换函数。

\n
\n

我需要定义一组 S3 泛型来遍历未计算的 R 表达式的 AST。

\n

出于演示目的,请考虑以下 S3 泛型及其方法:

\n
walk = function (x) UseMethod(\'walk\')\n\nwalk.default = function (x) message(\'default\')\n\nwalk.name = function (x) message(\'name\')\n\nwalk.call = function (x) message(\'call\')\n
Run Code Online (Sandbox Code Playgroud)\n

这工作正常:

\n
tests = alist(\'2\', c, f(1))\n\ninvisible(lapply(tests, walk))\n
Run Code Online (Sandbox Code Playgroud)\n
walk = function (x) UseMethod(\'walk\')\n\nwalk.default = function (x) message(\'default\')\n\nwalk.name = function (x) message(\'name\')\n\nwalk.call = function (x) message(\'call\')\n
Run Code Online (Sandbox Code Playgroud)\n

然而,有相当多的调用表达式的 S3 类是 \xe2\x80\x99t call;例如:

\n
tests2 = alist(for (x …
Run Code Online (Sandbox Code Playgroud)

r r-s3 non-standard-evaluation

5
推荐指数
1
解决办法
121
查看次数