The R programming language is a foundational element in many areas related to data science and statistics. And there’s good reason for that fact. The language provides users with a mature platform and easily understood syntax. But on top of all that, R approaches every task from a perspective based on data manipulation. This has led to a number of features that make it easy to work with large amounts of information on the fly. And one of the best ways to accomplish this is through anonymous functions.
However, while anonymous functions are an extremely useful part of R they’re not always easy to grasp. But you’ll soon see how you can define anonymous functions in R. Likewise, you’ll discover why doing so can open up a lot of possibilities for faster and more efficient coding practices.
What Are Anonymous Functions?
If you’re familiar with Python you might have some experience with its lambda function. Lambda’s a method by which you can perform on-the-fly calculations that would normally need to be defined as a function. This is relatively analogous to an anonymous function in R.
Consider what the term anonymous means. When we say that we’re anonymous we’re implying that we’re not using a name or stating our identity. And that’s the case for anonymous functions as well. We normally need to state the identity of a new function in R before we can use it. But that’s not the case when we use an anonymous function.
An anonymous function isn’t really defined, called, or treated like a standard function at all. A complex function can essentially sit nestled between otherwise simple processes if it’s anonymous. And this gets to the heart of why anonymous functions are so useful. The functions can dramatically improve your code’s readability by laying out all of a system’s functionality right there in front of the person reviewing it.
We can even nest anonymous functions within other functions. For example, the apply function lets you create loops that go over an entire R collection without needing to manually iterate over each individual element. And we could use anonymous functions within apply to perform specific actions on every item within that collection as a single action.
Introducing the Basic Elements
The prior description sets anonymous functions up as a relatively advanced concept. But the reality is the exact opposite. These functions are important in large part because they allow for elegant simplicity in your code. And this is inherently tied to ease of use. It’s true that there can be a learning curve when getting used to this style. But the following examples will make it clear just how quickly you’ll be able to master the technique. Take a look at a simple script that doesn’t make use of anonymous functions.
ourFunction <- function(x)
y <- x+1
Our example begins by defining a simple function called ourFunction. This function takes x as an argument. The x value is then added to 1 and assigned to a new y variable. The y variable is then sent back through return. This is all fairly straightforward. But how could we improve it with anonymous functions? Take a look at our improved version.
print( (function(x) x + 1)(2) )
We’ve reduced the entire script down to a single, easily readable, line of code. And what’s even more impressive is that this is all done with the base R setup. We’re not using any additional libraries or added functionality. So what’s actually going on in this code to make it run?
A Closer Look at Anonymous Functions
The most obvious element is the print statement that’s encapsulating the rest of the code. This, of course, isn’t really necessary and is only there to offer additional insight when running our script.
Anonymous functions begin with round brackets. This runs somewhat contrary to assumptions about a function definition coming first and then encapsulating the actual code. But here, we need to wrap the function in brackets containing all of the anonymous function’s elements. Next, we use the term function as we normally would in R. This signals the fact that we’ll soon define what parameters will be in use. In this case, we’re using x as our sole parameter. What happens after our function declaration will probably seem a little unusual at first. When anonymous functions are declared there’s no need to use curly brackets. We go straight from stating parameters to using them. In this case, that means performing some simple addition by adding x to 1. We use a closing round bracket to signify the end of the functional element.
After the equivalent to a standard function is written out we need to actually call it. To do so we lay out another opening round bracket. We generate the data used as an argument in our function. In this case that simply means stating a numerical value that will be automatically assigned to x. We then close out the assignment with another closing round bracket and repeat it one more time to complete the print statement.
While print is used here to illustrate what’s going on with the function, it also highlights another important point about anonymous functions. We essentially defined and used a function within a print statement. And we can extend that concept even further, as seen in the following example.
ourDataFrame <- data.frame(First=c(1, 2, 3, 4, 5),
Second=c(6, 7, 8, 9, 10),
Third=c(11, 12, 13, 14, 15),
print(sum(ourDataFrame[(function(x) x + 1)(2)]))
We begin by defining a new data frame as ourDataFrame and populating it with four columns. Next, we use the sum function to add together the contents of a row in ourDataFrame. But the column selected is dependent on a value created by a separate function. And it’s the same anonymous one that we’d created in the previous example. If you recall, that function returns a 3. This is then passed as the argument used in the sum function. And, finally, all of this is used by the print function. So our anonymous function’s sitting with the sum function. And the sum function is contained within print. And all three exist within a single line of code.
This nesting highlights how much more readable code can be when using anonymous functions. Situations where we’re using multiple user-created functions often turn into an exercise in maze running as we jump around in our code to figure out what’s going on. But anonymous functions make it easy to confine functionality to a small area within the larger codebase.
Since anonymous function are useful for looping & apply operations, we include them in this section… more below…
- How To Use the apply function (matrix or data frame)
- How To Use the sapply function (simplified version of lapply)
- How To Use the lapply function (list or vector)
- How To Use the mapply function (applying a function to multiple lists or vectors)
- How To Use the tapply function (levels of a factor)
- While Loops
- For Loops
- Creating Anonymous Functions in R