【问题标题】:Change the level of a factor based on the level of another factor根据另一个因素的水平改变一个因素的水平
【发布时间】:2021-02-21 16:29:05
【问题描述】:

我有一个包含许多变量的数据集,其中两个称为“动物”和“植物”。两个变量都是因子,并且都是二元的,即它们要么是文本值,要么是 NA。

例如:

animal <- c(NA, NA, "cat", "cat", NA)
plant  <- c("ivy", NA, "ivy", NA, NA)
value  <- c(1:5)
df     <- data.frame(animal, plant, value)

> df
  animal plant value
1   <NA>   ivy     1
2   <NA>  <NA>     2
3    cat   ivy     3
4    cat  <NA>     4
5   <NA>  <NA>     5

当植物的值为“ivy”,动物的值为“cat”时, 我想将植物的值更改为 NA(即,这两件事不能为真,动物值优先。我的其他变量没有任何变化

我尝试了以下方法,但收到错误消息:

df <- df %>% if (isTRUE(animal == "cat")) {plant==NA}

Error in if (.) isTRUE(animal == "cat") else { : 
  argument is not interpretable as logical
In addition: Warning message:
In if (.) isTRUE(animal == "cat") else { :
  the condition has length > 1 and only the first element will be used

我的目标输出是:

> df
  animal plant value
1   <NA>   ivy     1
2   <NA>  <NA>     2
3    cat  <NA>     3
4    cat  <NA>     4
5   <NA>  <NA>     5

我非常感谢任何帮助。我确信有一种非常简单的方法可以做到这一点,也许我只见树木不见森林。

【问题讨论】:

    标签: r dataframe if-statement na


    【解决方案1】:

    您的问题似乎比您想象的要简单。您只需将所有植物(动物不是NA)转为NA,即可达到相同的效果:

    df$plant[!is.na(df$animal)] <- NA
    

    或者有点花哨:

    is.na(df$plant) <- !is.na(df$animal)
    

    【讨论】:

    • 谢谢!这绝对成功了!我非常感激,谢谢!我知道我错过了一个简单的答案......
    • 很高兴听到它有帮助!为了正确结束这个问题 - 请随意接受其中一个答案。
    【解决方案2】:
    library(dplyr)    
    
    df %>% 
          mutate(plant = case_when(animal == 'cat' & plant == 'ivy' ~ NA_character_,
                                   TRUE ~ plant))
    

    这给了我们:

      animal plant value
    1   <NA>   ivy     1
    2   <NA>  <NA>     2
    3    cat  <NA>     3
    4    cat  <NA>     4
    5   <NA>  <NA>     5
    

    【讨论】:

    • 谢谢!这真的很有用——我肯定学到了很多东西!
    【解决方案3】:

    这里的问题是 == 不能直观地与 R 中的 NA 值一起使用。

    > df[df$animal=="cat",]
         animal plant value
    NA     <NA>  <NA>    NA
    NA.1   <NA>  <NA>    NA
    3       cat   ivy     3
    4       cat  <NA>     4
    NA.2   <NA>  <NA>    NA
    

    例如这里所有行都被返回,因为NA == "ANYTHING" 返回NA

    如果xy 相等而不是NA,或者两者都是NA,您可以定义返回TRUE 的函数。

    is.equal.force <- `%===%` <- function(x,y, vect=T) {
      res <- ifelse(is.na(x),is.na(y),ifelse(!is.na(y)&!is.na(x),x==y, NA))
      if(!vect){
        res <- all(res)
      }
      return(res)
    }
    

    那么你的问题的解决方案就变得简单了:

    df[df$animal%===%"cat"&df$plant%===%"ivy","plant"] <- NA
    df
      animal plant value
    1   <NA>   ivy     1
    2   <NA>  <NA>     2
    3    cat  <NA>     3
    4    cat  <NA>     4
    5   <NA>  <NA>     5
    

    注意这里使用了正确的语法。

    【讨论】:

    • 鉴于手头的任务,这似乎非常复杂。与提供的任何其他解决方案相比,此解决方案有什么好处吗?
    • 我经常使用这个功能。只要您有具有 potential NA 值的向量,== 就会产生意想不到的结果。如果您看不到生成与输入中的 NA 值相关的错误安全代码的价值,我无法帮助您。
    • 还要注意,OP 的真实数据可能与他刚刚给我们的有点简洁的玩具示例不同。
    • 谢谢 - 上面的简单答案有所帮助,但看到这个答案仍然很有帮助。感谢您的宝贵时间!
    【解决方案4】:

    你也可以这样做:

    df[!(is.na(df$animal)|is.na(df$plant)),'plant'] <- NA
    df
      animal plant value
    1   <NA>   ivy     1
    2   <NA>  <NA>     2
    3    cat  <NA>     3
    4    cat  <NA>     4
    5   <NA>  <NA>     5
    

    这也可以表示为:

    df[!is.na(df$animal) & !is.na(df$plant),'plant'] <- NA
    

    【讨论】:

    • 谢谢!这很有用。下面的示例非常简单且有效,但“&”对我来说是新的并且很有用。我很感激人们分享他们的专业知识!
    猜你喜欢
    • 2020-09-29
    • 1970-01-01
    • 2019-02-07
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多