nathaneastwood / poorman

A poor man's dependency free grammar of data manipulation
https://nathaneastwood.github.io/poorman/
Other
338 stars 15 forks source link

Standard evaluation functions #25

Open thomas-neitmann opened 4 years ago

thomas-neitmann commented 4 years ago

{dplyr} used to offer verbs with standard evaluation, e.g. mutate_(). Unfortunately, these have been deprecated. I think they are super useful, though, and would love to see them in {poorman}.

On a related note, how would one turn a {poorman} chain into a function? With {dplyr} and {rlang} I'd do something like this:

avg <- function(data, what, by) {
  by <- rlang::enquo(by)
  what <- rlang::enquo(what)
  data %>%
    dplyr::group_by(!!by) %>%
    dplyr::summarise(avg = mean(!!what))
}

I guess this would do the job with {poorman}?

avg <- function(data, what, by) {
  data %>%
    poorman::group_by(substitute(by)) %>%
    poorman::summarise(avg = mean(substitute(what)))
}
nathaneastwood commented 4 years ago

Hmm, that's not a bad suggestion to be honest. I guess I need to decide what I want {poorman} to be. The original idea was for it to be a carbon copy of {dplyr} but there is no reason why it couldn't deviate if it adds to the experience.

As for the avg() function, I don't think that would work with the way group_by() is currently implemented. However, I do plan on overhauling the internals bit by bit. I did select() with the v0.2.0 release and I will slowly do more as and when I get time.

couthcommander commented 4 years ago

Not sure if it works for everything, but in this case you could wrap it with eval(substitute(...)):

avg <- function(data, what, by) {
  eval(substitute(
    data %>%
      poorman::group_by(by) %>%
      poorman::summarise(avg = mean(what))
  ))
}

Love what you're doing with this package

nathaneastwood commented 4 years ago

That's a great solution 😄 I should have thought of that really 😅 and thank you, I will continue developing and adding more stuff - I have some pretty big plans.

bwiernik commented 4 years ago

Personally, I would recommend against adding functions to poorman. Going from dplyr -> poorman is important, but potentially also going from poorman -> dplyr.

nathaneastwood commented 4 years ago

Yes that is a very valid point. Thus far, I am trying to copy the API exactly and so adding these functions would go against that design philosophy. Food for thought!

nathaneastwood commented 4 years ago

FYI in relation to this original question. Another way to solve the problem which is similar to {rlang} would be

avg <- function(data, what, by) {
  by <- substitute(by)
  what <- substitute(what)
  eval(bquote(
    data %>%
    group_by(.(by)) %>%
    summarise(avg = mean(.(what)))
  ))
}

mtcars %>% avg(mpg, am)
thomas-neitmann commented 4 years ago

That's a neat solution @nathaneastwood!

Regarding @bwiernik's comment, I actually don't see many going the {poorman} -> {dplyr} direction. Fundamentally, I think the question is, do you think standard evaluation function would add value to the package? I certainly think they do, quite a bit actually. While the eval() + bquote() combination gets the job done, I think simply being able to pass strings of column names to summarise(), filter(), etc. would make it much easier to program with.

nathaneastwood commented 4 years ago

So my ambition is that I can have the best of both worlds in a single function. But I haven’t quite worked out all of the details just yet. We shall see.

torfason commented 3 years ago

I very much like the idea that not only should code written with dplyr work with poorman (to the extent possible), but also that code written with poorman should work with dplyr. I can see a number of use-cases where I might start off with poorman but then have to switch over to dplyr (because of features or co-authors), and knowing that I don't need to update any code that ran with poorman is quite useful.

An expanded package would therefore be my preference for any extra functions or features, and that package could import and re-export the poorman functions. One potential name for such a package would be richman :-)

ggrothendieck commented 11 months ago

There could be a poormanExtra package for functions that do not correspond to tidyverse. That would make it clear what is reverseable and what not.