dplyr как суммировать и разделять результат из функции, которая возвращает вектор - PullRequest
0 голосов
/ 12 января 2019

Привет, предположим, мне нужно подвести итог по гену из этого data.frame здесь.

g1 = data.frame ( 
      gene = c( "a","a","a","a","b"),
      value = c(1,200,3,5,0)
    )
  gene value
1    a     1
2    a   200
3    a     3
4    a     5
5    b     0

То, что я хочу сделать, это агрегировать по генам, но используя функцию, которая возвращает две переменные. Для этого примера допустим, что эта функция возвращает среднее значение и медиану.

mn <- function ( x ){
    return  ( c( median(x), mean(x) ))
}

Поскольку функция возвращает вектор, мне нужно вызвать его дважды. Есть ли способ разделить результат так, чтобы мне не приходилось рассчитывать его дважды?

g1 %>%
    group_by(gene) %>%
    dplyr::summarize(
        median = mn ( value )[1],  # because mn returns a vector I need to call it twice
        mean = mn ( value )[2]
    ) %>%
    data.frame()

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Вы можете сделать это с помощью dplyr, хотя это не обязательно так интуитивно понятно, как другие решения. Однако функция do() будет работать. ПРИМЕЧАНИЕ. - Я изменил вашу функцию mn(), чтобы присвоить имена возвращаемому вектору.

Вот справочная страница для do(). Сложная часть - как передать объект с пометкой .$.

library(dplyr)
g1 = data.frame ( 
  gene = c( "a","a","a","a","b"),
  value = c(1,200,3,5,0)
)

mn <- function (x){
  return(c(median = median(x), mean = mean(x)))
}


g1 %>% group_by(gene) %>% 
  do(data.frame(t(mn(.$value)))) %>%
  data.frame()
#>   gene median  mean
#> 1    a      4 52.25
#> 2    b      0  0.00

Создано в 2019-01-11 пакетом Представление (v0.2.1)

Не углубляясь в глубокое погружение между data.table и dplyr, вот временное сравнение между двумя решениями на порции данных умеренного размера:

library(data.table)
library(dplyr)
#function
mn <- function (x){
  return(list(median = median(x), mean = mean(x)))
}

#bigger data
g1 = data.frame( 
  gene = gl(1e5, 1e2),
  value = rnorm(1e8)
)

f_dt <- function() setDT(g1)[, mn(value), by = gene]
f_dp <- function() g1 %>% group_by(gene) %>% do(data.frame(t(mn(.$value)))) %>% data.frame()

system.time(f_dt())
#>    user  system elapsed 
#>   11.00    1.53   15.35
system.time(f_dp())
#>    user  system elapsed 
#>   38.09    0.37   39.94

Создано в 2019-01-11 пакетом Представить (v0.2.1)

0 голосов
/ 12 января 2019

Вы не можете сделать это с dplyr, но вы можете сделать это с data.table

library(data.table)

g1 = data.table ( 
  gene = c( "a","a","a","a","b"),
  value = c(1,200,3,5,0))


mn <- function(x){
  return(list(med = median(x), mean = mean(x)))
}


g1[, mn(value), by = gene]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...