为什么“ifelse”会将因子转换为整数?

10

我试图将变量的值更改为NA值,如果它们不在向量中:

sample <- factor(c('01', '014', '1', '14', '24'))
df <- data.frame(var1 = 1:6, var2 = factor(c('01', '24', 'none', '1', 'unknown', '24')))
df$var2 <- ifelse(df$var2 %in% sample, df$var2, NA)

出于某种原因,R不会保留原始的因子变量值,而是将它们转换为数值序列:
> sample <- factor(c('01', '014', '1', '14', '24'))
> df <- data.frame(var1 = 1:6, 
                   var2 = factor(c('01', '24', 'none', '1', 'unknown', '24')))
> class(df$var2)
[1] "factor"
> df
  var1    var2
1    1      01
2    2      24
3    3    none
4    4       1
5    5 unknown
6    6      24
> df$var2 <- ifelse(df$var2 %in% sample, df$var2, NA)
> class(df$var2)
[1] "integer"
> df
  var1 var2
1    1    1
2    2    3
3    3   NA
4    4    2
5    5   NA
6    6    3

为什么会发生这种情况,我应该怎么做才能正确地实现我的目标?
(我需要使用因子而不是整数,以免混淆“01”和“1”,并且我的原始数据集很大,因此使用因子而不是字符应该可以节省一些内存。)

2
尝试使用 dplyr::if_else - tchakravarty
你尝试过在 ifelse() 函数周围简单地添加 as.factor() 吗? 像这样:df$var2 <- as.factor(ifelse(df$var2 %in% sample, df$var2, NA)) - Pierre Chevallier
在R中,默认情况下,当一个由3个元素组成的向量有2个字符和1个数字时,数字会被转换为字符。在你的“sample”示例中,虽然它们都是字符,但包含所有数字值,因此如果else返回数字,则内部ifelse将其作为数字返回。如果您希望它成为字符,请使用as.character():ifelse(var2 %in% sample, as.character(var2), NA) - joel.wilson
1
Q中的一些语句需要澄清,(1) R将character存储得和factor一样高效。我避免使用factor,除非绝对必要。(2)factor的_levels_被存储为integer,所以不会有意外。(3)请阅读help("ifelse")中的_Warning_部分:_结果的模式可能取决于test的值,并且结果的类属性取自test,可能不适用于从yes和no中选择的值。_另请参考那里的建议以避免意外。 - Uwe
1个回答

2
我认为实现你想做的事情的一种方法是改变你的因子水平:
levels(df$var2)[!levels(df$var2) %in% sample] <- NA

通过改变级别,所有不匹配这些级别的值将被转换为因子NA,结果将如下:

df
  var1 var2
1    1   01
2    2   24
3    3 <NA>
4    4    1
5    5 <NA>
6    6   24

> df$var2
[1] 01   24   <NA> 1    <NA> 24  
Levels: 01 1 24

未知值和无值不再包含在因子级别中。 或者,如果您想保留未知值和无值,则可以尝试以下方法:
df$var2[!df$var2 %in% sample] <- NA

> df
  var1 var2
1    1   01
2    2   24
3    3 <NA>
4    4    1
5    5 <NA>
6    6   24


> df$var2
[1] 01   24   <NA> 1    <NA> 24  
Levels: 01 1 24 none unknown

如果ifelse改变了你的数据类型,那么原因在于ifelse不维护数据类型。请参考这里的第二个答案:如何防止ifelse()将日期对象转换为数值对象 另外一种方法是像@tchakravarty在评论中提到的那样,使用dplyr中的if_else函数!

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