R: apply() + function = no need for loops

In my research, I am constantly running the same computation over every combination of month-day-year-hour in a given sample’s time period. Traditionally, this can be done using loops, like so:

R:

[sourcecode language=”r”]
k = 2008 # year start
j = 1 # month start
i = 1 # day start
h = 1 # hour start

# start nested loops:
for (k in 2008:2010) {
for (j in 1:12) {
for (i in 1:31) {
for (h in 1:24) {

print(paste(‘The date is ‘,paste(j,i,k,sep=’/’),’ hour ‘,h,sep=”))

}}}}
[/sourcecode]

However, there is a cleaner, more efficient way to go. That is, to write a function that takes the day, month, year, etc. as input parameters, and call it using apply(). For a great explanation and introduction to using apply(), sapply(), lapply(), and other derivatives of apply(), see this excellent poston Neil Saunders blog: “What You’re Doing is Rather Desperate”.

To follow our silly example from above, we could create a function that prints the date and hour:

[sourcecode language=”r”]
dateprint = function(MM,DD,YR,HR) {
print(paste(‘The date is ‘,paste(MM,DD,YR,sep=’/’),’ hour ‘,HR,sep=”))
}
[/sourcecode]

Then we could call the function as follows:

[sourcecode language=”r”]
k = c(2008:2010) # year range
j = c(1:12) # month range
i = c(1:31) # day range
h = c(1:24) # hour range

# Call function using apply() and defined parameters
output = apply(expand.grid(j,i,k,h), 1,
function(x,y,z,a) dateprint(x[1],x[2],x[3],x[4]))

# Apply stores the output as a list
# I like to convert it to a dataframe for easier viewing and manipulation.
output=data.frame(output)
[/sourcecode]

Notice that you are essentially giving apply() an “input matrix” created by expand.grid(); apply() takes parameters from each row of that “input matrix” and feeds them to our dateprint() function. You can tell apply() to take parameters from each column by changing the “1” to a “2” within your call of apply().
I am not too close with the back end of R, so I am not certain that using apply() will increase the computational efficiency of your code. That said, it is another approach to solving a common problem, and one I use often. Furthermore, it cleans up your code a scintilla.
Clean code = happy code.

Advertisements

2 thoughts on “R: apply() + function = no need for loops

  1. Wouldnt using i(1:31) make all days for each month 31 I think seq_along in a for loop works better as it accounts for leap years and days of the month

Leave a Reply