关于dplyr Github repo已经存在一些问题,至少有一个相关的SO问题,但是我认为这些问题都没有完全涵盖我的问题。
tidyr::separate
)有一个特例的答案。do()
”。这是我的用例:我想计算精确的二项式置信区间
dd <- data.frame(x=c(3,4),n=c(10,11))
get_binCI <- function(x,n) {
rbind(setNames(c(binom.test(x,n)$conf.int),c("lwr","upr")))
}
with(dd[1,],get_binCI(x,n))
## lwr upr
## [1,] 0.06673951 0.6524529
我可以使用do()
完成此操作,但我想知道是否有更具表现力的方式(感觉mutate()
可以拥有.n
参数as is being discussed for summarise() ...)
library("dplyr")
dd %>% group_by(x,n) %>%
do(cbind(.,get_binCI(.$x,.$n)))
## Source: local data frame [2 x 4]
## Groups: x, n
##
## x n lwr upr
## 1 3 10 0.06673951 0.6524529
## 2 4 11 0.10926344 0.6920953
答案 0 :(得分:13)
另一种变体,虽然我认为我们都在这里分裂。
> dd <- data.frame(x=c(3,4),n=c(10,11))
> get_binCI <- function(x,n) {
+ as_data_frame(setNames(as.list(binom.test(x,n)$conf.int),c("lwr","upr")))
+ }
>
> dd %>%
+ group_by(x,n) %>%
+ do(get_binCI(.$x,.$n))
Source: local data frame [2 x 4]
Groups: x, n
x n lwr upr
1 3 10 0.06673951 0.6524529
2 4 11 0.10926344 0.6920953
就个人而言,如果我们只是通过可读性,我发现这更可取:
foo <- function(x,n){
bi <- binom.test(x,n)$conf.int
data_frame(lwr = bi[1],
upr = bi[2])
}
dd %>%
group_by(x,n) %>%
do(foo(.$x,.$n))
...但现在我们真的分裂了头发。
答案 1 :(得分:10)
另一种选择可能是使用purrr::map
系列函数。
如果您使用rbind
功能中的dplyr::bind_rows
替换get_binCI
:
library(tidyverse)
dd <- data.frame(x = c(3, 4), n = c(10, 11))
get_binCI <- function(x, n) {
bind_rows(setNames(c(binom.test(x, n)$conf.int), c("lwr", "upr")))
}
您可以将purrr::map2
与tidyr::unnest
一起使用:
dd %>% mutate(result = map2(x, n, get_binCI)) %>% unnest()
#> x n lwr upr
#> 1 3 10 0.06673951 0.6524529
#> 2 4 11 0.10926344 0.6920953
或purrr::map2_dfr
与dplyr::bind_cols
:
dd %>% bind_cols(map2_dfr(.$x, .$n, get_binCI))
#> x n lwr upr
#> 1 3 10 0.06673951 0.6524529
#> 2 4 11 0.10926344 0.6920953
答案 2 :(得分:5)
以下是使用data.table
包而非
首先,对功能进行一点改动
get_binCI <- function(x,n) as.list(setNames(binom.test(x,n)$conf.int, c("lwr", "upr")))
然后,只需
library(data.table)
setDT(dd)[, get_binCI(x, n), by = .(x, n)]
# x n lwr upr
# 1: 3 10 0.06673951 0.6524529
# 2: 4 11 0.10926344 0.6920953
答案 3 :(得分:5)
这使用了“标准”dplyr工作流程,但正如@BenBolker在评论中指出的那样,它需要两次调用get_binCI
:
dd %>% group_by(x,n) %>%
mutate(lwr=get_binCI(x,n)[1],
upr=get_binCI(x,n)[2])
x n lwr upr
1 3 10 0.06673951 0.6524529
2 4 11 0.10926344 0.6920953
答案 4 :(得分:3)
以下是rowwise
和nesting
的一些可能性。
library("dplyr")
library("tidyr")
带有重复x / n组合的数据框,非常有趣
dd <- data.frame(x=c(3, 4, 3), n=c(10, 11, 10))
返回数据框的CI函数版本,如@ Joran的
get_binCI_df <- function(x,n) {
binom.test(x, n)$conf.int %>%
setNames(c("lwr", "upr")) %>%
as.list() %>% as.data.frame()
}
按照x
和n
分组,删除重复项。
dd %>% group_by(x,n) %>% do(get_binCI_df(.$x,.$n))
# # A tibble: 2 x 4
# # Groups: x, n [2]
# x n lwr upr
# <dbl> <dbl> <dbl> <dbl>
# 1 3 10 0.1181172 0.8818828
# 2 4 11 0.1092634 0.6920953
使用rowwise
会保留所有行,但会删除x
和n
,除非您使用cbind(.
将其放回去(就像Ben在他的OP中所做的那样)。
dd %>% rowwise() %>% do(cbind(., get_binCI_df(.$x,.$n)))
# Source: local data frame [3 x 4]
# Groups: <by row>
#
# # A tibble: 3 x 4
# x n lwr upr
# * <dbl> <dbl> <dbl> <dbl>
# 1 3 10 0.06673951 0.6524529
# 2 4 11 0.10926344 0.6920953
# 3 3 10 0.06673951 0.6524529
感觉嵌套可以更干净地工作,但这是我能得到的好。使用mutate
表示我可以直接使用x
和n
代替.$x
和.$n
,但mutate需要单个值,因此需要将其包含在内list
。
dd %>% rowwise() %>% mutate(ci=list(get_binCI_df(x, n))) %>% unnest()
# # A tibble: 3 x 4
# x n lwr upr
# <dbl> <dbl> <dbl> <dbl>
# 1 3 10 0.06673951 0.6524529
# 2 4 11 0.10926344 0.6920953
# 3 3 10 0.06673951 0.6524529
最后,对于dplyr来说,这样的事情是一个公开的问题(截至2017年10月5日);见https://github.com/tidyverse/dplyr/issues/2326;如果实现了类似的东西那么这将是最简单的方法!
答案 5 :(得分:2)
古老的问题(有很多好的答案),但这是tidyverse的broom package的一个很好的用例,它处理来自测试和建模对象(例如binom.test
,{{1 }}等。
它比其他方法更冗长,但我认为它符合您对更具表现力的方法的渴望。
过程是:
lm
上运行的组(在这种情况下,这些组由binom.test
和x
定义)和n
,以创建单独的数据每个.frame(在完整的data.frame中)nest
对每个组的map
和binom.test
值的x
调用n
每个组的tidy
输出(这是扫帚进入的位置)binom.test
整理好的测试输出data.frames到完整data.frame 现在剩下的是一个data.frame,其中每行包含unnest
和x
值,以及来自相应n
的所有输出,并分别用整齐的格式进行格式化输出信息的每一位(点估计,上/下conf,p值等)的列。
binom.test
在这里,您只需进行一点点操作即可选择所需的确切格式,选择所需的输出变量,然后重命名它们:
library(tidyverse)
library(broom)
dd <- data.frame(x=c(3,4),n=c(10,11))
dd %>%
group_by(x, n) %>%
nest() %>%
mutate(test = map(data, ~tidy(binom.test(x, n)))) %>%
unnest(test)
#> # A tibble: 2 x 11
#> # Groups: x, n [2]
#> x n data estimate statistic p.value parameter conf.low conf.high
#> <dbl> <dbl> <lis> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 3 10 <tib… 0.3 3 0.344 10 0.0667 0.652
#> 2 4 11 <tib… 0.364 4 0.549 11 0.109 0.692
#> # … with 2 more variables: method <chr>, alternative <chr>
如前所述,它很冗长。比(例如)@joran简洁优美
dd %>%
group_by(x, n) %>%
nest() %>%
mutate(test = map(data, ~tidy(binom.test(x, n)))) %>%
unnest(test) %>%
rename(lwr = conf.low, upr = conf.high) %>%
select(x, n, lwr, upr)
#> # A tibble: 2 x 4
#> # Groups: x, n [2]
#> x n lwr upr
#> <dbl> <dbl> <dbl> <dbl>
#> 1 3 10 0.0667 0.652
#> 2 4 11 0.109 0.692
但是,扫帚方法的好处是您不需要定义函数dd %>%
group_by(x,n) %>%
do(foo(.$x,.$n))
(或foo
)。它是完全独立的,我认为它更具表现力和灵活性。