问题描述
在许多变体中,类似的问题已被问过多次......但我没有找到明确的建议:
In many variants, similar questions have been asked many times ...but i do not find a clear advice about:
将 S3 方法导出为函数"
我使用 roxygen2 编写了一个自定义 S3 类,将其命名为 'my_item'.这是构造函数:
I wrote a custom S3 class with roxygen2, call it 'my_item'.This is the constructor function:
my_item <- function(n) structure(list(n=n),class='my_item')
我需要的是一种定义 "list of my_items => data.frame"
转换函数的方法:
What I need is a way to define a "list of my_items => data.frame"
cast function:
#' @method as.data.frame my_item
#' @export
as.data.frame.my_item <- function(x) ...
只要我以这种方式用 my_item 调用它,就可以了:
As soon as I call it with a my_item in this way, it is fine:
as.data.frame(my_item('a'))
但是对对象列表应用相同的调用是行不通的,因为 class(list)
是空的:
But applying the same call to a list of objects cannot work, because class(list)
is empty:
as.data.frame(list(my_item('a'),my_item('b')))
这也行不通,因为函数/方法没有导出
This cannot work also because the function/method is not exported
as.data.frame.my_item(list(my_item('a'),my_item('b')))
这不适用于显式命名空间限定:
This does not work with explicit namespace qualification:
my_pkg::as.data.frame.my_item(...)
Error: 'as.data.frame.my_item' is not an exported object from 'namespace:my_pkg'
在包 zoo 中,这对于 plot
通用函数是可能的.
In the package zoo, this is possible for plot
generic function.
参见 plot.zoo
,一种 S3 方法,作为函数导出:
See plot.zoo
, an S3 method, exported as a function:
在动物园::NAMESPACE
export(
...
"plot.zoo"
...
)
S3method("plot", "zoo")
S3method("as.data.frame", "zoo")
由此产生的包范围是:
library(zoo)
methods('as.data.frame')
[1] as.data.frame.aovproj* as.data.frame.array as.data.frame.AsIs
[4] as.data.frame.character as.data.frame.chron* as.data.frame.complex
[7] as.data.frame.data.frame as.data.frame.data.table* as.data.frame.Date
[10] as.data.frame.dates* as.data.frame.default as.data.frame.difftime
[13] as.data.frame.factor as.data.frame.ftable* as.data.frame.integer
[16] as.data.frame.ITime* as.data.frame.list as.data.frame.logical
[19] as.data.frame.logLik* as.data.frame.matrix as.data.frame.model.matrix
[22] as.data.frame.noquote as.data.frame.numeric as.data.frame.numeric_version
[25] as.data.frame.ordered as.data.frame.POSIXct as.data.frame.POSIXlt
[28] as.data.frame.raw as.data.frame.shingle* as.data.frame.table
[31] as.data.frame.times* as.data.frame.ts as.data.frame.vector
[34] as.data.frame.yearmon* as.data.frame.yearqtr* as.data.frame.zoo*
see '?methods' for accessing help and source code
methods('plot')
[1] plot.acf* plot.data.frame* plot.decomposed.ts* plot.default plot.dendrogram*
[6] plot.density* plot.ecdf plot.factor* plot.formula* plot.function
[11] plot.hclust* plot.histogram* plot.HoltWinters* plot.isoreg* plot.lm*
[16] plot.medpolish* plot.mlm* plot.ppr* plot.prcomp* plot.princomp*
[21] plot.profile.nls* plot.raster* plot.shingle* plot.spec* plot.stepfun
[26] plot.stl* plot.table* plot.times* plot.trellis* plot.ts
[31] plot.tskernel* plot.TukeyHSD* plot.zoo
see '?methods' for accessing help and source code
这说明plot.zoo
导出了,as.data.frame.zoo*
没有导出
This shows that plot.zoo
is exported, as.data.frame.zoo*
is not exported
所以这个问题可能是错误的.
So probably the question is wrong.
更好的方法是:
在使用lists-of-list-based-S3-objects"时如何实现cast-protocol ('as-...')?>
推荐答案
我采取了不同的方法:
- 通过
as.my_item_list()
函数将'my_item'+'_list'
类添加到通用列表中 - 定义一个
as.data.frame.my_item_list
方法来处理我的自定义" 列表 - 使用泛型调用 DF 转换:
as.data.frame(as.my_item_list(some_list))
- adding
'my_item'+'_list'
class to a generic list via anas.my_item_list()
function - defining an
as.data.frame.my_item_list
method working on my "custom" lists - invoke DF conversion with generics:
as.data.frame(as.my_item_list(some_list))
在以下示例中,我将 my_item
类名替换为较短的 ob
In the following example, I substituted my_item
class name with a shorter ob
定义
# ---( the 'ob' S3 constructor )---------------------------------------------
ob <- function(a,b) structure(list(a=a,b=b), class='ob')
is.ob <- function(x) inherits(x,'ob')
#---( the 'ob_list' cast for lists )-----------------------------------------
as.ob_list <- function(x, ...) UseMethod('as.ob_list')
as.ob_list.list <- function(x, ...) {
stopifnot(all(sapply(x,is.ob)))
class(x) <- append(class(x),'ob_list',after=0)
x
}
#---( as.data.frame.* methods )----------------------------------------------
as.data.frame.ob <- function(x, ...) data.frame(t(as.matrix(unlist(x))))
as.data.frame.ob_list <- function(x, ...) do.call('rbind', lapply(x,as.data.frame))
测试
o1 <- ob(1,10)
o2 <- ob(2,20)
o3 <- ob(3,30)
ol <- list(o1,o2,o3)
df <- as.data.frame(as.ob_list(ol))
print(df)
a b
1 1 10
2 2 20
3 3 30
看起来不错!
这篇关于为自定义 S3 对象编写“as.data.frame"方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!