5.2 User defined functions

In this section we cover how to write your own user-defined functions (Section 5.2), which as the name suggests are functions you write yourself instead of using the built-in functions.

While there are hundreds of packages that can do everything that you need in R, it is often quicker to write a function to do something specific than it is to find someone else’s function. For purposes of scientific reproducibility, for automation and for clean code, wrapping chunks of code into functions is a must!

Crafting a function is pretty simple. We use the function() command, and provide it with a name for our new function and some logic for that function to perform.

Below we create a very simple function called addOrMinus:

addOrMinus <- function(a, b=2, add=TRUE) {
  if (add) {          # If the logical add is TRUE, then carry out this section
    return(a + b)     # Add a and b and return the result
  } else {            # or if add is FALSE, then do this instead
    return(a - b)     # Subtract b from a and return that result
  }
}

What is happening here?

This function takes the following three arguments:

  1. a required numerical value named a,
  2. an optional numerical value named b and
  3. an optional logical value named add.

Arguments b and add are given default values of 2 and TRUE respectively by using the equal (=) sign in the function declaration. These defaults values are used in the logic of the function if no other values are provided when the function is called.

You call the function using its name and specifying the input:

addOrMinus(1)
## [1] 3
addOrMinus(2, 4)
## [1] 6

and you can assign the answer to a new variable:

answer <- addOrMinus(2, add=FALSE, b=4)

Below is another example calculating the hypotenuse of a triangle:

hypotenuse <- function(a,b) {
  return(sqrt(a^2+b^2))
}
hypotenuse(3,4)

What is happening here? This function takes two numbers and returns the square root of the sum of the squares of those two numbers.

Functions can contain any data-type as input, they can be simple data types (Section 2.3) or even the more complex data structures (Section 2.6). You can have a mixture of required and optional values. By convention, required arguments are listed first, then followed by any optional arguments.

Taking the above hypotenuse function, the second number \(b\) can become optional by specifying a default value, such as:

hypotenuse2 <- function(a,b=3){
  print(paste("a=",a,"and b=",b))
  return(sqrt(a^2+b^2))
}
hypotenuse2(3)
## [1] "a= 3 and b= 3"
## [1] 4.242641
hypotenuse2(234,32)
## [1] "a= 234 and b= 32"
## [1] 236.1779

Creating and using functions

  1. Try the examples above to create and experiment with the two functions.

  2. Create a function that will perform the temperature conversion celsius to fahrenheit: \(F=\frac{9}{5}C+32\). Call the function celsius.to.fahrenheit(minTemp\(X1996)</code> on temperatures from 1996 of our temperature data. Save this to a new variable <code>fahrenheit.1996</code>.</p></li> <li><p>Create another function to perform the ooposite conversion, from fahrenheit to celsius: <span class="math inline">\)C=(F-32)$. Call the function fahrenheit.to.celsius(fahrenheit.1996), did you get the same results?

  3. Now try running either celsius.to.fahrenheit or fahrenheit.to.celsius on the full matrix minTemp.

Expected output for 2: Only the first 6 results are shown

## [1] "Before conversion:"
## [1] 23.4 23.5 24.7 17.8 20.4 20.5
## [1] "Convert to fahrenheit:"
## [1] 74.12 74.30 76.46 64.04 68.72 68.90