标签: r-s3

覆盖基R中的S3方法

我试图从教学中使用的本地包中的R stats包中覆盖print.anova()函数.基本上,我想删除标题的打印并添加"总"行而不用新类创建新函数(例如,ANOVA()).

该函数如下所示:

print.anova <- function(x,digits=max(getOption("digits")-2,3),
 signif.stars=getOption("show.signif.stars"),totalSS=TRUE,rm.heading=TRUE,...) {
  if (!any(grepl("Res.Df",colnames(x)))) {         # exclusion for multiple lm objects
    if (!any(grepl("Levene",attr(x,"heading")))) { # exclusion for levenes.test
      if (totalSS) {                               # add total SS row
        x <- rbind(x,c(sum(x$Df),sum(x[,"Sum Sq"]),NA,NA,NA))
        row.names(x)[dim(x)[1]] <- "Total"
      }
    }
  }
  if (rm.heading) attr(x,"heading") <- NULL        # remove heading
  stats::print.anova(x,digits=digits,signif.stars=signif.stars,...)
  invisible(x)
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,我不确定是将它作为函数,方法,S3方法,这些的某种组合或其他完全导出.例如,当我尝试这个(roxygenize代码的一部分)时:

#'@export
Run Code Online (Sandbox Code Playgroud)

运行Rcmd检查时,我收到以下警告:

S3 methods shown with full name in documentation object 'print.anova':
  'print.anova'
Run Code Online (Sandbox Code Playgroud)

但是当我加载我的包时,该函数按预期工作.

但是,如果我试试这个:

#'@method print anova
#'@S3method print anova
Run Code Online (Sandbox Code Playgroud)

我没有用Rcmd检查得到任何警告或错误,但是当我尝试在R中使用该函数时,它在stats包命名空间中找到原始函数.此外,如果我这样做

getAnywhere(print.anova)
Run Code Online (Sandbox Code Playgroud)

我明白了

2 differing …
Run Code Online (Sandbox Code Playgroud)

r r-s3

10
推荐指数
1
解决办法
1456
查看次数

在R6类上实现S3调度的正确方法

我有一个R6类,我想S3为它添加一个方法.我发现的文档简要提到,为了使用你必须拥有的S3调度,我找不到应该怎么做的例子.R6class = TRUE

我确实在经验上看到只是简单地在表单中编写S3方法s3generic.r6class,但我想知道这是否确实以正确的方式编写S3方法R6.

例如,假设我有一个R6增强a 的类list

library(R6)

R6list <- R6Class(
  "R6list",
  public = list(
    orig = NULL,
    initialize = function(x) {
      self$orig <- x
    }
  )
)
Run Code Online (Sandbox Code Playgroud)

问题1

当然,我想提供一种获取基础列表的方法,所以我想添加一个as.list方法.是否标准在类中添加S3泛型和as.list公共函数?我的直观答案是添加两者.

R6list <- R6Class(
  "R6list",
  public = list(
    orig = NULL,
    initialize = function(x) {
      self$orig <- x
    },
    as.list = function() {
      self$orig
    }
  )
)

as.list.R6list <- function(x, ...) …
Run Code Online (Sandbox Code Playgroud)

r r-s3 r6

10
推荐指数
1
解决办法
450
查看次数

使用sd作为R中的通用函数

如果我有一个被调用的类foo,那么重载该summary函数是很简单的

summary.foo = function(x, ...) print("bar")
Run Code Online (Sandbox Code Playgroud)

但是,这种技术不适用于该sd功能

> bar = createFooClass()
> sd.foo = function(x, ...) print("Hi")
> sd(bar)
  error: is.atomic(x) is not TRUE
Run Code Online (Sandbox Code Playgroud)

重载此功能的正确方法是什么?

oop r r-s3

8
推荐指数
1
解决办法
1508
查看次数

为什么class(data.frame(...))不显示列表继承?

人们常常说,data.frame继承list,这是有道理的给予许多常见的范例访问data.frame列($,sapply,等).

然而"list",不是在data.frame对象的类列表中返回的项目之一:

dat <- data.frame(x=runif(100),y=runif(100),z=runif(100),g=as.factor(rep(letters[1:10],10)))
> class(dat)
[1] "data.frame"
Run Code Online (Sandbox Code Playgroud)

取消分类data.frame显示它是一个列表:

> class(unclass(dat))
[1] "list"
Run Code Online (Sandbox Code Playgroud)

如果没有data.frame方法,测试它看起来像默认方法将优先调用list方法:

> f <- function(x) UseMethod('f')
> f.default <- function(x) cat("Default")
> f.list <- function(x) cat('List')
> f(dat)
Default
> f.data.frame <- function(x) cat('DF')
> f(dat)
DF
Run Code Online (Sandbox Code Playgroud)

那么两个问题:

  1. 从设计的角度来看,未能data.frame正式继承是否list有任何优势?
  2. 那些似乎将data.frames视为列表的函数如何知道将它们视为列表?看起来lapply它看起来很快就会转到C内部代码,所以也许就是这样,但我的思绪在这里有点夸张.

r r-s3

8
推荐指数
1
解决办法
433
查看次数

在R包中定义自定义dplyr方法

我有一个自定义的包summary(),print()对于具有特定类对象的方法.这个软件包还使用了很棒dplyr的数据包进行操作 - 我希望我的用户能够编写同时使用我的软件包和dplyr的脚本.

其他人在这里这里注意到的一个障碍是dplyr动词不保留自定义类 - 这意味着ungroup命令可以剥离我的自定义类的data.frames,从而搞乱方法调度summary等.

Hadley说"正确执行此操作取决于您 - 您需要为每个dplyr方法定义一个方法,以便正确恢复所有类和属性"并且我正在尝试接受建议 - 但我无法弄清楚如何正确包装dplyr动词.

这是一个简单的玩具示例.假设我已经定义了一个cars类,我有一个自定义summary.

这很有效

library(tidyverse)

class(mtcars) <- c('cars', class(mtcars))

summary.cars <- function(x, ...) {
  #gather some summary stats
  df_dim <- dim(x)
  quantile_sum <- map(mtcars, quantile)

  cat("A cars object with:\n")
  cat(df_dim[[1]], 'rows and ', df_dim[[2]], 'columns.\n')

  print(quantile_sum)

}

summary(mtcars)
Run Code Online (Sandbox Code Playgroud)

这是问题所在

small_cars <- mtcars %>% filter(cyl < 6)
summary(small_cars)
class(small_cars)
Run Code Online (Sandbox Code Playgroud)

那个summary调用small_cars …

r r-s3 dplyr r-package tidyverse

8
推荐指数
2
解决办法
426
查看次数

R''as'函数的类型/来源

R的S3 OO系统以泛型函数为中心,这些函数根据调用泛型函数的对象类调用方法.关键是泛型函数调用适当的方法,而不是在类中定义方法的其他OO编程语言.

例如,该mean函数是通用函数.

isGeneric("mean")
methods(mean)
Run Code Online (Sandbox Code Playgroud)

这将打印

TRUE
[1] mean,ANY-method          mean.Date                mean.default             mean.difftime           
[5] mean.IDate*              mean,Matrix-method       mean.POSIXct             mean.POSIXlt            
[9] mean,sparseMatrix-method mean,sparseVector-method
see '?methods' for accessing help and source code
Run Code Online (Sandbox Code Playgroud)

我正在探索R并发现了这个as功能.我很困惑R这个函数不是通用的,但它仍然有方法.

isGeneric("as")
methods(as)

TRUE
  [1] as.AAbin                                  as.AAbin.character                       
  [3] as.alignment                              as.allPerms                              
  [5] as.array                                  as.array.default                         
  [7] as.binary                                 as.bitsplits                             
  [9] as.bitsplits.prop.part                    as.call
  ...                                  
Run Code Online (Sandbox Code Playgroud)

最后有一个警告说这as不是通用的.

 Warning message:
 In .S3methods(generic.function, class, parent.frame()) :
 function 'as' appears not to be S3 generic; found functions that look like S3 methods
Run Code Online (Sandbox Code Playgroud)

有人能解释我是什么as功能,以及如何连接 …

generics r object dispatch r-s3

8
推荐指数
1
解决办法
226
查看次数

什么是S1和S2类?

在R中有S3,S4和R 2.12,参考类(非正式地称为S5类).

是否有S1(或S2)类这样的东西?如果是这样,他们是什么?如果没有,为什么从S3开始?

oop r r-s3 r-s4

7
推荐指数
1
解决办法
1623
查看次数

使用S3为"+"方法模拟多个调度 - 可能吗?

我有两个类(ab),我想+为它们定义方法.我需要两种类的四种可能组合的不同方法,即:

a + a  method 1
a + b  method 2
b + a  method 3
b + b  method 4
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用S4进行多次调度,但我想知道是否有办法使用S3模拟这种行为.我的方法如下:

a <- "b"
class(a) <- "a"

b <- "e"
class(b) <- "b"

Ops.a <- function(e1, e2){
  if (class(e1) == "a" &
      class(e2) == "a")
    print("a & a")
  if (class(e1) == "a" &
        class(e2) == "b")
    print("a & b")
  if (class(e1) == "b" &
        class(e2) == "a")
    print("b & a")
  NULL
}

a …
Run Code Online (Sandbox Code Playgroud)

r r-s3

7
推荐指数
1
解决办法
667
查看次数

运算符重载在R包中停止工作

我有一个基本上是列表的容器类.因为我想支持子集化,所以我重载了子集[运算符(可能实现得很差).

#' Constructor for spectra object
.spectra = function(n_spectrum = 0) {
    object        = vector(mode = "list", n_spectrum)
    class(object) = "spectra"
    return(object)
}

#' Operator overload
#' @export
`[.spectra` = function(x, i) {
    x = unclass(x)
    x = x[i]                  # Using the list's subset function
    class(x) = "spectra"
    return(x)                 # Should return a "spectra" object, not a list
}
Run Code Online (Sandbox Code Playgroud)

现在,这在我的开发环境中(当我正在调试包时)按预期工作.也就是说,如果y_old是一个spectra对象,我做的y_new = y_old[-1],y_new仍然是一个spectra对象.

但是,当我将项目编译为包并安装它时,子集操作符返回一个list而不是一个spectra …

overloading r devtools r-s3

7
推荐指数
1
解决办法
278
查看次数

修改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
查看次数

标签 统计

r ×10

r-s3 ×10

oop ×2

devtools ×1

dispatch ×1

dplyr ×1

generics ×1

object ×1

overloading ×1

r-package ×1

r-s4 ×1

r6 ×1

tidyverse ×1