dplyr elaborate verb

71 views
Skip to first unread message

Stijn de Waele

unread,
Oct 16, 2016, 6:02:37 PM10/16/16
to manipulatr
I would like to use dplyr in the situation where I perform an operation for each row that returns several rows. This could be called an "elaborate" action, as opposed to summarize. Of course, this can currently be be achieved using do. This is a basic example:

draw <- 1:2; draw <- data.frame(draw)
estimate <- function(d) {
  r <- data.frame(a=1:3, b=11:13)
  cbind(d, r)
}
r <- draw %>%
  rowwise %>%
  do(estimate(.))

Output:
# A tibble: 4 × 3
   draw     a     b
* <int> <int> <int>
1     1     1    11
2     1     2    12
3     2     1    11
4     2     2    12

However, the code is not as compact as I hope it would be. Instead it would be great to replace the code above by:
estimate <- function(d) {
  r <- data.frame(a=1:3, b=11:13)
}
r <- draw %>%
  rowwise %>%
  elaborate(estimate)

Notice that the cbind would be handled automatically by elaborate. Is there already support for this kind of action? If not, could it perhaps be a useful addition?

Thanks for your comments!

Stijn de Waele

unread,
Oct 16, 2016, 9:11:38 PM10/16/16
to manipulatr
To add - elaborate can also operate directly on a dataframe, yielding the following, even more compact, code:

r <- draw %>%
  elaborate(estimate)

holger brandl

unread,
Oct 18, 2016, 4:48:30 AM10/18/16
to manipulatr
Hi,

I also feel that row-wise operations are not so smooth in dplyr. In good old plyr times the combination of adply and splat allowed to write very nice constructs such as:

require(plyr)
require(dplyr)

contrasts = frame_data(
~sample_1, ~sample_2,
"foo", "bar",
"te", "st")

contrasts %>% adply(1,  splat(function(sample_1, sample_2){
# in here sample_1 are scalar variables no indexing is required
mutate(head(iris), samples=paste(sample_1, sample_2))
}))


So far I failed to achieve the same splat-like elegance with dplyr::rowwise:

contrasts %>% rowwise %>% do({
mutate(head(iris), samples=paste(.$sample_1[
1], .$sample_2[1]))
})

We need dots, dollars and indexing, whereas with splat we needed nothing. 

Is there a elegant way to rewrite this (potentially involving a new verb but hopefully not) to combine dplyr::rowwise with plyr::splat?

Thanks,
Holger

holger brandl

unread,
Oct 24, 2016, 9:22:43 AM10/24/16
to manipulatr
I've found a workaround:

contrasts %>% rowwise %>% do(splat(function(sample_1, sample_2){
mutate(head(iris), samples=paste(sample_1, sample_2))
})(.))


The dot invocation of the splat-return value is not really eye-friendly and unreadable for the occasional r-user, but it still feels sufficiently smooth to me.

To use splat without importing the whole plyr:
## selectively import splat into current environment
splat = plyr::splat

## or simply redefine it:
splat = function (flat) {
function(args, ...) {
do.call(flat, c(args, list(...)))
}
}

Cheers,
Holger

Andrew MacDonald

unread,
Oct 26, 2016, 2:52:03 AM10/26/16
to manipulatr

It is possible to do this with purrr in just a few lines:

require(dplyr)
require(purrr)

contrasts = frame_data(
  ~sample_1, ~sample_2,
  
"foo", "bar",
  "te", "st"
)

contrasts %>% 
  split(seq_len(nrow(.))) %>% 
  map_df(~ cbind(.x, head(iris)))

you could also use an approach with nest() and unnest(), but that would take more lines :)

Andrew

--
You received this message because you are subscribed to the Google Groups "manipulatr" group.
To unsubscribe from this group and stop receiving emails from it, send an email to manipulatr+unsubscribe@googlegroups.com.
To post to this group, send email to manip...@googlegroups.com.
Visit this group at https://groups.google.com/group/manipulatr.
For more options, visit https://groups.google.com/d/optout.

holger brandl

unread,
Oct 26, 2016, 5:08:36 AM10/26/16
to manipulatr
Thanks Andrew,

I've also tried purrr which seems to be made for this type of problems, but dplyr-style still seems to me more readable (no formula syntax, no strange .x, less obvious *rowwise* nature of the operation). But probably I'm simply not yet purrrified.

Your solution also made think again about my previous posting and it turned out that it was overly complicated. All that's needed is to "unwrap the ."  using `with`:

contrasts %>% rowwise %>% do(with(., {
mutate(head(iris), samples=paste(sample_1, sample_2))
}))

To me this looks like the most idiomatic tidyverse solution. No need for plyr::splat anymore! The curly brackets are not even needed in the example, and would just  allow to write more complex multiline-expressions within `do`. :-)

Cheers,
Holger
To unsubscribe from this group and stop receiving emails from it, send an email to manipulatr+...@googlegroups.com.

Reply all
Reply to author
Forward
0 new messages