Подтвердить что ты не робот

Dplyr:: mutate добавить несколько значений

Есть несколько вопросов об этом на dplyr Github repo уже и, по крайней мере, один связанный вопрос SO, но ни один из них вполне охватывает мой вопрос - я думаю.

  • Добавление нескольких столбцов в вызов duter mutate более или менее то, что я хочу, но для этого случая есть специальный случай (tidyr::separate), который не делает Мне кажется, я работаю для меня.
  • Эта проблема ( "суммировать или мутировать с функциями, возвращающими несколько значений/столбцов" ) говорит "use 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 как обсуждается для summary()...)

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
4b9b3361

Ответ 1

Еще один вариант, хотя я думаю, что мы все раскалываем волосы здесь.

> 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))

... но теперь мы действительно раскалываем волосы.

Ответ 2

Здесь быстрое решение с использованием пакета 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

Это использует "стандартный" рабочий процесс 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

Еще одним вариантом может быть использование семейства функций 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

Ответ 5

Вот некоторые возможности с 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(. (как Бен делает в своем 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

Наконец, похоже, что это что-то вроде открытой проблемы (по состоянию на 5 октября 2017 года) для dplyr; см. https://github.com/tidyverse/dplyr/issues/2326; если что-то подобное реализовано, то это будет самый простой способ!