library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.3.6 ✔ purrr 0.3.4
## ✔ tibble 3.1.8 ✔ dplyr 1.0.9
## ✔ tidyr 1.2.0 ✔ stringr 1.4.1
## ✔ readr 2.1.2 ✔ forcats 0.5.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(stringr)
# Creating a function called mySum with 2 required arguments
mySum <- function(number1, number2) {
return(number1 + number2)
}
# Defaulting to order of arguments in function
mySum(5, 3)
## [1] 8
# Manually specifying arguments
mySum(number1 = 13, number2 = 1989)
## [1] 2002
mySum(number1 = NA, number2 = 1989)
## [1] NA
You try
# Creating a function called 'myNewSum' that adds two numbers.
myNewSum <- function(number1, number2, remove.na = TRUE) {
# Defines the function 'calcSum' based on whether it receives 'NA' as an output, redefining both numbers inputted as zero.
if(remove.na) {
calcSum <- ifelse(is.na(number1), 0, number1) +
ifelse(is.na(number2), 0, number2)
} else {
# Defines the function 'calcSum' as long as there is no 'NA'.
calcSum <- number1 + number2
}
# Outputs calcSum
return(calcSum)
}
# Creates a function that checks if a string has a given prefix
starts_with_prefix <- function(string, prefix) {
str_sub(string, 1, nchar(prefix)) == prefix
}
starts_with_prefix("anti-hero", prefix = "anti")
## [1] TRUE
starts_with_prefix("anti-hero", prefix = "hero")
## [1] FALSE
# Creating function that drops last value of vector.
drop_last <- function(x) {
if (length(x) <= 1) return(NULL)
x[-length(x)]
}
drop_last(1:5)
## [1] 1 2 3 4
drop_last(c("GVSU","SVSU", "Ashland", "Ferris State"))
## [1] "GVSU" "SVSU" "Ashland"
drop_last("GVSU")
## NULL
# Creating a function that calculates the harmonic mean.
harmonic_mean <- function(x) {
1 / (mean(1 / x))
}
harmonic_mean(1:50)
## [1] 11.11307
mean(1:50)
## [1] 25.5
# Creating geometric mean function.
geometricMean <- function(values) {
n <- length(values)
totalProd <- prod(values)
return(totalProd^(1 / n))
}
geometricMean(1:5)
## [1] 2.605171
mean(1:5)
## [1] 3
# Function to calculate square root
calcSqrt <- function(val) {
if (val >= 0) {
return(val^0.5)
} else {
warning("val is negative but must be >= 0!")
return(NaN)
}
}
calcSqrt(4)
## [1] 2
## [1] 2
calcSqrt(-9)
## Warning in calcSqrt(-9): val is negative but must be >= 0!
## [1] NaN
## [1] NaN
Chained if else statements.
a_b_or_c <- function() {
firstLetter <- str_sub(string, start = 1, end = 1)
if (condition1) {
return("Starts with a!")
# do that
} else if (condition2) {
# do something else
return("Starts with b!")
} else {
return("Doesn't start with a or b!")
#
}
}
#Create a function called is.whole.number(), which checks if a given value is a whole number.
is.whole.number <- function() {
roundedx <- round(x)
return(x == roundedx)
}
#Alternative way
is.whole.number <- function(x) {
flooredx <- floor(x)
return(x == flooredx)
}
is.whole.number(3.1415)
## [1] FALSE
#Create a function that raises a number to a specified power and returns a warning and an NaN value if the number is negative and the power is not a whole number.
raise_power <- function(x, power) {
if(x < 0 & (is.whole.number(x) == FALSE)) {
warning("Check yoruself before you wreck yourself! That power is negative and the number is not a whole number...")
return(NaN)
} else {
return(x^power)
}
}
raise_power(x = 4, power = 2)
## [1] 16
raise_power(x = -9, power = 2)
## [1] 81
raise_power(x = 3, power = 1/3)
## [1] 1.44225
raise_power(x = -3, power = 1/3)
## [1] NaN
The ifelse() function
xs <- c(-2, -1, 0, 1, 2)
ifelse(xs > 0, xs, NA)
## [1] NA NA NA 1 2
# Creating a function called mySum with 2 required arguments, 1 optional argument
myNewSum <- function(number1, number2, remove.na = TRUE) {
if(remove.na) {
calcSum <- ifelse(is.na(number1), 0, number1) +
ifelse(is.na(number2), 0, number2)
} else {
calcSum <- number1 + number2
}
return(calcSum)
}
myNewSum(13, 1989)
## [1] 2002
myNewSum(NA, 1989)
## [1] 1989
myNewSum(NA, 1989, remove.na = FALSE)
## [1] NA
Logical operators.
# The 'or' operator
(3 < 5) || (-1 > 0)
## [1] TRUE
# The 'and' operator
(3 < 5) && (-1 > 0)
## [1] FALSE
# The 'equals' operator
3 == 5
## [1] FALSE
(4/2) == 2
## [1] TRUE
3 != 5
## [1] TRUE
# Vectorized examples
1:4
## [1] 1 2 3 4
1:4 == 3
## [1] FALSE FALSE TRUE FALSE
(1:4 < 4) & (1:4 > 1)
## [1] FALSE TRUE TRUE FALSE
(1:4 < 4) | (1:4 > 1)
## [1] TRUE TRUE TRUE TRUE
# Create a function that takes a numeric vector as input, and returns a single boolean value indicating whether or not the vector has any negative values.
any_negative <- function(numbers) {
return(any(numbers < 0))
}
any_negative(c(1,2,3,0))
## [1] FALSE
any_negative(c(1,2,3))
## [1] FALSE
any_negative(c(1,2,3,-1))
## [1] TRUE
# Does the code (1:4 < 4) & (1:4 > 1) produce the same result as (1:4 < 4) && (1:4 > 1)? Which code achieves what appears to be its intended purpose?
#Looks at all values
(1:4 < 4) & (1:4 > 1)
## [1] FALSE TRUE TRUE FALSE
#Only looks at the 1st value of each vector
(1:4 < 4) && (1:4 > 1)
## [1] FALSE
#The first one is the one we want because the second one can be misleading.