我正在努力验证一个函数来计算我实验室中某个标准的通过率.这背后的数学非常简单:给定了许多通过或失败的测试,通过了多少百分比.
数据将作为一列值提供P1(在第一次测试时传递),F1(在第一次测试时失败)P2或F2(分别在第二次测试时传递或失败).我编写了passRate下面的函数来帮助计算总体通过率(第一次和第二次尝试)以及第一次测试和第二次测试.
设置验证参数的质量专家给了我一个通过和失败计数的列表,我使用test_vector下面的函数将其转换为向量.
一切都看起来很棒,直到我到达Pass数据框的第三行,其中包含来自我的质量专家的通过/失败计数.它不是返回100%的第二次测试通过率,而是返回NA ...但仅在我使用时返回mutate
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))
Run Code Online (Sandbox Code Playgroud)
所以这里有类似于我所做的事情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
Run Code Online (Sandbox Code Playgroud)
比较我用的时候 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
Run Code Online (Sandbox Code Playgroud)
我原以为这些会返回相同的结果.我的猜测是mutate在某个地方遇到问题,因为它假设n每组的行应该映射到n结果中的行(它在n这里计算时会感到困惑吗?),同时summarise知道无论它开始有多少行,它都会以1.
有没有人对这种行为背后的机制有什么想法?
在我看来,这似乎是dplyr和之间的一些干扰plyr。我对另一个不平衡的数据集也有同样的问题(因此分组是必要的),而在第三组中,突变变量错误地为 NA!然后我在家里重现了你的例子。首先,之后
library("dplyr", lib.loc="~/R/x86_64-pc-linux-gnu-library/3.2")
Run Code Online (Sandbox Code Playgroud)
我得到了你的准确结果。plyr然后我执行了我自己的脚本,其中已加载包。在警告不要加载之后plyr,我的第三dplyr组中的 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
Run Code Online (Sandbox Code Playgroud)
然后我做了:
> 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
Run Code Online (Sandbox Code Playgroud)
我知道这不是一个令人满意的答案,因为plyr不应在之后加载,dplyr但也许它可以帮助那些需要的人group_by(id)。或者使用plyr::mutate(). 然后你可以dplyr在之后加载plyr:
> 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
Run Code Online (Sandbox Code Playgroud)