Используйте ссылочный класс в качестве уровней фактора

Есть ли у кого-нибудь опыт использования эталонных классов в качестве уровней фактора? Это один из шагов к моей цели — добавить поддержку «внешнего ключа» к data.frame в одном из моих пакетов.

В конечном итоге я хочу создать data.frame, который может хранить в виде целых чисел коды, связанные с фактором, но уровни этого фактора на самом деле являются объектами ссылочного класса, а не обычно используемыми факторами векторов символов. Мне удалось найти некоторую информацию об использовании объектов S4 в качестве уровней фактора, но похоже, что эти методы не работают для ссылочных классов.

Например, простой:

> myClass <- setRefClass("MyClass", fields=list(a="numeric", b="character"))
> myObj <- myClass$new(a=1, b="test")
> factor(myObj)
Error in unique.default(x) : unique() applies only to vectors
> as.character(myObj)
Error in as.vector(x, "character") : 
  cannot coerce type 'environment' to vector of type 'character'
> as.character.MyClass <- function(x){ x$b }
> as.character(myObj)
[1] "test"
> factor(myObj)
Error in unique.default(x) : unique() applies only to vectors
>
> unique.MyClass <- function (x, incomparables = FALSE, ...) { unique(as.character(x)) }
> factor(myObj)
Error in as.vector(x, mode) : invalid 'mode' argument
> traceback()
2: as.vector(exclude, typeof(x))
1: factor(myObj)

кажется, ничего не работает. Похоже, в лучшем случае я могу добраться до строки в factor(), которая анализирует параметр exclude:

exclude <- as.vector(exclude, typeof(x))

в этот момент все разваливается, так как мне не разрешено создавать вектор типа "S4".

Будем очень признательны за любые мысли о том, как решить этот или, что еще лучше, альтернативный подход к сопоставлению целого числа с объектом ссылочного класса data.frame-дружественным способом!


Изменить: в ответ на вопрос @Aaron ниже:

Простым решением здесь было бы просто хранить целые числа в data.frame, а затем поддерживать отдельный список/data.frame, отвечающий за сопоставление этих идентификаторов с некоторыми другими данными (такими как объекты ссылочного класса). Это будет поддерживать все необходимые данные для выполнения того, что мне нужно, но будет менее элегантным для меня по нескольким причинам:

  1. Я предполагаю решение, которое позволило бы мне распечатать часть самого объекта эталонного класса, а не идентификатор. Например, если я сопоставляю идентификаторы сотрудников (целые числа) с классом «Сотрудники», я хотел бы, чтобы мой data.frame печатал имена сотрудников, а не их идентификаторы.
  2. Я хотел бы иметь возможность извлекать объекты непосредственно из файла data.frame. Точно так же as.character(myDataFrame$someColumn) даст мне метки этого столбца (при условии, что это фактор), а не базовые целые числа, фактически хранящиеся в data.frame.

Опять же, я очень открыт для альтернативных решений этой проблемы, если есть лучший способ сделать это!


person Jeff Allen    schedule 24.04.2013    source источник
comment
Хорошо, я должен признать, что следил за этим вопросом в надежде прочитать ответы, но их пока нет, поэтому я спрошу, что (мне) кажется очевидным вопросом, но я не так много знаю о ссылочных классах или о том, что означает data-frame-friendly. Кажется, что простое решение состоит в том, чтобы просто использовать обычное целое число во фрейме данных и иметь список соответствующих внешних по отношению к нему объектов. Что в этом для вас минус?   -  person Aaron left Stack Overflow    schedule 25.04.2013
comment
Спасибо, @Аарон. Я добавил некоторую информацию к исходному вопросу, чтобы (надеюсь) пояснить, почему мне нужен объект, подобный фактору, и преимущества, которые я вижу в том, чтобы быть дружественным к data.frame.   -  person Jeff Allen    schedule 25.04.2013
comment
Чтобы разделить ваши проблемы, вы можете создать объектно-значный фактор, сначала создав его из символьного представления, а затем заменив атрибут уровней фактическими объектами. Тогда у вас есть две подзадачи. Один из них создает их автоматически, либо путем настройки функции factor, либо путем написания собственной функции для их создания. Другой — убедиться, что эти звери печатаются разумным образом, что не работает из коробки для их появления в data.frame.   -  person MvG    schedule 25.04.2013


Ответы (1)


Я думаю, это можно было бы сделать, создав новый класс, скажем, myFactor, с необходимыми методами; format кажется тем, что вам нужно для печати во фрейме данных; вы можете легко добавить print или другие методы по вашему выбору. Мне удобнее всего использовать методы S3, вот что я сделал здесь.

Здесь я настроил как ваш эталонный класс, так и функцию format для класса myFactor.

myClass <- setRefClass("MyClass", fields=list(a="numeric", b="character"))
format.myFactor <- function(obj, ...) {
  n <- sapply(levels(obj), function(x) x[["b"]])
  n[obj]
}

Здесь я создаю два новых эталонных объекта и использую их как уровни моего нового объекта myFactor.

myObj <- myClass$new(a=1, b="test")
myObj2 <- myClass$new(a=4, b="testagain")
foo <- structure(c(2,1,2), levels=c(myObj, myObj2), class=c("myFactor","numeric"))
d <- data.frame(x=foo)

Потом хорошо печатает.

> d
          x
1 testagain
2      test
3 testagain
person Aaron left Stack Overflow    schedule 25.04.2013