dplyr::mutate会得到x/y = NA,而summarise会得到x/y = 实数

5
我正在验证一个函数,用于计算实验室中某个标准的通过率。这背后的数学非常简单:给定一些测试结果(通过或失败),计算通过的百分比。
数据将作为一列值提供,这些值可以是“P1”(第一次测试通过)、“F1”(第一次测试失败)、“P2”或“F2”(第二次测试通过或失败)。我编写了下面的函数“passRate”,以帮助计算总体(第一次和第二次尝试)以及独立于第一次和第二次测试的通过率。
设置验证参数的质量专员给了我一个通过和失败计数的列表,我正在使用下面的“test_vector”函数将其转换为向量。
一切看起来都很好,直到我到达“Pass”数据框架的第三行,其中包含质量专员的通过/失败计数。当我使用“mutate”时,它返回NA,而不是100%的第二次测试通过率。
library(dplyr)

Pass <- structure(list(P1 = c(2L, 0L, 10L), 
                       F1 = c(0L, 2L, 0L), 
                       P2 = c(0L, 3L, 2L), 
                       F2 = c(0L, 2L, 0L), 
                       id = 1:3), 
                  .Names = c("P1", "F1", "P2", "F2", "id"), 
                  class = c("tbl_df", "data.frame"), 
                  row.names = c(NA, -3L))

以下是类似于我使用mutate的操作。

Pass %>%
  group_by(id) %>%
  mutate(pass_rate = (P1 + P2) / (P1 + P2 + F1 + F2) * 100,
         pass_rate1 = P1 / (P1 + F1) * 100,
         pass_rate2 = P2 / (P2 + F2) * 100)

Source: local data frame [3 x 8]
Groups: id [3]

     P1    F1    P2    F2    id pass_rate pass_rate1 pass_rate2
  (int) (int) (int) (int) (int)     (dbl)      (dbl)      (dbl)
1     2     0     0     0     1 100.00000        100         NA
2     0     2     3     2     2  42.85714          0         60
3    10     0     3     1     3 100.00000        100         NA

当我使用summarise时进行比较

Pass %>%
  group_by(id) %>%
  summarise(pass_rate = (P1 + P2) / (P1 + P2 + F1 + F2) * 100,
            pass_rate1 = P1 / (P1 + F1) * 100,
            pass_rate2 = P2 / (P2 + F2) * 100)

Source: local data frame [3 x 4]

     id pass_rate pass_rate1 pass_rate2
  (int)     (dbl)      (dbl)      (dbl)
1     1 100.00000        100         NA
2     2  42.85714          0         60
3     3 100.00000        100        100

我本来期望这两个函数返回的结果是相同的。 我猜测是因为“mutate”在某个地方出了问题,因为它假设每组中的“n”行应映射到结果中的“n”行(它是否在计算“n”时被混淆了?),而“summarise”知道无论它从多少行开始,最终只会有1行。
有人对这种行为背后的机制有什么想法吗?

3
这个例子非常复杂。你有一个更简单的例子来说明听起来像是一个 bug(在你的标题中)吗?这是典型的参考文献:[mcve] - Frank
你说得对,我没有花太多时间尝试解开它。我已经加入了代码,直接计算结果,而不需要所有额外的函数。 - Benjamin
4
看起来像是一个bug:Pass <- data.frame(P2 = c(0,3,2), F2 = c(0,2,0), id = 1:3); Pass %>% group_by(id) %>% mutate(pass2 = P2/(P2 + F2))。第三行不应该有任何NA。 - jeremycg
4
可能是与这里相同的错误。 - jeremycg
就像那个问题中提到的那样,我认为可以公正地说,在使用mutate时,我可能试图做太多事情了(至少在我的初始复杂示例中),应该采用dosummarise的组合方法来处理它,因为事实证明,在简化的示例中,如果您删除group_by并直接使用mutate,则会得到预期的结果。所以也许这只是一种分组滥用的情况? - Benjamin
1个回答

3
我觉得这个问题似乎是由于和之间的某些干扰引起的。我在另一个不平衡数据集上也遇到了同样的问题(因此需要分组),在第三组中,突变的变量错误地成为NA!然后我在家复制了您的示例。首先,在

之后:
library("dplyr", lib.loc="~/R/x86_64-pc-linux-gnu-library/3.2")

我得到了和你一模一样的结果。然后,我执行了自己的脚本,在其中加载了 plyr 包。在警告不要在 dplyr 之后加载 plyr 后,我的第三个组中的 NA 就消失了,并且你的示例也被正确地计算了!这是我所做的(我添加了一行以查看 NA 是否仍保留在第三组中):

> Pass <- structure(list(P1 = c(2L, 0L, 10L,8L), 
+                        F1 = c(0L, 2L, 0L, 4L), 
+                        P2 = c(0L, 3L, 2L, 2L), 
+                        F2 = c(0L, 2L, 0L, 1L), 
+                        id = 1:4), 
+                   .Names = c("P1", "F1", "P2", "F2", "id"), 
+                   class = c("tbl_df", "data.frame"), 
+                   row.names = c(NA, -4L))
> Pass %>%
+     group_by(id) %>%
+     mutate(pass_rate = (P1 + P2) / (P1 + P2 + F1 + F2) * 100,
+            pass_rate1 = P1 / (P1 + F1) * 100,
+            pass_rate2 = P2 / (P2 + F2) * 100)
Source: local data frame [4 x 8]
Groups: id [4]

 P1    F1    P2    F2    id pass_rate pass_rate1 pass_rate2
(int) (int) (int) (int) (int)     (dbl)      (dbl)      (dbl)
 1     2     0     0     0     1 100.00000  100.00000         NA
 2     0     2     3     2     2  42.85714    0.00000   60.00000
 3    10     0     2     0     3 100.00000  100.00000         NA
 4     8     4     2     1     4  66.66667   66.66667   66.66667

然后我执行了以下操作:
> library("plyr", lib.loc="~/R/x86_64-pc-linux-gnu-library/3.2")
> Pass %>%
+     group_by(id) %>%
+     mutate(pass_rate = (P1 + P2) / (P1 + P2 + F1 + F2) * 100,
+            pass_rate1 = P1 / (P1 + F1) * 100,
+            pass_rate2 = P2 / (P2 + F2) * 100)
Source: local data frame [4 x 8]
Groups: id [4]

 P1    F1    P2    F2    id pass_rate pass_rate1 pass_rate2
(int) (int) (int) (int) (int)     (dbl)      (dbl)      (dbl)
 1     2     0     0     0     1 100.00000  100.00000        NaN
 2     0     2     3     2     2  42.85714    0.00000   60.00000
 3    10     0     2     0     3 100.00000  100.00000  100.00000
 4     8     4     2     1     4  66.66667   66.66667   66.66667

我知道这不是一个令人满意的答案,因为plyr不应该在dplyr之后被加载,但对于那些需要使用group_by(id)或者使用plyr::mutate()的人可能会有所帮助。然后你可以在加载plyr之后再加载dplyr

 > Pass %>%
+     group_by(id) %>%
+     plyr::mutate(pass_rate = (P1 + P2) / (P1 + P2 + F1 + F2) * 100,
+            pass_rate1 = P1 / (P1 + F1) * 100,
+            pass_rate2 = P2 / (P2 + F2) * 100)
Source: local data frame [4 x 8]
Groups: id [4]

 P1    F1    P2    F2    id pass_rate pass_rate1 pass_rate2
(int) (int) (int) (int) (int)     (dbl)      (dbl)      (dbl)
 1     2     0     0     0     1 100.00000  100.00000        NaN
 2     0     2     3     2     2  42.85714    0.00000   60.00000
 3    10     0     2     0     3 100.00000  100.00000  100.00000
 4     8     4     2     1     4  66.66667   66.66667   66.66667

有些事情我从未想过。迷人的副作用。 - Benjamin
我认为这主要是由于在加载plyr后,group_by无法正常工作。 - jeremycg

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