R tips and tricks – higher-order functions

[This article was first published on R – Eran Raviv, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

A higher-order function is a function that takes one or more functions as arguments, and\or returns a function as its result. This can be super handy in programming when you want to tilt your code towards readability and still keep it concise.

Consider the following code:

# Generate some fake data
> eps <- rnorm(10, sd= 5)
> x <- c(1:10)
> y <- 2+2*x + eps
# Load libraries required
> library(quantreg)
> library(magrittr)
> eps <- rnorm(10, sd= 5)
> x <- c(1:10)
> y <- 2+2*x + eps
# create a higher order function
> higher_order_function <- function(func){
+   func(y ~ x) %>% summary
+ }
> 
# Give as an argument the function "lm"
> higher_order_function(lm)

Call:
func(formula = y ~ x)
Residuals:
     Min       1Q   Median       3Q      Max 
-12.0149  -0.7603   1.0969   2.7483   4.2373 
Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)   1.3214     3.3338   0.396  0.70219   
x             2.1690     0.5373   4.037  0.00375 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 4.88 on 8 degrees of freedom
Multiple R-squared:  0.6708,	Adjusted R-squared:  0.6296 
F-statistic:  16.3 on 1 and 8 DF,  p-value: 0.003751

# Now give as an argument the function rq (for regression quantile)
> higher_order_function(rq)

Call: func(formula = y ~ x)
tau: [1] 0.5
Coefficients:
            coefficients lower bd upper bd
(Intercept)  3.80788     -1.26475  6.15759
x            1.83968      1.59747  2.98423

It’s also quite safe to use in that if you provide a non-existent function it would not default to some unknown behavior but will return an error:

> higher_order_function(mm)

Error in eval(lhs, parent, parent) : object 'mm' not found

However, this function can be also written as a sequence of if statements, like so

> if_function <- function(x,y, which_reg){ 
+   if (which_reg== "OLS") { lm(y~x) %>% summary }
+   else if (which_reg== "LAD") { rq(y~x) %>% summary }
+ } 

> if_function(x,y, which_reg= "OLS")

Call:
lm(formula = y ~ x)
Residuals:
     Min       1Q   Median       3Q      Max 
-12.0149  -0.7603   1.0969   2.7483   4.2373 
Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)   1.3214     3.3338   0.396  0.70219   
x             2.1690     0.5373   4.037  0.00375 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 4.88 on 8 degrees of freedom
Multiple R-squared:  0.6708,	Adjusted R-squared:  0.6296 
F-statistic:  16.3 on 1 and 8 DF,  p-value: 0.003751

> if_function(x,y, which_reg= "LAD")
Call: rq(formula = y ~ x)
tau: [1] 0.5
Coefficients:
            coefficients lower bd upper bd
(Intercept)  3.80788     -1.26475  6.15759
x            1.83968      1.59747  2.98423

Using higher-order functions does not seem to create any additional computational cost:

> library(microbenchmark)
> microbenchmark( higher_order_function(rq), if_function(x, y, "LAD") )

Unit: milliseconds
                      expr      min       lq     mean   median       uq
 higher_order_function(rq) 1.463210 1.498967 1.563553 1.527253 1.624969
  if_function(x, y, "LAD") 1.468262 1.498464 1.584453 1.618997 1.644462
      max neval
 2.280419   100
 2.082765   100

> microbenchmark( higher_order_function(lm), if_function(x, y, "OLS") )

Unit: microseconds
                      expr     min       lq     mean   median      uq      max
 higher_order_function(lm) 916.858 928.8825 946.9838 935.3930 955.791 1025.575
  if_function(x, y, "OLS") 918.674 928.1260 953.2587 938.0465 958.284 1433.167
 neval
   100
   100

So you can make your code more concise with little computational overhead.

To leave a comment for the author, please follow the link and comment on their blog: R – Eran Raviv.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)