我想为data.frame
(等)创建一个子类。我想要一个创建类信息的函数和另一个删除它的函数。
df <- data.frame(x = 1:10)
我认为这将是“R 认可”的添加类的方式。添加然后删除该类按预期工作,返回未触及的对象。
df2 <- df
class(df2$x) <- c("someclass", class(df2$x))
class(df2$x) <- class(df2$x)[class(df2$x) != "someclass"]
all.equal(df2, df)
#> [1] TRUE
但是,如果我想通过引用更改对象,则此方法不起作用,因为class<-
似乎复制了 data.table:
add.class <- function(object) {
class(object$x) <- c("someclass", class(object$x))
return(invisible(object))
}
add.class(df)
class(df$x) # doesn't work
#> [1] "integer"
文档说通过引用设置属性的data.table
正确方法是使用setattr
,并且确实,此功能确实按预期工作
add.class <- function(object) {
data.table::setattr(object$x, "class", c("someclass", class(object$x)))
return(invisible(object))
}
add.class(df)
class(df$x) # works!
#> [1] "someclass" "integer"
但问题是,当使用相同的逻辑来删除类时,对象并没有完全回到以前的状态
remove.class <- function(object) {
data.table::setattr(object$x, "class", class(object$x)[class(object$x) != "someclass"])
return(invisible(object))
}
df <- data.frame(x = 1:10)
df2 <- data.table::copy(df)
add.class(df2)
remove.class(df2)
all.equal(df, df2) # Not equal!
#> [1] "Component \"x\": Attributes: < target is NULL, current is list >"
#> [2] "Component \"x\": target is numeric, current is integer"
all.equal(class(df$x), class(df2$x)) # But, equal classes??
#> [1] TRUE
该问题并非特定于data.table::setattr()
,因为常规
attr<-
函数在更改class
属性时具有相同的问题
df <- data.frame(x = 1:10)
df2 <- data.table::copy(df)
attr(df$x, "class") <- c("someclass", class(df$x))
attr(df$x, "class") <- class(df$x)[class(df$x) != "someclass"]
all.equal(df, df2)
#> [1] "Component \"x\": Attributes: < Modes: list, NULL >"
#> [2] "Component \"x\": Attributes: < Lengths: 1, 0 >"
#> [3] "Component \"x\": Attributes: < names for target but not for current >"
#> [4] "Component \"x\": Attributes: < current is not list-like >"
#> [5] "Component \"x\": target is integer, current is numeric"
我的猜测是,它的作用与and
class<-
不同。但后来我意识到,这似乎只有在我更改列的类时才会发生。更改整个对象的类按预期工作。attr<-
setattr()
add.class <- function(object) {
data.table::setattr(object, "class", c("someclass", class(object)))
return(invisible(object))
}
remove.class <- function(object) {
data.table::setattr(object, "class", class(object)[class(object) != "someclass"])
return(invisible(object))
}
df <- data.frame(x = 1:10)
df2 <- data.table::copy(df)
add.class(df2)
remove.class(df2)
all.equal(df, df2)
#> [1] TRUE
这不是一个大问题,但它确实让正确测试变得很痛苦,因为我不能testthat::expect_equal()
用于单元测试。
那么,data.frame
通过引用更改列的类的正确方法是什么?由reprex 包(v0.2.0)于 2018-08-29 创建。