5  Functions

Functions are reusable blocks of code designed to perform a specific task.
Writing functions improves clarity, efficiency, and reproducibility.

5.1 Objectives

  • Define and use built-in functions
  • Write custom functions
  • Return single and multiple values
  • Use default arguments
  • Create nested functions
  • Validate arguments using stopifnot()
  • Understand basic error handling

5.2 Built-In Functions

R provides many built-in functions for analysis, including:

5.2.1 Example: mean()

mean(1:5)
[1] 3

Handling missing values:

v <- c(2, NA, 4, NaN, 6)

mean(v)                # returns NA
[1] NA
mean(v, na.rm = TRUE)  # removes missing values
[1] 4

To use functions from packages:

library(dplyr)

# Example of package function
dplyr::select

5.3 Custom Functions

You create a function using function().

5.3.1 Basic Syntax

f <- function(arg1, arg2, arg3, ...){
  # code
}

5.3.2 Example: One Argument

squareroot <- function(a){
  a^0.5
}

squareroot(49)
[1] 7

5.3.3 Example: Two Arguments

Addtwo <- function(a, b){
  a + b
}

Addtwo(1, 2)
[1] 3

5.3.4 Returning Values

R automatically returns the last evaluated expression, but return() makes it explicit.

F2C <- function(temp) {
  c <- (temp - 32) * (5 / 9)
  return(c)
}

F2C(100)
[1] 37.77778

5.3.5 Returning Multiple Values

Use a list to return multiple outputs.

sqsum <- function(a){
  sq <- a^0.5
  sumsq <- a + sq
  output <- list(sq = sq, sumsq = sumsq)
  return(output)
}

sqsum(49)
$sq
[1] 7

$sumsq
[1] 56

5.4 Default Arguments

You can assign default values to arguments.

power <- function(x, exponent = 2){
  x^exponent
}

power(3)       # uses default exponent = 2
[1] 9
power(3, 3)    # overrides default
[1] 27

Default arguments make functions more flexible.

5.5 Nested Functions

Nested functions combine multiple operations inside one expression.

Example using mtcars:

Goal: Compute the mean mpg for cars with 4 cylinders.

Step-by-step approach:

data(mtcars)

ind1 <- mtcars$cyl == 4
ind2 <- mtcars$mpg[ind1]
mean(ind2)
[1] 26.66364

Nested version:

mean(mtcars$mpg[mtcars$cyl == 4])
[1] 26.66364

You can also define functions inside functions:

outer_function <- function(x){
  
  inner_function <- function(y){
    y^2
  }
  
  inner_function(x) + 1
}

outer_function(3)
[1] 10

5.6 Error Handling

Functions should check inputs to avoid incorrect results.

5.6.1 Using stopifnot()

safe_sqrt <- function(x){
  stopifnot(x >= 0)
  sqrt(x)
}

safe_sqrt(9)
[1] 3

If the condition fails, R stops execution.

5.6.2 Using stop()

safe_divide <- function(a, b){
  if(b == 0){
    stop("Division by zero is not allowed.")
  }
  a / b
}

5.6.3 Using warning()

check_positive <- function(x){
  if(x < 0){
    warning("Negative value detected.")
  }
  x
}

5.7 Key Points

  • Functions improve efficiency and readability
  • Built-in functions cover many common tasks
  • Custom functions use function()
  • Use default arguments for flexibility
  • Return multiple values using lists
  • Nested functions simplify complex operations
  • Validate inputs using stopifnot() or stop()