0

我想为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 创建。

4

0 回答 0