R 因子的哈希或列表备份级别

R 因子的哈希或列表备份级别,r,R,我正在处理一个从数据库中检索的分类变量,希望使用因子来保持数据的“完整性” 例如,我有一个存储颜色及其相关数字ID的表 ID | Color ------+------- 1 | Black 1805 | Red 3704 | White ID |颜色 ------+------- 1 |黑色 1805 |红色 3704 |白色 因此,我想使用一个因子将此信息存储在数据框中,例如: Car Model | Color ----------+------- Civic | B

我正在处理一个从数据库中检索的分类变量,希望使用因子来保持数据的“完整性”

例如,我有一个存储颜色及其相关数字ID的表

ID | Color ------+------- 1 | Black 1805 | Red 3704 | White ID |颜色 ------+------- 1 |黑色 1805 |红色 3704 |白色 因此,我想使用一个因子将此信息存储在数据框中,例如:

Car Model | Color ----------+------- Civic | Black Accord | White Sentra | Red 车型|颜色 ----------+------- 思域|黑色 雅阁白色 森特拉红 其中,color列是一个因子,存储的底层数据(而不是字符串)实际上是c(137041805)——到与每种颜色相关联的id

因此,我可以通过修改factor类的对象的levels属性来创建自定义因子,以实现此效果

不幸的是,正如您在示例中看到的,我的ID没有增加。在我的应用程序中,我有约30个级别,一个级别的最大ID为约9000。因为级别存储在一个因子数组中,这意味着我要存储一个长度为9000的整数向量,其中只有30个元素

是否有任何方法可以使用散列或列表更有效地实现此效果?i、 e.如果我在因子的levels属性中使用散列,我可以用我喜欢的任何索引存储所有30个元素,而不必创建一个size max(ID)数组


提前谢谢

嗯,我很确定你不能改变因素的工作方式。因子的级别ID始终为整数
1..n
,其中
n
是级别数

…但您可以轻松地使用转换向量来获取颜色ID:

# 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

然后,您还可以修复
print.foo
等。

在考虑它时,“级别”需要实现的唯一功能是
[
访问器。因此,从任何接口函数的角度来看,实现
[
访问器的任何对象都可以被视为向量

我查看了该类,但发现它使用了正常的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
库(散列)
设置方法(
'[' , 
签名(x=“散列”,i=“任意”,j=“缺失”,drop=“缺失”),
功能(
x、 i,j,
滴
) {     
if(i类)=“系数”){
#可能正在尝试查找与此哈希中的有序键关联的值

toReturn谢谢,Tommy。我希望可以避免第二步(查找实际ID)的操作,但您的建议最终可能会达到最佳效果。与其他基于哈希的答案相比,这个解决方案似乎不那么优雅(尽管可能更容易使用),但是--令人惊讶的是--我使用这段代码的性能比使用散列时要好。虽然它是常量,但从散列环境中检索元素的时间足够长,因此当级别数<~4000时,基于数组的代码的性能会更好(散列需要一个常数.25s来格式化10000行df,您的需要.17+.0000212L,其中L是级别数)。因此,我将搁置我的理论算法分析,使用这个!唯一的缺点是在单独的数据结构中存储代码的开销,但假设值的数量>>级别的数量,这可能不值得关注。
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