Il y a quelques problèmes à ce sujet sur le dplyr Github repo déjà, et au moins une question connexe SO, mais aucun d'eux ne couvre tout à fait ma question - je pense.
tidyr::separate
) Qui ne fonctionne pas (je pense) pour moi.do()
".Voici mon cas d'utilisation: je veux calculer les intervalles de confiance binomiaux exacts
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
Je peux faire ça avec do()
mais je me demande s'il y a une manière plus expressive de faire ça (on dirait que mutate()
pourrait ont un argument .n
comme cela est discuté pour resume () ...)
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
Encore une autre variante, même si je pense que nous partageons tous des cheveux ici.
> 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
Personnellement, si nous allons juste par lisibilité, je trouve cela préférable:
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))
... mais maintenant nous sommes vraiment coupant les cheveux.
Une autre option pourrait être d'utiliser le purrr::map
famille de fonctions.
Si vous remplacez rbind
par dplyr::bind_rows
dans le get_binCI
fonction:
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")))
}
Vous pouvez utiliser purrr::map2
avec 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
Ou purrr::map2_dfr
avec 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
Voici une solution rapide en utilisant data.table
package à la place
Tout d'abord, un petit changement dans la fonction
get_binCI <- function(x,n) as.list(setNames(binom.test(x,n)$conf.int, c("lwr", "upr")))
Ensuite, simplement
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
Cela utilise un flux de travail dplyr "standard", mais comme @BenBolker le note dans les commentaires, il nécessite d'appeler get_binCI
deux fois:
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
Voici quelques possibilités avec rowwise
et nesting
.
library("dplyr")
library("tidyr")
trame de données avec des combinaisons répétées x/n, pour le plaisir
dd <- data.frame(x=c(3, 4, 3), n=c(10, 11, 10))
une version de la fonction CI qui renvoie une trame de données, comme celle de @ Joran
get_binCI_df <- function(x,n) {
binom.test(x, n)$conf.int %>%
setNames(c("lwr", "upr")) %>%
as.list() %>% as.data.frame()
}
Le regroupement par x
et n
comme précédemment, supprime le doublon.
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
L'utilisation de rowwise
conserve toutes les lignes mais supprime x
et n
à moins que vous ne les remettiez à l'aide de cbind(.
(comme Ben le fait dans son 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
J'ai l'impression que la nidification pourrait fonctionner plus proprement, mais c'est aussi bon que possible. L'utilisation de mutate
signifie que je peux utiliser x
et n
directement au lieu de .$x
et .$n
, mais mutate attend une valeur unique, elle doit donc être enveloppée dans 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
Enfin, il semble que quelque chose comme ceci soit un problème ouvert (au 5 octobre 2017) pour dplyr; voir https://github.com/tidyverse/dplyr/issues/2326 ; si quelque chose comme ça est implémenté, ce sera le moyen le plus simple!