You can try to work on formating the result of your t-test to be able to use tidy tools.
Here is one way - and surely not the only one and more efficient one.
library(tidyverse)
tibble(a = list(c(1, 2), c(3, 4))) %>%
mutate(low_high = map(a, ~t.test(., conf.level = 0.95)$conf.int %>%
# name the t-test resulting numeric vector
set_names(c("low", "high")) %>%
# transform the vector in tibble
enframe)) %>%
# unnest only this column (keep the a list column)
unnest(low_high, .drop = FALSE) %>%
# spread result using tidy to have two column
spread(name, value)
#> # A tibble: 2 x 3
#> a high low
#> <list> <dbl> <dbl>
#> 1 <dbl [2]> 7.85 -4.85
#> 2 <dbl [2]> 9.85 -2.85
Thanks, cderv.
They are good workarounds for this specific case but unfortunately don't solve the main problem.
Anyway, I was impressed by broom solution
That's a very narrow specific case.
In other words, I think it would be great to have a short expression (1-2 lines of code) when you calculate something once and create more than one column based on it. I believed I missed something in the tidyverse system of packages. If not, it should be:
some complex object in each line
split it into a number of other columns (in my specific case it's 2)
I feel like it would be easier, if it's a fixed number of elements in each vector (as with a confidence interval), to just pull them out individually with map_dbl:
And then just select(-low_high) afterward if you don't want the original list column
It sounds like you want a more general solution, though, so maybe I'm stating the obvious! If I were going to write a function to tackle that workflow, I'd probably try to "unnest" the vectors by creating rows, not columns, as there's no guarantee with a list-column of vectors that each vector will be of the same length (though I suppose you could fill the extra columns for shorter vectors with NA or something).
I think the approach with enframe is rather specific, as it is rowise and you don't need to know the number of element in you complex element. It should apply to all list columns that you want to transform.
Name the vector element in the list column
enframe to get a tibble (this is the step that put it rowise)
unnest the result
spread as desired.
It is not specific to t.test or a two element list.
I think to approach this colwise, it is as @rensa said and gave as example, you need to know the number of element.
In fact, it the complex list is in the correct form you could use the splice operator !!! from rlang. The correct form is a list of desired column.
library(tidyverse)
# takes a column and format result in a list of desired column
conf_int_function <- function(column) {
res <- map(column, ~ t.test(.x, conf.level = 0.95))
conf <- map(res, "conf.int") %>% map(set_names, c('low', 'high'))
transpose(conf) %>% simplify_all()
}
tibble(a = list(c(1, 2), c(3, 4))) %>%
# use the splice operator to get the columns
# You need `.$a` - it is not working with tidyeval
mutate(!!!conf_int_function(.$a))
#> # A tibble: 2 x 3
#> a low high
#> <list> <dbl> <dbl>
#> 1 <dbl [2]> -4.85 7.85
#> 2 <dbl [2]> -2.85 9.85
Looks good! The only caveat I'd mention is that this fails if the vectors in your list-column vary in size at all. That might not be a problem for your use-case, but it might be worth keeping in mind if you use it in production!