当前位置: 首页 > 知识库问答 >
问题:

为什么嵌套的ifelse会在dplyr 0.5中创建不正确的结果。0变异?

亢胤运
2023-03-14

考虑以下数据html" target="_blank">框架:

(tmp_df <-
structure(list(class = c(0L, 0L, 1L, 1L, 2L, 2L), logi = c(TRUE, 
FALSE, TRUE, FALSE, TRUE, FALSE), val = c(1, 1, 1, 1, 1, 1), 
    taken = c(1.00684931506849, 0.993197278911565, 1.025, 0.975609756097561, 
    1.00826446280992, 0.991803278688525)), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -6L), .Names = c("class", 
"logi", "val", "taken")))

这就产生了:

Source: local data frame [6 x 4]

  class  logi   val     taken
  <int> <lgl> <dbl>     <dbl>
1     0  TRUE     1 1.0068493
2     0 FALSE     1 0.9931973
3     1  TRUE     1 1.0250000
4     1 FALSE     1 0.9756098
5     2  TRUE     1 1.0082645
6     2 FALSE     1 0.9918033

我希望按类分组,如果每个组包含两个成员,然后从val中减去1,如果logi==FALSE,否则,从val中减去该组中最小值...如果每个组不包含两个成员,那么我们从val中减去零。

使用dplyr包执行上述操作的代码可以使用以下表达式表示:

tmp_df %>%
    group_by(class) %>%
    mutate(taken_2 = ifelse(n() != 2, 0, 
                              ifelse(logi, min(taken), 1)),
           not_taken = val - taken_2)

但是,这会产生不正确的结果,其中第二个ifelse始终解析为第一个条件:

Source: local data frame [6 x 6]
Groups: class [3]

  class  logi   val     taken   taken_2   not_taken
  <int> <lgl> <dbl>     <dbl>     <dbl>       <dbl>
1     0  TRUE     1 1.0068493 0.9931973 0.006802721
2     0 FALSE     1 0.9931973 0.9931973 0.006802721
3     1  TRUE     1 1.0250000 0.9756098 0.024390244
4     1 FALSE     1 0.9756098 0.9756098 0.024390244
5     2  TRUE     1 1.0082645 0.9918033 0.008196721
6     2 FALSE     1 0.9918033 0.9918033 0.008196721

如果没有第一条ifelse语句,则可以生成正确的结果。

tmp_df %>%
    group_by(class) %>%
    mutate(taken_2 = ifelse(logi, min(taken), 1),
           not_taken = val - taken_2)

生产:

Source: local data frame [6 x 6]
Groups: class [3]

  class  logi   val     taken   taken_2   not_taken
  <int> <lgl> <dbl>     <dbl>     <dbl>       <dbl>
1     0  TRUE     1 1.0068493 0.9931973 0.006802721
2     0 FALSE     1 0.9931973 1.0000000 0.000000000 # correct!
3     1  TRUE     1 1.0250000 0.9756098 0.024390244
4     1 FALSE     1 0.9756098 1.0000000 0.000000000 # correct!
5     2  TRUE     1 1.0082645 0.9918033 0.008196721
6     2 FALSE     1 0.9918033 1.0000000 0.000000000 # correct!

通过检查成功完成类似工作的其他代码片段,我们可以看到这个问题似乎被隔离到mutate和嵌套的ifelse

tmp_df %>%
    group_by(class) %>%
    mutate(taken_2 = ifelse(n() != 3, 0, 
                            ifelse(logi, min(taken), 1)),
           not_taken = val - taken_2)

tmp_df_2 <-
    tmp_df %>%
    filter(row_number() <= 2)

(tmp_df_2$taken_2 <-
    ifelse(c(0, 0), 0, 
           ifelse(tmp_df_2$logi, min(tmp_df_2$taken), 1)))

## but the following does not work (checks problem is not to do with grouping)
# tmp_df_2 %>%
#     mutate(taken_2 = ifelse(n() != 2, 0, 
#                             ifelse(logi, min(taken), 1)),
#            not_taken = val - taken_2)

为什么会发生这种情况,以及如何获得预期的行为?一种解决方法是将嵌套的ifelse逻辑拆分为多个内嵌变异:

tmp_df %>%
    group_by(class) %>%
    mutate(taken_2 = ifelse(n() != 2, 0, 1),
           taken_3 = taken_2 * ifelse(logi, min(taken), 1),
           not_taken = val - taken_3)

其他人发现嵌套的ifelse存在类似的问题,但我不知道它是否具有相同的根:ifelse使用dplyr会导致某些记录的NAs

共有2个答案

上官季
2023-03-14

?如果出现其他情况

“ifelse”返回与“test”形状相同的值。

自从n()!=2返回长度为1的向量,且始终为真,第二个ifelse始终返回长度为1的向量,但会循环使用以适合组的形状。一种解决方案是将组长度的向量馈送到第一个ifelse

tmp_df %>%
    group_by(class) %>%
    mutate(taken_2 = ifelse(rep(n() != 2, n()), 0, 
                              ifelse(logi, min(taken), 1)),
           not_taken = val - taken_2)
# Source: local data frame [6 x 6]
# Groups: class [3]

#   class  logi   val     taken   taken_2   not_taken
#   <int> <lgl> <dbl>     <dbl>     <dbl>       <dbl>
# 1     0  TRUE     1 1.0068493 0.9931973 0.006802721
# 2     0 FALSE     1 0.9931973 1.0000000 0.000000000
# 3     1  TRUE     1 1.0250000 0.9756098 0.024390244
# 4     1 FALSE     1 0.9756098 1.0000000 0.000000000
# 5     2  TRUE     1 1.0082645 0.9918033 0.008196721
# 6     2 FALSE     1 0.9918033 1.0000000 0.000000000
步胜
2023-03-14

你是ifelse向量循环的受害者。关键是这一行:

mutate(taken_2 = ifelse(n() != 2, 0, 
                          ifelse(logi, min(taken), 1))

因为n()!=2是长度-1(对于每组),ifelse只考虑第一个logi并重复/循环该值。

您应该使用ifif\u else

mutate(taken_2 = if (n() != 2) 0 else if_else(logi, min(taken), 1))

我建议永远不要使用ifelse。从一个几乎因为这个错误导致了数百万美元错误的人那里得到的。

 类似资料:
  • 为什么这段代码不生成这样的表; 你会注意到,我想要的格式把所有类似的Y变量在那里自己的块(表)和当我读代码在我的脑海中它应该这样做,但没有这样的运气对我来说,3天与这微不足道的11行代码和我已经尝试了十几个或更多的变化相同的代码和无论我做什么它总是搞砸了这个当前版本产生的结果组合在一起只有X值=5然后噗丢弃所有的其余数据 以上代码的结果:

  • 问题内容: 情况一: 输出: 2005年7月8日星期五00:00:00 GMT-0700(PST) 案例二: 输出: Thu Jul 07 2005 17:00:00 GMT-0700(PST) 为什么第二次解析不正确? 问题答案: 在第5版规范发布之前,该Date.parse方法完全依赖于实现(除后者返回数字而不是a之外,其他方法new Date(string)等效)。在第5版规范中,添加了该要

  • 问题内容: 嵌套的RAL居? 假设我正在尝试做Spark中的“嵌套循环”。就像普通语言一样,假设我在内部循环中有一个例程,该例程以Pi Average Spark示例 的方式估算Pi(请参见估算Pi) 我可以在Spark中嵌套并行化调用吗?我正在尝试,但还没有解决。乐于张贴错误和代码,但我想我要问一个更概念性的问题,即这是否是Spark中的正确方法。 我已经可以并行化一个Spark实例/ Pi估计

  • 问题内容: 我想转换成 我用了 但是我明白了 问题答案: 每月使用CAPITAL M, 另外,您首先要设置日期,然后再重置日历,我想这不是您想要的,可能是因为您需要将其更改为以下内容 看到 API文件

  • 我在测试环境方面工作。

  • “条件是正确的,但结果是空的,为什么?当我没有添加索引时,查询结果是正确的。