# Load packages
library(tidyverse)
library(tidyquant)
library(moments)
library(ggrepel)
library(scales)
library(stringr)
library(timetk)
library(PerformanceAnalytics)

Functions

# A simple square function example
square_number <- function(x) {
  x * x
}

square_number(5)
## [1] 25

When should you write a function

# Create a reproducible dataset
set.seed(1234)
df <- tibble(
  a = rnorm(10),
  b = rnorm(10),
  c = rnorm(10),
  d = rnorm(10)
)

# Rescale function to avoid repeating code
rescale_vec <- function(x) {
  (x - min(x)) / (max(x) - min(x))
}

# Apply the function to each column
df$a <- rescale_vec(df$a)
df$b <- rescale_vec(df$b)
df$c <- rescale_vec(df$c)
df$d <- rescale_vec(df$d)

df
## # A tibble: 10 × 4
##        a      b     c     d
##    <dbl>  <dbl> <dbl> <dbl>
##  1 0.332 0.153  0.782 1    
##  2 0.765 0      0.473 0.519
##  3 1     0.0651 0.498 0.448
##  4 0     0.311  0.943 0.511
##  5 0.809 0.573  0.373 0.168
##  6 0.831 0.260  0     0.308
##  7 0.516 0.143  1     0    
##  8 0.524 0.0255 0.210 0.256
##  9 0.519 0.0472 0.708 0.575
## 10 0.424 1      0.253 0.522

Functions are for humans and computers

# Bad vs. good function naming
add_vals <- function(x, y) {
  x + y
}

add_vals(3, 5)
## [1] 8

Conditional execution

# Define function that uses if, else if, and stop
detect_sign <- function(x) {
  if (x > 0) {
    message("Value is positive")
    print(x)
  } else if (x == 0) {
    warning("Value is zero, but acceptable")
    print(x)
  } else {
    stop("Value is negative. Stopping function.")
  }
}

# Safe test
detect_sign(3)
## [1] 3
# Warning test
detect_sign(0)
## [1] 0
# Error test — comment this line before knitting!
# detect_sign(-1)

Function arguments

# Example vector with NA and outlier
x <- c(1:10, 100, NA)

# Custom wrapper for mean()
mean_remove_na <- function(x, na.rm = TRUE, ...) {
  mean(x, na.rm = na.rm, ...)
}

# Run examples
mean_remove_na(x)
## [1] 14.09091
mean_remove_na(x, na.rm = FALSE)  # Returns NA
## [1] NA
mean_remove_na(x, trim = 0.1)     # Trims outlier
## [1] 6