Method chaining with R

前端 未结 4 1420
一生所求
一生所求 2021-02-20 14:19

Is it possible to chain functions in R?

Sample data:

m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)

For example, I would like to r

相关标签:
4条回答
  • 2021-02-20 14:55

    I would use the magrittr package. It has a "pipe" operator that takes the result of one function and passes it in as an argument to the next:

    m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)
    
    m %>% mean %>% sum
    

    Ceci n'est pas un pipe!

    0 讨论(0)
  • 2021-02-20 15:03

    Try the functional package:

    library(functional)
    squared <- function(x)x*x
    Compose(sum, squared)(m)
    ## [1] 44100
    squared(sum(m))
    ## [1] 44100
    

    EDIT:

    Regarding the question in the comments of another response about arguments here is an example of composing with arguments. Curry is also from the functional package:

    addn <- function(n, x) x + n
    Compose(Curry(addn, 1), squared)(10)
    ## [1] 121
    squared(addn(1, 10))
    ## [1] 121
    

    EDIT 2:

    Regarding question about debugging, debug works if the function is curried. If its not already curried then wrap it in Curry :

    # this works since addn is curried
    debug(addn)
    Compose(Curry(addn, 1), squared)(10)
    
    # to debug squared put it in a Curry -- so this works:
    debug(squared)
    Compose(Curry(addn, 1), Curry(squared))(10)
    
    0 讨论(0)
  • 2021-02-20 15:10

    In a similar vein to Ben's answer, but allowing arguments:

    `%@%` <- function(x, f) eval.parent(as.call(append(as.list(substitute(f)), list(x), 1)))
    
    x %@% mean %@% sqr # => 6.25
    c(1, 2, NA, 3, 4) %@% mean(na.rm=T) %@% sqr # => 6.25
    m %@% colMeans() %@% sum() # => 21
    
    0 讨论(0)
  • 2021-02-20 15:10

    Sort of, but I think it's un-idiomatic and maybe fragile/not a good idea. (This is implied, I think, by @RichieCotton's comment above.)

    From http://cran.r-project.org/doc/manuals/R-lang.html :

    10.3.4 Special operators

    R allows user-defined infix operators. These have the form of a string of characters delimited by the ‘%’ character. The string can contain any printable character except ‘%’. The escape sequences for strings do not apply here.

    Note that the following operators are predefined

     %% %*% %/% %in% %o% %x%
    
    "%@%" <- function(x,f) {
        f(x)
    }
    
    sqr <- function(x) x^2
    x <- 1:4
    
    x %@% mean  ## 2.5
    x %@% mean %@% sqr  ## 6.25
    x %@% (mean %@% sqr)  ## fails
    

    Given m as defined above -- maybe what you had in mind?

     m %@% colMeans %@% sum  ## 21
    

    Notes:

    • your example is a bit funny, because mean(x) always returns a scalar (i.e. a length-1 vector), so sum(mean(x)) is always going to be the same as mean(x)
    • the infix operators have to be surrounded by %, so you can't have anything as compact as a single symbol (and %% is taken already).
    • this sort of chaining is non-associative, which worries me -- it seems that the examples above work, so R is (apparently) evaluating left-to-right, but I don't know that that's guaranteed ...

    edit: the question now asks how additional arguments can be incorporated. I don't think the syntax suggested (x %@% fun1(arg1) %@% fun2(arg2)) will work without some serious magic. This is the closest I can get at the moment -- creating a wrapper function that creates a modified version of the original function.

    F <- function(f,...) {
        function(x) {
            f(x,...)
        }
    }
    

    Testing:

    pow <- function(x,b=2) { x^b }
    sqr <- function(x) x^2
    x <- 1:4
    
    x %@% F(mean,na.rm=TRUE)  ## 2.5
    x %@% F(mean,na.rm=TRUE) %@% F(pow,3)  ## 16.25
    

    (Note that I have used F as a function here, which may be dicey in some situations because it overwrites the F==FALSE shortcut)

    0 讨论(0)
提交回复
热议问题