Добавить класс в столбец data.frame по ссылке - PullRequest
0 голосов
/ 29 августа 2018

Я хочу создать подкласс для data.frame (и тому подобное). Я хочу функцию который создает информацию о классе, а другой удаляет ее.

df <- data.frame(x = 1:10)

Думаю, это был бы "санкционированный" способ добавления классов. А также добавление, а затем удаление класса работает, как ожидалось, возвращая нетронутый объект.

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"

Я предполагаю, что 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 ссылка? Создано в 2018-08-29 пакетом Представление (v0.2.0).

...