如何在改变水平时保留NA值

3
我创建了一个包含NA值的因子向量。
my_vec <- factor(c(NA,"a","b"),exclude=NULL)
levels(my_vec)
# [1] "a" "b" NA 

我修改了其中一个级别。
levels(my_vec)[levels(my_vec) == "b"] <- "c"

NA消失了。
levels(my_vec)
# [1] "a" "c"

我该怎么保留它?


编辑

@rawr提供了一个不错的解决方案,可以大多数情况下工作,它适用于我的先前特定示例,但对于下面我将展示的示例则无效。 @Hack-R提供了一种实用的选项,使用addNA我可以使其正常工作,但我更喜欢一个完全通用的解决方案。

请参阅这个广义问题

my_vec <- factor(c(NA,"a","b1","b2"),levels = c("a",NA,"b1","b2"),exclude=NULL)
levels(my_vec)
[1] "a"  NA   "b1" "b2"
levels(my_vec)[levels(my_vec) %in% c("b1","b2")] <- "c"
levels(my_vec)
[1] "a" "c"      # NA disppeared

@rawr的解决方案:
my_vec <- factor(c(NA,"a","b1","b2"),levels = c("a",NA,"b1","b2"),exclude=NULL)
levels(my_vec)
[1] "a"  NA   "b1" "b2"
attr(my_vec, 'levels')[levels(my_vec) %in% c("b1","b2")] <- "c"
levels(my_vec)
droplevels(my_vec)
[1] "a" NA  "c" "c" # c is duplicated

@Hack-R的解决方案:
my_vec <- factor(c(NA,"a","b1","b2"),levels = c("a",NA,"b1","b2"),exclude=NULL)
levels(my_vec)
[1] "a"  NA   "b1" "b2"
levels(my_vec)[levels(my_vec) %in% c("b1","b2")] <- "c"
my_vec <- addNA(my_vec)
levels(my_vec)
[1] "a" "c" NA     # NA is in the end

I want levels(my_vec) == c("a",NA,"c")


2
有趣的是,?levels 表明你的方法是首选,但是 attr(my_vec, 'levels')[attr(my_vec, 'levels') == 'b'] <- 'c' 的效果也是符合预期的。 - rawr
1
attr(my_vec, 'levels')[levels(my_vec) == "b"] <- 'c'同样有效,这将解决我的问题,现在知道为什么会这样也是不错的 :) - moodymudskipper
1
要了解这个,你就必须挖掘原始数据:function (x, value) .Primitive("levels<-") : 祝你好运 ;-) - Cath
1
因此,它基于这个C函数 - Cath
1
@Cath 是的,在那种情况下,alexis-laz,在sotos发布的链接中的评论会起作用,vec <- factor(c("a","b", NA), levels=paste(c("a","b", NA))) - lmo
显示剩余11条评论
2个回答

1
你需要引用NA,否则R会将其视为null值而不是因子级别。因子级别默认按字母顺序排序,但显然这并不总是有用的,所以你可以通过向levels()传递一个新的列表顺序来指定不同的顺序。
require(plyr)
my_vec <- factor(c("NA","a","b1","b2"))
vec2 <- revalue(my_vec,c("b1"="c","b2"="c"))

#now reorder levels

my_vec2 <- factor(vec2, levels(vec2)[c(1,3,2)])

Levels: a NA c

如果你引用它,它就不再是NA了 :) - moodymudskipper
@Moody_Mudskipper 对于你来说,是这样的。如果你想将NA存储为factor级别,那么无论NA是一个字符串还是一个真正的<NA>值都不应该有任何区别,实际上,最好将NA存储为字符串,这样你就不必为每个操作传递特殊规则以处理NA。 - Mako212
有很多需要替换的内容,一些是要更改的 is.na 等等,这并不是那么简单。 - moodymudskipper
每当我做像用"NA"替换NA这样的事情时,我感觉可能有更简洁的方法,我开始怀疑NA因素是否有帮助,也许在需要之前使用addNA才是最清洁的方式。 - moodymudskipper

0

我终于创建了一个函数,首先用临时值(受@lmo启发)替换NA值,然后按照标准方式进行所需的替换,最后使用@rawr的建议将NA放回原位。

my_vec <- factor(c(NA,"a","b1","b2"),levels = c("a",NA,"b1","b2"),exclude=NULL)
my_vec <- level_sub(my_vec,c("b1","b2"),"c")
my_vec
# 1] <NA> a    c    c   
# Levels: a <NA> c

作为奖励,level_sub 可以与 na_rep = NULL 一起使用,这将删除 NA,并且在管道链中看起来很好:)。
level_sub <- function(x,from,to,na_rep = "NA"){
  if(!is.null(na_rep)) {levels(x)[is.na(levels(x))] <- na_rep}
  levels(x)[levels(x) %in% from] <- to
  if(!is.null(na_rep)) {attr(x, 'levels')[levels(x) == na_rep] <- NA}
  x
}

尽管如此,似乎R确实不希望您将NA添加到因子中。

levels(my_vec) <- c(NA,"a")会产生奇怪的行为,但这并不止于此。虽然subset将保留列中的NA级别,但rbind会悄悄地删除它们!如果进一步调查发现有一半的R函数都会删除NA因子,则我不会感到惊讶,这使得它们非常不安全...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接