R 因子的哈希或列表备份级别
我正在处理一个从数据库中检索的分类变量,希望使用因子来保持数据的“完整性” 例如,我有一个存储颜色及其相关数字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)数组R 因子的哈希或列表备份级别,r,R,我正在处理一个从数据库中检索的分类变量,希望使用因子来保持数据的“完整性” 例如,我有一个存储颜色及其相关数字ID的表 ID | Color ------+------- 1 | Black 1805 | Red 3704 | White ID |颜色 ------+------- 1 |黑色 1805 |红色 3704 |白色 因此,我想使用一个因子将此信息存储在数据框中,例如: Car Model | Color ----------+------- Civic | B
提前谢谢 嗯,我很确定你不能改变因素的工作方式。因子的级别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