我试图从教学中使用的本地包中的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) 我有一个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) 如果我有一个被调用的类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)
重载此功能的正确方法是什么?
人们常常说,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)
那么两个问题:
data.frame正式继承是否list有任何优势?data.frames视为列表的函数如何知道将它们视为列表?看起来lapply它看起来很快就会转到C内部代码,所以也许就是这样,但我的思绪在这里有点夸张.我有一个自定义的包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的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功能,以及如何连接 …
在R中有S3,S4和R 2.12,参考类(非正式地称为S5类).
是否有S1(或S2)类这样的东西?如果是这样,他们是什么?如果没有,为什么从S3开始?
我有两个类(a和b),我想+为它们定义方法.我需要两种类的四种可能组合的不同方法,即:
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) 我有一个基本上是列表的容器类.因为我想支持子集化,所以我重载了子集[运算符(可能实现得很差).
#' 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 …
我是 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。内容非常丰富。我试图解决的问题在流程方面非常复杂,因此参考类的刚性可能会给结构带来帮助。我希望我可以接受所有回复作为答案,而不仅仅是一个。