gpt4 book ai didi

R:如何真正从 S4 对象中移除 S4 插槽(附有解决方案!)

转载 作者:行者123 更新时间:2023-12-03 16:19:16 24 4
gpt4 key购买 nike

假设我定义了一个 S4 类 'foo'带两个插槽 'a''b' ,并定义一个对象 x类(class)'foo' ,

setClass(Class = 'foo', slots = c(
a = 'numeric',
b = 'character'
))
x <- new('foo', a = rnorm(1e3L), b = rep('A', times = 1e3L))
format(object.size(x), units = 'auto') # "16.5 Kb"
然后我想删除插槽 'a'来自 'foo'的定义
setClass(Class = 'foo', slots = c(
b = 'character'
))
slotNames(x) # slot 'a' automatically removed!! wow!!!
我看到 R 会自动处理我的对象 x并有插槽 'a'移除。好的!但是等等,对象的大小 x没有减少。
format(object.size(x), units = 'auto') # still "16.5 Kb"
format(object.size(new(Class = 'foo', x)), units = 'auto') # still "16.5 Kb"
对..不知何故 'a'仍然在那里,但我无法对它做任何事情
head(x@a) # `'a'` is still there
rm(x@a) # error
x@a <- NULL # error
所以问题:我如何才能 真的移除插槽 'a'来自 x缩小尺寸 (这是我最关心的问题)?

我最深切的感谢所有的答案!
以下解决方案的灵感来自 dww
trimS4slot <- function(x) {
nm0 <- names(attributes(x))
nm1 <- names(getClassDef(class(x))@slots) # ?methods::.slotNames
if (any(id <- is.na(match(nm0, table = c(nm1, 'class'))))) attributes(x)[nm0[id]] <- NULL # ?base::setdiff
return(x)
}
format(object.size(y1 <- trimS4slot(x)), units = 'auto') # "8.5 Kb"
以下解决方案的灵感来自 Robert Hijmans
setClass('foo1', contains = 'foo')
format(object.size(y2 <- as(x, 'foo1')), units = 'auto') # "8.5 Kb"
method::as可能会做一些全面的检查,所以速度很慢
library(microbenchmark)
microbenchmark(trimS4slot(x), as(x, 'foo1')) # ?methods::as 10 times slower

最佳答案

插槽存储为属性。我们有几个选项可以将插槽转换为 NULL .
选项 1 : 您可以使用 check=FALSE参数在 slot<-在不触发错误的情况下将插槽分配为 NULL。

slot(x, 'a', check=FALSE) <- NULL
setClass(Class = 'foo', slots = c(b = 'character'))
format(object.size(x), units = 'auto')
# [1] "8.7 Kb"
但是,该属性并未完全删除(它仍然存在,其值为 \001NULL\001 )。这是因为 C 函数中的一行 R_do_slot_assign ,其中有: if(isNull(value)) value = pseudo_NULL;其中pseudo_NULL 是“一个对象......用于表示NULL 的插槽(属性不能是)”。
还应该注意 ?slot 中的建议。 “用户在正常使用中不应设置 check=FALSE,因为生成的对象可能无效。”在这种情况下,它不会导致任何问题,因为该插槽随后会立即被移除。尽管如此,谨慎使用 check=False 标志还是有好处的,除非您确定自己了解自己在做什么。
选项 2 :在类定义中去掉slot后直接去掉属性,可以实现更完整的去掉:
setClass(Class = 'foo', slots = c(
b = 'character'
))
attr(x, 'a') <- NULL
format(object.size(x), units = 'auto')
# [1] "8.7 Kb"
但是,删除插槽是个好主意吗?
删除插槽是一种黑客行为,可能会在以后导致错误,例如如果调用了一个假设插槽存在的方法。您可能会在自己的机器上针对特定用例执行此操作。但是将其作为生产代码发布到野外并不是一个好主意。在这种情况下,@RobertHijmans 的回答中的方法将是可行的方法。

关于R:如何真正从 S4 对象中移除 S4 插槽(附有解决方案!),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67028788/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com