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
Ответы
Ответ 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; если что-то подобное реализовано, то это будет самый простой способ!