Хеш или поддерживаемые списком уровни фактора - PullRequest
3 голосов
/ 20 марта 2012

Я имею дело с категориальной переменной, извлеченной из базы данных, и хочу использовать факторы для поддержания «полноты» данных.

Например, у меня есть таблица, в которой хранятся цвета и связанные с нимичисловой идентификатор

  ID  | Color
------+-------
    1 | Black
 1805 | Red
 3704 | White

Поэтому я хотел бы использовать фактор для хранения этой информации во фрейме данных, например:

Car Model | Color
----------+-------
Civic     | Black
Accord    | White
Sentra    | Red

, где цветовой столбец является фактором, а основнойхранящиеся данные, а не строки, на самом деле с (1, 3704, 1805) - идентификаторы, связанные с каждым цветом.

Таким образом, я могу создать пользовательский фактор, изменив атрибуты уровней объектакласс факторов для достижения этого эффекта.

К сожалению, как видно из примера, мои идентификаторы не увеличиваются.В моем приложении у меня ~ 30 уровней, а максимальный ID для одного уровня ~ 9000.Поскольку уровни хранятся в массиве для фактора, это означает, что я храню целочисленный вектор длиной 9000, содержащий только 30 элементов.

Есть ли способ использовать хеш или список для достижения этой цели?эффект эффективнее?то есть, если бы я использовал хеш в атрибуте уровней фактора, я мог бы хранить все 30 элементов с любыми индексами, которые мне нравятся, без необходимости создавать массив размером max (ID).

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 20 марта 2012

Ну, я почти уверен, что вы не можете изменить работу факторов. Фактор всегда имеет идентификаторы уровня, которые являются целыми числами 1..n, где n - количество уровней.

... но вы можете легко получить вектор перевода, чтобы получить свои идентификаторы цвета:

# The translation vector...
colorIds <- c(Black=1,Red=1805,White=3704)

# Create a factor with the correct levels 
# (but with level ids that are 1,2,3...)
f <- factor(c('Red','Black','Red','White'), levels=names(colorIds))
as.integer(f) # 2 1 2 3

# Translate level ids to your color ids
colorIds[f] # 1805 1 1805 3704

Технически, colorIds не нужно определять названия цветов, но его проще иметь в одном месте, так как имена используются при создании уровней для фактора. Вы хотите явно указать уровни, чтобы их нумерация соответствовала, даже если уровни расположены не в алфавитном порядке (как у вас).

РЕДАКТИРОВАТЬ Однако возможно создать класс, производный от фактора, который имеет коды в качестве атрибута. Давайте назовем этот новый славный класс foo:

foo <- function(x = character(), levels, codes) {
    f <- factor(x, levels)
    attr(f, 'codes') <- codes
    class(f) <- c('foo', class(f))
    f
}

`[.foo` <- function(x, ...) {
    y <- NextMethod('[')
    attr(y, 'codes') <- attr(x, 'codes')
    y
}

as.integer.foo <- function(x, ...) attr(x,'codes')[unclass(x)]

# Try it out
set.seed(42)
f <- foo(sample(LETTERS[1:5], 10, replace=TRUE), levels=LETTERS[1:5], codes=101:105)

d <- data.frame(i=11:15, f=f)

# Try subsetting it...
d2 <- d[2:5,]

# Gets the codes, not the level ids...
as.integer(d2$f) # 105 102 105 104

Вы также можете исправить print.foo и т. Д. *

0 голосов
/ 21 марта 2012

Обдумывая это, единственная функция, которую "уровень" должен реализовать, чтобы иметь действительный фактор, - это средство доступа [. Таким образом, любой объект, реализующий метод доступа [, можно рассматривать как вектор с точки зрения любой сопрягающей функции.

Я посмотрел в класс hash , но увидел, что он использует нормальное поведение R (как видно из списков), возвращая фрагмент исходного хэша, когда используется только одна скобка (при извлечении фактическое значение при использовании двойной скобки). Однако, если бы я переопределил это с помощью setMethod (), я действительно смог получить желаемое поведение.

library(hash)

setMethod( 
    '[' , 
    signature( x="hash", i="ANY", j="missing", drop = "missing") ,  
    function( 
        x,i,j, ... ,        
        drop
        ) {     

        if (class(i) == "factor"){
            #presumably trying to lookup the values associated with the ordered keys in this hash
            toReturn <- NULL
            for (k in make.keys(as.integer(i))){
                toReturn <- c(toReturn, get(k, envir=x@.xData))
            }
            return(toReturn)
        }

        #default, just make keys and get from the environment
        toReturn <- NULL
        for (k in make.keys(i)){
            toReturn <- c(toReturn, get(k, envir=x@.xData))
        }
        return(toReturn)        
    }
    )

as.character.hash <- function(h){
    as.character(values(h))
}

print.hash <- function(h){
    print(as.character(h))
}

h <- hash(1:26, letters)

df <- data.frame(ID=1:26, letter=26:1, stringsAsFactors=FALSE)

attributes(df$letter)$class <- "factor"
attributes(df$letter)$levels <- h

>   df
   ID letter
1   1      z
2   2      y
3   3      x
4   4      w
5   5      v
6   6      u
7   7      t
8   8      s
9   9      r
10 10      q
11 11      p
12 12      o
13 13      n
14 14      m
15 15      l
16 16      k
17 17      j
18 18      i
19 19      h
20 20      g
21 21      f
22 22      e
23 23      d
24 24      c
25 25      b
26 26      a
>   attributes(df$letter)$levels
<hash> containing 26 key-value pair(s).
  1 : a
  10 : j
  11 : k
  12 : l
  13 : m
  14 : n
  15 : o
  16 : p
  17 : q
  18 : r
  19 : s
  2 : b
  20 : t
  21 : u
  22 : v
  23 : w
  24 : x
  25 : y
  26 : z
  3 : c
  4 : d
  5 : e
  6 : f
  7 : g
  8 : h
  9 : i
>
> df[1,2]
[1] z
Levels: a j k l m n o p q r s b t u v w x y z c d e f g h i
> as.integer(df$letter)
 [1] 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
[26]  1

Есть отзывы по этому поводу? Как я могу сказать, все работает. Похоже, что он работает должным образом, что касается печати, и базовые данные, хранящиеся в фактическом data.frame, не тронуты, поэтому я не чувствую, что я что-то там подвергаю опасности. Возможно, мне даже удастся добавить новый класс в мой пакет, который просто реализует этот метод доступа, чтобы избежать необходимости добавлять зависимость от хеш-класса.

Буду очень признателен за любые отзывы или замечания по поводу того, что я пропускаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...