mean()
sum()
sd()
E.g., set defaults for nice plots
plot(1:10)
par(lwd = 2, tcl = 0.3,
font.lab = 2, las = 1,
cex = 1.5, cex.lab = 1.5, cex.axis = 1.5,
mar = c(5,5,2,2))
plot(1:10)
# Calculate the mean of your data
sum(my.data) / length(my.data)
# Function to calculate mean
my.mean <- function(x){
sum(x) / length(x)
}
# Calculate mean of my data
my.mean(my.data)
This code is shorter but harder to understand
data$response.logit <- log(data$response / (1 - data$response))
This code is more lines, but:
separates the what from the how,
is more reliable.
logit <- function(p){
log(p / (1-p))
}
data$response.logit <- logit(data$response)
Functions are self-contained (e.g., do not depend on global variables)
Limit the scope of variables, because they are contained within function body.
Enable easy re-use of code.
Project becomes more modular and easy to change.
Take an object
Perform an action/s
Return another object or output
Name: Can be any valid name. Do not write over existing functions. Follow style guide to function names.
Input arguments: What are the inputs or data to the function? As many inputs as you want.
Actions: What do you want the function to do with the inputs? Create a plot? Calculate a statistic? Run a regression analysis?
Action arguments: Are there any options and/or defaults you want to set?
Output: What output or final product do you want? A scalar? A vector? A dataframe? A plot? A table?
# The basic structure of a function
NAME <- function(ARGUMENTS) {
ACTIONS
return(OUTPUT) # Optional
}
# Create the function my.mean()
my.mean <- function(x) { # Single input called x
output <- sum(x) / length(x) # Calculate output
return(output) # Return output to the user after running the function
}
# Create the function my.mean()
my.mean <- function(x) { # Single input called x
sum(x) / length(x) # Calculate output
}
i. Directly using the data
sum(dat_tree$DBH) / length(dat_tree$DBH)
ii. Turn this into a function
my_mean <- function(dat_tree$DBH){
sum(dat_tree$DBH) / length(dat_tree$DBH)
}
iii. Abstract it
my_mean <- function(x){
sum(x) / length(x)
}
You can call functions from within functions.
We already did this in the function above, where we used sum() and length().
my_mean <- function(x){
sum(x) / length(x)
}
meanSD <- function(x){
out <- c( my_mean(x), sd(x) )
return(out)
}
Multiple inputs
Set defaults
Store your functions in a new customFunctions.R
file.
Use source() to load that file into R
source("customFunctions.R")
Build functions step-by-step.
Test each line.
Test full function on known inputs.
# Good
checkNames()
calcBA()
# Bad
nameChecker()
baCalculator()
# Variables
names_original
names_checked
tree_dbh
tree_ba
# Good
checkNames <- function(x,
names_correct = 'file-of-correct-names.txt'
) {
# Code of function body goes here, indented
}
# Bad
checkNames <- function(x,
names_correct = 'file-of-correct-names.txt') {
# Here it is hard to tell the arguments from the code body
}
# Good
calcCarbon <- function(dbh, height,
genus = 'Quercus')
# Bad
calcCarbon <- function(dbh, height, genus =
'Quercus')
Each line of comment should begin with a hash and a single space.
# A comment explains why
There are many ways to document your functions.
It should include:
Describe what is returned.
# One example
funcName <- function(x, a, b,
arg1 = 'bananas',
arg2 = 6.45) {
# A short description of what the function does
#
# Arguments:
# Followed by a list of the arguments and description
# x: data from ..., numeric
# a: something, numeric
# b: something else, numeric
# arg1: type of fruit, character
# arg2: a constant modifier, numeric
#
# Returns:
# The total biomass of fruit in a forest
code body here
}
Not that kind of list
list()
# A simple list of three integers
x <- list(1, 2, 3)
str(x)
#> List of 3
#> $ : num 1
#> $ : num 2
#> $ : num 3
# We can name each part of the list
x_named <- list(a = 1, b = 2, c = 3)
str(x_named)
#> List of 3
#> $ a: num 1
#> $ b: num 2
#> $ c: num 3
y <- list("a", 1, 1.5, TRUE)
str(y)
#> List of 4
#> $ : chr "a"
#> $ : int 1
#> $ : num 1.5
#> $ : logi TRUE
z <- list(list(1, 2), list(3, 4))
str(z)
#> List of 2
#> $ :List of 2
#> ..$ : num 1
#> ..$ : num 2
#> $ :List of 2
#> ..$ : num 3
#> ..$ : num 4
# An example list
a <- list(a = 1:3, b = "some text", c = pi, d = list(4, 5))
# The structure of 'a'
str(a)
#> List of 4
#> $ a: int [1:3] 1 2 3
#> $ b: chr "some text"
#> $ c: num 3.14
#> $ d:List of 2
#> ..$ : num 4
#> ..$ : num 5
[ ]
[[ ]]
$
[ ]
extracts a sub-list.str(a[1:2])
#> List of 2
#> $ a: int [1:3] 1 2 3
#> $ b: chr "some text"
str( a[c("a", "b")] )
#> List of 2
#> $ a: int [1:3] 1 2 3
#> $ b: chr "some text"
[[ ]]
extracts a single component from a list.str(a[[1]])
#> int [1:3] 1 2 3
$
works for named elements in a list.[[ ]]
, except quotes are not needed.str(a[["a"]])
#> int [1:3] 1 2 3
str(a$a)
#> int [1:3] 1 2 3
Updated: 2017-10-03