--- title: "R Functions and Conditional Logic" output: revealjs::revealjs_presentation: theme: white center: true transition: none incremental: true --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) knitr::opts_chunk$set(cache=TRUE) library(knitr) ``` # Conditional Expressions in R ## Exercise: Conditions in R We have touched on many of these before, but here are some examples of expressions (conditions) in R. Evaluate these expressions: ```{r, eval=FALSE} pi > 3 & pi < 3.5 c(1,3,5,7) %in% 1:3 1:3 %in% c(1,3,5,7) rand.uniform <- runif(n = 1, min = 0, max = 1) rand.uniform < .5 ``` ## Solutions: Conditions in R: Evaluated 1 ```{r} pi > 3 & pi < 3.5 c(1,3,5,7) %in% 1:3 1:3 %in% c(1,3,5,7) ``` ## Solutions: Conditions in R: Evaluated 2 ```{r} set.seed(01252020) rand.uniform <- runif(n = 1, min = 0, max = 1); rand.uniform rand.uniform < .5 ``` ## Conditional Expression: If and Else ```{r} print(rand.uniform) ``` Now what does this return? ```{r, eval=FALSE} if (rand.uniform < .5){ print('value less than 1/2') } else { print('value greater than or equal to 1/2') } ``` ## Conditional Expression: If and Else ```{r} print(rand.uniform) if (rand.uniform < .5){ print('value less than 1/2') } else { print('value greater than or equal to 1/2') } ``` ## Conditional Expression: Vectorized? Does this function accept a vector as an input? ```{r, eval=F} rand.uniform2 <- runif(2) print(rand.uniform2) if (rand.uniform2 < .5){ print('value less than 1/2') } else { print('value greater than or equal to 1/2') } ``` ## Conditional Expression: Vectorized? ```{r, eval=T} rand.uniform2 <- runif(2) print(rand.uniform2) ``` ## Conditional Expression: Vectorized? ```{r, eval=T} if (rand.uniform2 < .5){ 'value less than 1/2' } else { 'value greater than 1/2' } ``` ## Conditional Expression, ifelse ```{r} print(rand.uniform2) ifelse(rand.uniform2 < .5,'less than 1/2', 'greater than 1/2') ``` The `ifelse()` function is vectorized and generally preferred with a single set of if/else statements. ## Exercise: Conditional Expression Write a conditional statement that takes a playing card with two arguments: - (`card.number <- '4'` and `card.suit <- 'C'` = 4 of clubs or `card.number <-'K'` and `card.suit <- 'H'` = King of hearts) and - Print `Yes` if the card is a red face card and `No` otherwise. Verify this works using the following inputs: - `card.number <- 'J'` and `card.suit <- 'D'` - `card.number <- 'Q'` and `card.suit <- 'S'` ## Solution: Conditional Expression \footnotesize ```{r} card.number <- 'J' card.suit <- 'D' ifelse(card.number %in% c('J','Q','K') & card.suit %in% c('H','D'),'Yes','No') card.number <- 'Q' card.suit <- 'S' ifelse(card.number %in% c('J','Q','K') & card.suit %in% c('H','D'),'Yes','No') ``` # Writing R Functions ## Organization: Functions Functions should contain a comments section immediately below the function definition line. These comments should consist of >1. a one-sentence description; 2. a list of the functions arguments, denoted by `Args:`, with a description of each and 3. a description of the return value, denoted by `Returns:`. The comments should be descriptive enough that the function can be used without reading the function code. ## Overview Functions in R Functions are a way to save elements of code to be used repeatedly. ```{r} RollDice <- function(num.rolls){ # # ARGS: # RETURNS: return(sample(6, num.rolls, replace = T)) } RollDice(2) ``` ## Exercise: Function Descriptions Document this function with 1. a description, 2. summary of input(s) 3. summary of outputs ```{r} RollDice <- function(num.rolls){ # # ARGS: # RETURNS: return(sample(6, num.rolls, replace = T)) } ``` ## Solution: Function Descriptions ```{r} RollDice <- function(num.rolls){ # function that returns rolls of dice # ARGS: num.rolls - number of rolls # RETURNS: vector of num.rolls of a die return(sample(6, num.rolls, replace = T)) } RollDice(2) ``` ## Format of an R function Here is an example (trivial) R function. ```{r func.def} SquareRoot <- function(value.in){ # function takes square root of value. # Args: value.in - numeric value # Returns: the square root of value.in return(value.in ^ .5) } ``` ## Square Root Function Now consider running the function for a few values. ```{r evalSQ} SquareRoot(9) SquareRoot(25) ``` Now what happens with `SquareRoot(-1)`? ## Square Root Function ```{r neqSQ} SquareRoot(-1) ``` What should happen? ## Errors in R functions Here is an example (trivial) R function. ```{r func.def.new} SquareRoot <- function(value.in){ # function takes square root of value. # Args: value.in - numeric value # Returns: the square root of value.in if (value.in < 0) stop('argument less than zero') return(value.in ^ .5) } ``` ## Square Root Function ```{r neqSQ.new,eval=FALSE} SquareRoot(-1) ``` This returns: ```{r error, eval=FALSE} > SquareRoot(-1) Error in SquareRoot(-1) : argument less than zero ``` ## Exercise: Writing and Documenting a Function Use the defined style guidelines to create an R script that: 1. Takes a state abbreviations as an input 2. Imports a file available at: [http://math.montana.edu/ahoegh/teaching/stat408/datasets/HousingSales.csv](http://math.montana.edu/ahoegh/teaching/stat408/datasets/HousingSales.csv) 3. Creates a subset of housing sales from that state. 4. Returns a vector with the mean closing price in that state. Verify your functions works by running it twice using "MT" and "NE" as inputs. ## Solution: Writing and Documenting a Function ```{r, mysize=TRUE, size='\\tiny'} SummarizeHousingCosts <- function(state){ # computes average sales price in a state # ARGS: state abbr, such as 'MT' or 'CA' # RETURNS: vector with average sales price that each state housing.data <- read.csv( 'http://math.montana.edu/ahoegh/teaching/stat408/datasets/HousingSales.csv') location <- subset(housing.data, State == state) mean.price <- mean(location$Closing_Price) return(mean.price) } ``` ```{r, mysize=TRUE, size='\\footnotesize'} SummarizeHousingCosts('MT') SummarizeHousingCosts('NE') ``` ## Exercise: Functions Part 2 Now write a function that; 1. Takes daily snowfall total in inches as input 2. Takes day of week as input 3. Returns whether to ski or stay home. Also include and the `stop()` function for errors. Test this function with two settings: - snowfall = 15, day = "Sat" - snowfall = -1, day = "Mon" ## Solution: Functions Part 2 ```{r} ToSki <- function(snowfall, day){ # determines whether to ski or stay home # ARGS: snowfall in inches, day as three letter # abbrwith first letter capitalized # RETURNS: string stating whether to ski or not if (snowfall < 0) stop('snowfall should be greater than or equal to zero inches') if (day == 'Sat') { return('Go Ski') } else if (snowfall > 5) { return('Go Ski') } else return('Stay Home') } ``` ## Solution: Functions Part 2 cont.. ```{r, error = T, mysize=TRUE, size='\\small'} ToSki(snowfall = 15, day = "Sat") ToSki(-1, 'Mon') ```