【问题标题】:handling NA in if_else in r在 r 中处理 if_else 中的 NA
【发布时间】:2017-06-23 20:43:05
【问题描述】:

我有以下数据集,其中包含包含日期的三列。

library(dplyr)

set.seed(45)

df1 <- data.frame(hire_date = sample(seq(as.Date('1999/01/01'),    as.Date('2000/01/01'), by="week"), 10),
              t1 = sample(seq(as.Date('2000/01/01'), as.Date('2001/01/01'), by="week"), 10),
              t2 = sample(seq(as.Date('2000/01/01'), as.Date('2001/01/01'), by="day"), 10))

#this value is actually unknown
df1[10,2] <- NA

    hire_date         t1         t2
1  1999-08-20 2000-05-13 2000-02-17   
2  1999-04-23 2000-11-11 2000-04-27   
3  1999-03-26 2000-04-15 2000-08-01   
4  1999-05-07 2000-06-03 2000-08-29   
5  1999-04-30 2000-05-27 2000-11-19   
6  1999-04-09 2000-12-30 2000-01-26   
7  1999-03-12 2000-12-23 2000-12-07  
8  1999-06-25 2000-02-12 2000-09-26  
9  1999-02-26 2000-05-06 2000-08-23 
10 1999-01-01       <NA> 2000-03-18 

如果 t1 OR t2 和hire_date 之间的差异在 [395,500] 之间,我想执行一个 if else 语句,这样 df1$com 为 1

下面的 if_else 语句几乎可以让我到达那里,但 NA 把它搞砸了。有什么想法吗?

df1$com <- if_else((df1$t1 - df1$hire_date) >= 395 &
               (df1$t1 - df1$hire_date) <= 500, 1,
       if_else((df1$t2 - df1$hire_date) >= 395 &
                (df1$t2 - df1$hire_date) <= 500, 1, 0))

【问题讨论】:

  • 也许在这里和那里添加一些&amp; !is.na 语句。
  • 应该如何处理NA
  • 这样的...df1$com &lt;- if_else(!is.na(df1$t1) &amp; (df1$t1 - df1$hire_date) &gt;= 395 &amp; (df1$t1 - df1$hire_date) &lt;= 500, 1, if_else(!is.na(df1$t2) &amp; (df1$t2 - df1$hire_date) &gt;= 395 &amp; (df1$t2 - df1$hire_date) &lt;= 500, 1, 0))?
  • 是的,我想我已经盯着它太久了,以至于没有意识到这是显而易见的解决方案。感谢您的帮助!

标签: r if-statement dplyr


【解决方案1】:

您可以使用dplyr::case_when 而不是嵌套if_else 语句。它可以让您轻松控制如何对待NAdplyr::between 也会为您的日期比较进行清理。

df1 %>%
  mutate(com = case_when(
    is.na(t1) | is.na(t2) ~ 999, # or however you want to treat NA cases
    between(t1 - hire_date, 395, 500) ~ 1,
    between(t2 - hire_date, 395, 500) ~ 1,
    TRUE ~ 0 # neither range is between 395 and 500
  ))

#>     hire_date         t1         t2 com
#> 1  1999-08-20 2000-05-13 2000-02-17   0
#> 2  1999-04-23 2000-11-11 2000-04-27   0
#> 3  1999-03-26 2000-04-15 2000-08-01   1
#> 4  1999-05-07 2000-06-03 2000-08-29   1
#> 5  1999-04-30 2000-05-27 2000-11-19   0
#> 6  1999-04-09 2000-12-30 2000-01-26   0
#> 7  1999-03-12 2000-12-23 2000-12-07   0
#> 8  1999-06-25 2000-02-12 2000-09-26   1
#> 9  1999-02-26 2000-05-06 2000-08-23   1
#> 10 1999-01-01       <NA> 2000-03-18 999

【讨论】:

  • 感谢提示:dplyr::between。我从未使用过 case_when 并将继续阅读它。你的答案的问题是我不在乎是否缺少一个或另一个,我只想确保 t1 或 t2 和hire_date 之间的差异在 395 和 500 之间。你的代码使 df1$com == 999如果缺少 t1 或 t2。
  • 我明白了,从您的帖子中不清楚NA 的期望行为是什么。在这种情况下,只需删除我的case_when 命令中以is.na(... 开头的第一行
  • 删除 'is.na(...' 让我离开了我开始的地方。由于 t1 是 'NA' 它不会评估 t2。
  • 如果我注释掉上面case_when 块中的第一行,我得到[1] 0 0 1 1 0 0 0 1 1 1 作为case_when 的结果——最后一个值来自它评估t2。 case_when 不会在 NA 处停止评估,它会寻找 TRUE 条件。比较得到NAif_else(NA, 0, 1) 和得到1case_when(NA ~ 0, TRUE ~ 1)。当 t1 上的第一个 between 语句计算结果为 NA 时,它会前进到下一行并查看 t2。
  • 您的回答很明确,完全有道理。不幸的是,当我注释掉第一行时,我得到以下 [1] 0 0 1 1 0 0 0 1 1 NA
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-19
  • 2017-04-17
  • 2012-07-17
  • 2018-08-07
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
相关资源
最近更新 更多