\(~~~~~~\)R Programming: Programming\(~~~~~~\)

Somsak Chanaim

International College of Digital Innovation, CMU

October 31, 2024

What is a function?

A function is a relationship that assigns each input from a set to exactly one output. Each function has a domain, which is the set of inputs, and a codomain or range, representing possible outputs. Functions are typically represented as \(f(x)\), where \(x\) denotes the input. In mathematical terms, this is commonly expressed as \[y = f(x).\]

In computer programming

A function is a block of organized, reusable code to perform a single, related action. As a result, functions provide better modularity for your application and a high degree of code reusing.

How to write a function in R language?

Defining R functions

In order to write a function in R you first need to know how the syntax of the function command is. The basic R function syntax is as follows:

function_name <- function(arg1, arg2, ...) {
  # Code for the function
  # Operations using the arguments
  result <- some_calculations
  
  # Return the result
  return(result)
}

In the previous code block we have the following parts:

  • arg1, arg2, … are the input arguments.

The output of the return() function can be a vector, matrix, data frame, list, plot, or another object types.

Creating a function in R

Example

We will create a function to work with geometric progressions. A geometric progression is a succession of numbers \(a_1\), \(a_2\), \(a_3,~\cdots\) such that each of them (except the first) is equal to the last multiplied by a constant \(r,r\in (0,1)\) called ratio. You can verify that, \[\begin{align*} a_1&=ar^0\\ a_2 &=a_1\times r=ar\\ a_3&=a_2\times r=ar^2\\ &\vdots\\ a_n&=a_{n-1}\times r =ar^{n-1} \end{align*}\] You can also verify that the sum of the n terms of the progression is \[S_n=a_1+a_2+\cdots + a_n =\dfrac{a(r^n-1)}{r-1}\]

ล “The application of this formula is the annuity function.

What is the amount of money to deposit initially (at time \(t = 0\)), such that we can withdraw \(a at times t = 0, 1, \cdots, n - 1\)? Here, \(r\) represents the discount rate.”

annuity.ver1() function

annuity.ver2() function

that calculates the general term \(a_n\) of a geometric progression giving the parameters \(a\) , the ratio \(r\) and the value \(n\).

Note

Which one is better and why?

Input arguments in R functions

Arguments are input values of functions. As an example, on the function we created before, we have three input arguments named a, r and n. There are several considerations when dealing with this type of argument:

  • If we maintain the input order, we don’t need to call the argument names.

As an example, the following calls are equivalent.

\(~\)

\(~\)

  • If you name the arguments, you can use any order.

\(~\)

\(~\)

  • If you call the function name, the console will return the code of the function

\(~\)

Default arguments for functions in R

Sometimes it is exciting to have default function arguments, so the default values will be used unless others are included when executing the function. When writing a function, such as the one in our example,

\(~\)

So that, you can used

\(~\) and you can change value

Additional arguments in R

The argument “…” (dot-dot-dot) allows you to freely pass arguments that will use a sub-function inside the primary function. As an example, in the function,

Example

The return() function

You can use the return() function in cases where you need to return one object or another based on specific conditions or if you need to execute code after determining the object to be returned.

It’s important to note that only one R object can be returned at a time, but you can return any type of R object. Because of this, it’s common practice to return multiple objects as a list, as shown below:

When you run the function, you will have the following output. Recall to have the annuity.ver2 functions loaded in the workspace.

Local and global variables in R

In R, there’s no need to declare variables within a function. Instead, R uses a rule called “lexical scoping” to determine whether an object is local to the function or part of the global environment. For example:

Since the variable x is not defined within the function, R will look for x in the “enclosing” scope and use its value from there. However, if x exists in the global environment, its value remains unchanged when used inside the function.

Is x change?

To change the global value of a variable inside a function you can use the double assignment operator (\(<<\)\(-\)).

test

If else in R

In R, the if…else statement is used for conditional execution of code based on whether a condition is TRUE or FALSE.

Syntax

if (condition) {
  # Code to execute if condition is TRUE
} else {
  # Code to execute if condition is FALSE
}

Note: You can also use the conditional statement WITHOUT the ELSE statement.

Example 1

Example 2

We can define a function to check if some number is even or odd. In order to check it, we can verify if the modulus of the number is equal to 0 or not, and print the corresponding result.

Nested if

In R, you can nest if...else statements to check multiple conditions within other conditions.

Syntax

if (condition1) {
  # Code if condition1 is TRUE
  if (nested_condition) {
    # Code if both condition1 and nested_condition are TRUE
  } else {
    # Code if condition1 is TRUE, but nested_condition is FALSE
  }
} else {
  # Code if condition1 is FALSE
}

Examples of if else in R

Now we are going to show some elaborated cases of use of if else in R. First, consider, for instance, the following function that depends on x: \[\begin{aligned} f(x)=\left\{\begin{array}{ll} 0, & \text { if } x<0 \\ x / 10, & \text { if } 0 \leq x \leq 10 \\ 1, & \text { if } x>10 \end{array}\right. \end{aligned}\]

For that purpose, you can create a function named f and inside the function create a nested if condition to support all the possible cases.

\(~\)

switch() function

The switch() function in R is used to execute different code based on the value of an input. It’s a cleaner alternative to if...else if...else when you have multiple conditions based on a single variable or expression.

Syntax

switch(expression,
       case1 = value1,
       case2 = value2,
       case3 = value3,
       ...)

Arguments

  • expression evaluating to a number or a character string.

  • the list of alternatives. If it is intended that EXPR has a character-string value these will be named, perhaps except for one alternative to be used as a ‘default’ value.

Example

switch() with Numeric Expression

The numeric version of switch() works in a slightly different way. Instead of using names, the return value is determined purely with positional matching (Index).

Example

For loop in R

The for loop in R, also called a for` cycle, is a type of loop used to repeatedly execute code for each element in a list or vector. During each iteration, the code processes or evaluates the current element of the sequence.

For loop R syntax]

for (variable in sequence) {
  # Code to execute for each element
}
  • variable: This is a placeholder that takes the value of each element in the sequence during each iteration.

  • sequence: This can be a vector, list, or any other iterable object.

Example 1: Simple for Loop

Prints each element of a vector:

Example 2: for Loop with Calculations

You can perform calculations inside a for loop. For example, here’s how to calculate the square of each number in a vector:

Example 3: Nested for Loops

You can also nest for loops. Here’s an example of a nested loop that creates a multiplication table:

Example 4: Looping with Index

You can also loop through indices of a vector if you need to access the index values:

Loop break and next functions

Sometimes you need to stop the loop at some index if some condition is satisfied or to avoid evaluating some code for some index or condition. You can use the break() and next() functions.

the loop will break on the sixth iteration (that won’t be evaluated) despite the full loop has 15 iterations, and will also skip the forth iteration.

Summary

The for loop is a powerful tool in R for iterating over data structures and performing repetitive tasks efficiently. It helps in executing the same block of code multiple times with different inputs.

While loop in R

The while loop will execute some code until a logical condition is met. Therefore, while some condition is TRUE, R will do the process.

Thus, for a while loop, you need to use the while() function

Syntax

while (condition) {
  # Code to execute while condition is TRUE
}
  • condition: A logical expression that is evaluated before each iteration. If it evaluates to TRUE, the loop continues; if it evaluates to FALSE, the loop stops.

Example 1: Basic while Loop

Here’s a simple example that prints numbers from 1 to 5 using a while loop:

Example 2: while Loop with a Condition

You can use a while loop to perform calculations until a certain condition is met. For example, here’s a loop that continues to add numbers until the sum exceeds 10:

Example 3: Using break and next

You can control the flow within a while loop using break to exit the loop early and next to skip the current iteration.

Using break:

Using next:

Summary

The while loop is a flexible looping construct in R, suitable for situations where the number of iterations is not known in advance. It’s essential to ensure that the condition will eventually become FALSE to avoid creating infinite loops.

The apply() function

The apply() function is a versatile tool for applying a function to the rows or columns of a matrix or data frame. It allows for more concise and efficient code, particularly when working with data structures like matrices and data frames.

Syntax

apply(X,      # Array, matrix or data frame
      MARGIN, # 1: columns, 2:rows, c(1, 2):rows and columns
      FUN,    # Function to be applied
      ...)    # Additional arguments to FUN
  • X: The array or matrix you want to operate on.

  • MARGIN: A numeric value indicating whether to apply the function over rows (1) or columns (2).

  • FUN: The function to apply.

  • ...: Additional arguments to pass to the function.

Example

Calculating the mean of df for each variable

\(~\)

\(~\)

For loop vs apply

\(~\) Use loop for

\(~\) Use apply()

Set MARGIN =1 and run again.

Caution

What is the object type from apply() function?

The sapply() function

The sapply() function is applies a function to each element of a list or vector and simplifies the output to a vector, matrix, or array when possible. This function is particularly useful for when you want to apply a function to each element of a list or vector and get a simplified result without the need for manual conversion.

Syntax

sapply(X, 
      FUN, 
      ..., 
      simplify = TRUE, 
      USE.NAMES = TRUE)
  • X: A vector, list, or expression that can be coerced to a list.

  • FUN: The function to apply to each element of X.

  • ...: Additional arguments to be passed to FUN.

  • simplify: A logical value that determines whether to simplify the result to a vector or matrix if possible (default is TRUE).

  • USE.NAMES: A logical value that determines whether to use names for the result if X has names.

Example 1: Basic Usage

A simple example of using sapply() to calculate the length of each element in a character vector:

Example 2: Applying a Custom Function

You can also apply custom functions using sapply(). For instance, here’s how to square each number in a numeric vector:

Example 3: Working with Lists

sapply() can be especially useful when working with lists. Here’s an example where we calculate the mean of numeric vectors contained within a list:

Example 4: Simplification and Named Output

sapply() simplifies the result when possible. If the input has names, the output will also have names:

Summary

The sapply() function is a convenient way to apply a function to each element of a list or vector while simplifying the output. It’s particularly useful when you want a clean and straightforward result without the complexity of nested lists, making it a valuable tool for data manipulation and analysis in R.

The tapply() function

The tapply() function in R is used to apply a function to subsets of a vector, grouped by one or more factors. It is particularly useful for performing operations on data that is split into groups, such as calculating statistics for different categories within a dataset.

Syntax

tapply(X, 
INDEX, FUN = NULL, 
..., 
simplify = TRUE)
  • X: A vector (numeric, character, etc.) to which the function will be applied.

  • INDEX: A factor or a list of factors that defines the groups. Each unique combination of levels in the factor(s) will be treated as a group.

  • FUN: The function to apply to each group.

  • ...: Additional arguments to pass to the function.

  • simplify: A logical value that determines whether to simplify the result (default is TRUE).

Example 1: Basic Usage

A simple example where we calculate the mean of a numeric vector grouped by a factor:

Example 2: Using Custom Functions

You can also use custom functions with tapply(). For instance, if you want to calculate the sum of the values for each group:

Example 3: Multiple Factors

You can use multiple factors to group the data. Here’s an example using two factors:

Example 4: Handling NA Values

You can also handle missing values with tapply(). Here’s an example where we calculate the mean while excluding NA values:

Summary

The tapply() function is a powerful tool for applying functions to subsets of data defined by factors. It is particularly useful for summarizing data and performing calculations across different categories. By leveraging tapply(), you can efficiently analyze grouped data without the need for complex loops or manual filtering.

The assign() function

Good example

I want to random one number from N(0,1) and assign to variables x1,x2,x3, …,x100.

Question: if you don’t want to use assign() function how do you do?

Solution

Variables x1 to x100 were created in the R environment. You can check it by used

The assign() function is used to assign a value to a variable, where the variable name can be specified as a character string. This is particularly useful when you want to create variable names dynamically or when the name of the variable is generated during runtime.

Syntax

assign(x, value, envir = as.environment(-1))
  • x: A character string representing the name of the variable to which the value will be assigned.

  • value: The value to assign to the variable.

  • envir: The environment in which to assign the variable. The default is the current environment (typically the global environment).

Example 1: Basic Usage

Here’s a simple example of using assign() to create a variable with a dynamic name:

Example 2: Using assign() in a Loop

You can use assign() within a loop to create multiple variables with dynamically generated names:

Example 3: Assigning to a Different Environment

You can also specify a different environment for the assignment. Here’s an example:

Example 4: Using assign() with Data Frames

You can also use assign() to create columns in a data frame dynamically:

Summary

The assign() function in R is a useful tool for dynamically assigning values to variable names specified as strings. It can be particularly helpful in scenarios where variable names are generated programmatically or when working with environments. However, for most cases in data manipulation, it is often better to use lists or data frames for managing multiple variables more efficiently.

The try( ) function

Run this code and tell me what happen?

Without try() function

With try() function

What is the difference?

The try() function is used to handle errors gracefully during the execution of code. It allows you to run a block of code and capture any errors that may occur without stopping the execution of the entire program. This is particularly useful in scenarios where you want to attempt a risky operation and handle any potential issues without crashing your R session.

Syntax

try(expr, silent = FALSE)
  • expr: An R expression to be evaluated.

  • silent: A logical value indicating whether to suppress error messages (default is FALSE). If set to TRUE, any error messages will not be printed.

Exercise: if…else

Exercise 1: Check Positive, Negative, or Zero

# Testing the function
check_number(5)   # Output: "Positive"
check_number(-3)  # Output: "Negative"
check_number(0)   # Output: "Zero"

Task: Write a function called check_number() that takes a single numeric input and:

  • Prints “Positive” if the number is greater than zero.

  • Prints “Negative” if the number is less than zero.

  • Prints “Zero” if the number is exactly zero.

Solution

check_number <- function(num) {
  if (num > 0) {
    print("Positive")
  } else if (num < 0) {
    print("Negative")
  } else {
    print("Zero")
  }
}

# Testing the function
check_number(5)   # Output: "Positive"
check_number(-3)  # Output: "Negative"
check_number(0)   # Output: "Zero"

Exercise 2: Check Leap Year

# Testing the function
is_leap_year(2024)  # Output: "Leap Year"
is_leap_year(1900)  # Output: "Not a Leap Year"
is_leap_year(2000)  # Output: "Leap Year"

Task: Write a function called is_leap_year() that takes a year as input and:

  • Prints “Leap Year” if the year is a leap year.

  • Prints “Not a Leap Year” otherwise.

A year is a leap year if:

  • It is divisible by 4, but not by 100, OR

  • It is divisible by 400.

Solution

is_leap_year <- function(year) {
  if ((year %% 4 == 0 && year %% 100 != 0) || (year %% 400 == 0)) {
    print("Leap Year")
  } else {
    print("Not a Leap Year")
  }
}

# Testing the function
is_leap_year(2024)  # Output: "Leap Year"
is_leap_year(1900)  # Output: "Not a Leap Year"
is_leap_year(2000)  # Output: "Leap Year"

Exercise 3: Calculate Discounts Based on Purchase Amount

# Testing the function
calculate_discount(40)  # Output: "Final amount after discount: 40"
calculate_discount(75)  # Output: "Final amount after discount: 71.25"
calculate_discount(150) # Output: "Final amount after discount: 135"
calculate_discount(250) # Output: "Final amount after discount: 212.5"

Task: Write a function called calculate_discount() that takes a purchase amount as input and applies a discount based on the following criteria:

  • No discount for amounts below $50.

  • 5% discount for amounts between $50 and $100.

  • 10% discount for amounts between $100 and $200.

  • 15% discount for amounts above $200.

The function should print the final amount after applying the discount.

Solution

calculate_discount <- function(amount) {
  if (amount < 50) {
    discount <- 0
  } else if (amount < 100) {
    discount <- 0.05
  } else if (amount < 200) {
    discount <- 0.10
  } else {
    discount <- 0.15
  }
  
  final_amount <- amount * (1 - discount)
  print(paste("Final amount after discount:", final_amount))
}

# Testing the function
calculate_discount(40)   # Output: "Final amount after discount: 40"
calculate_discount(75)   # Output: "Final amount after discount: 71.25"
calculate_discount(150)  # Output: "Final amount after discount: 135"
calculate_discount(250)  # Output: "Final amount after discount: 212.5"

Exercise 4: BMI Calculator with Health Categories

# Testing the function
calculate_bmi(60, 1.7) # Output: "BMI: 20.76 - Category: Normal weight"
calculate_bmi(50, 1.6) # Output: "BMI: 19.53 - Category: Normal weight"
calculate_bmi(80, 1.7) # Output: "BMI: 27.68 - Category: Overweight"
calculate_bmi(95, 1.7) # Output: "BMI: 32.87 - Category: Obesity"

Task: Write a function called calculate_bmi() that takes weight (in kg) and height (in meters) as inputs and calculates the Body Mass Index (BMI) as

\[\text{BMI} = \dfrac{\text{weight}}{\text{height}^2}\]

Based on the BMI value, categorize the result as:

  • Underweight if BMI is below 18.5.

  • Normal weight if BMI is between 18.5 and 24.9.

  • Overweight if BMI is between 25 and 29.9.

  • Obesity if BMI is 30 or more.

The function should print both the BMI value and the category.

Solution

calculate_bmi <- function(weight, height) {
  bmi <- weight / (height ^ 2)
  
  if (bmi < 18.5) {
    category <- "Underweight"
  } else if (bmi < 25) {
    category <- "Normal weight"
  } else if (bmi < 30) {
    category <- "Overweight"
  } else {
    category <- "Obesity"
  }
  
  print(paste("BMI:", round(bmi, 2), "- Category:", category))
}

# Testing the function
calculate_bmi(60, 1.7)  # Output: "BMI: 20.76 - Category: Normal weight"
calculate_bmi(50, 1.6)  # Output: "BMI: 19.53 - Category: Normal weight"
calculate_bmi(80, 1.7)  # Output: "BMI: 27.68 - Category: Overweight"
calculate_bmi(95, 1.7)  # Output: "BMI: 32.87 - Category: Obesity"

Exercise: Loop for

Certainly! Here are four exercises to practice using for loops in R, with solutions provided for each one.

Exercise 5: Sum of the First N Natural Numbers

# Testing the function
sum_n_numbers(5)  # Output: 15 (1 + 2 + 3 + 4 + 5)
sum_n_numbers(10) # Output: 55 (1 + 2 + ... + 10)

Task: Write a function called sum_n_numbers() that takes a positive integer n as input and calculates the sum of the first n natural numbers using a for loop.

Solution

sum_n_numbers <- function(n) {
  sum <- 0
  for (i in 1:n) {
    sum <- sum + i
  }
  return(sum)
}

# Testing the function
sum_n_numbers(5)  # Output: 15 (1 + 2 + 3 + 4 + 5)
sum_n_numbers(10) # Output: 55 (1 + 2 + ... + 10)

Exercise 6: Print Multiplication Table

# Testing the function
multiplication_table(5)

Task: Write a function called multiplication_table() that takes an integer num as input and prints the multiplication table for that number up to 10.

Use a for loop to iterate through the multipliers.

Solution

multiplication_table <- function(num) {
  for (i in 1:10) {
    result <- num * i
    cat(num, "*", i, "=", result, "\n")
  }
}

# Testing the function
multiplication_table(5)

Exercise 7: Count Even and Odd Numbers in a Vector

# Testing the function
count_even_odd(c(1, 2, 3, 4, 5, 6, 7, 8))

Task: Write a function called count_even_odd() that takes a numeric vector as input and counts how many even and odd numbers are in the vector.

Use a for loop to iterate over the elements and check if they are even or odd.

Solution

count_even_odd <- function(numbers) {
  even_count <- 0
  odd_count <- 0
  
  for (num in numbers) {
    if (num %% 2 == 0) {
      even_count <- even_count + 1
    } else {
      odd_count <- odd_count + 1
    }
  }
  
  cat("Even numbers:", even_count, "\n")
  cat("Odd numbers:", odd_count, "\n")
}

# Testing the function
count_even_odd(c(1, 2, 3, 4, 5, 6, 7, 8))

Exercise 8: Calculate Factorials

# Testing the function
calculate_factorials(5)  

Task: Write a function called calculate_factorials() that takes a positive integer n as input and returns a vector containing the factorials of all numbers from 1 to n.

Use a for loop to calculate each factorial.

Solution

calculate_factorials <- function(n) {
  factorials <- numeric(n)  # Initialize a vector to store the factorials
  
  for (i in 1:n) {
    factorial <- 1
    for (j in 1:i) {
      factorial <- factorial * j
    }
    factorials[i] <- factorial
  }
  
  return(factorials)
}

# Testing the function
calculate_factorials(5)  

Exercise: Loop while

Exercise 9: Countdown from a Given Number

# Testing the function
countdown(5)

Task: Write a function called countdown() that takes a positive integer n as input and uses a while loop to print a countdown from n to 1. When the countdown reaches 1, print “Liftoff!”.

Solution

countdown <- function(n) {
  while (n > 0) {
    print(n)
    n <- n - 1
  }
  print("Liftoff!")
}

# Testing the function
countdown(5)

Exercise 10: Sum of Natural Numbers until Limit Exceeds 100

# Testing the function
sum_until_100()  # Output: 105 (or the first sum that exceeds 100)

Task: Write a function called sum_until_100() that starts at 1 and keeps adding numbers in sequence (1 + 2 + 3 + …) until the sum exceeds 100. Use a while loop to perform this task and print the final sum.

Solution

sum_until_100 <- function() {
  sum <- 0
  i <- 1
  
  while (sum <= 100) {
    sum <- sum + i
    i <- i + 1
  }
  
  return(sum)
}

# Testing the function
sum_until_100()  # Output: 105 (or the first sum that exceeds 100)

Exercise 11: Finding the Smallest Divisor of a Number

# Testing the function
smallest_divisor(15)  # Output: 3
smallest_divisor(17)  # Output: 17 (since 17 is a prime number)

Task: Write a function called smallest_divisor() that takes a positive integer n as input and finds the smallest divisor of n greater than 1. Use a while loop to test each number starting from 2 until you find the divisor.

Solution

smallest_divisor <- function(n) {
  divisor <- 2
  
  while (n %% divisor != 0) {
    divisor <- divisor + 1
  }
  
  return(divisor)
}

# Testing the function
smallest_divisor(15)  # Output: 3
smallest_divisor(17)  # Output: 17 (since 17 is a prime number)

Exercise 12: Collatz Conjecture Sequence

# Testing the function
collatz_sequence(6)

Task: Write a function called collatz_sequence() that takes a positive integer n and prints each step in the Collatz sequence until reaching 1. The rules for the sequence are: - If the number is even, divide it by 2. - If the number is odd, multiply it by 3 and add 1.

Solution

collatz_sequence <- function(n) {
  while (n != 1) {
    print(n)
    if (n %% 2 == 0) {
      n <- n / 2
    } else {
      n <- 3 * n + 1
    }
  }
  print(1)  # Print the final 1 in the sequence
}

# Testing the function
collatz_sequence(6)

Exercise: The switch() function

Exercise 13: Days of the Week

# Testing the function
day_of_week(1)  # Output: "Sunday"
day_of_week(5)  # Output: "Thursday"
day_of_week(8)  # Output: "Invalid day number"

Task: Write a function called day_of_week() that takes an integer from 1 to 7 as input and returns the corresponding day of the week (1 = “Sunday”, 2 = “Monday”, …, 7 = “Saturday”). Use the switch() function to map numbers to days.

Solution

day_of_week <- function(day_number) {
  switch(as.character(day_number),
         "1" = "Sunday",
         "2" = "Monday",
         "3" = "Tuesday",
         "4" = "Wednesday",
         "5" = "Thursday",
         "6" = "Friday",
         "7" = "Saturday",
         "Invalid day number")  # default case
}

# Testing the function
day_of_week(1)  # Output: "Sunday"
day_of_week(5)  # Output: "Thursday"
day_of_week(8)  # Output: "Invalid day number"

Exercise 14: Basic Calculator

Task: Write a function called calculator() that takes three arguments: two numbers and an operation (either “add”, “subtract”, “multiply”, or “divide”). Use switch() to perform the appropriate arithmetic operation based on the input.

Solution

calculator <- function(num1, num2, operation) {
  switch(operation,
         "add" = num1 + num2,
         "subtract" = num1 - num2,
         "multiply" = num1 * num2,
         "divide" = ifelse(num2 != 0, num1 / num2, "Cannot divide by zero"),
         "Invalid operation")
}

# Testing the function
calculator(10, 5, "add")       # Output: 15
calculator(10, 5, "subtract")  # Output: 5
calculator(10, 5, "multiply")  # Output: 50
calculator(10, 0, "divide")    # Output: "Cannot divide by zero"
calculator(10, 5, "mod")       # Output: "Invalid operation"

Exercise 15: Animal Sounds

# Testing the function
animal_sound("dog")  # Output: "Bark"
animal_sound("cat")  # Output: "Meow"
animal_sound("cow")  # Output: "Moo"
animal_sound("bird") # Output: "Unknown animal"

Task: Write a function called animal_sound() that takes the name of an animal (either “dog”, “cat”, “cow”, or “duck”) and returns the sound it makes (“dog” = “Bark”, “cat” = “Meow”, “cow” = “Moo”, “duck” = “Quack”). Use switch() to return the appropriate sound.

Solution

animal_sound <- function(animal) {
  switch(animal,
         "dog" = "Bark",
         "cat" = "Meow",
         "cow" = "Moo",
         "duck" = "Quack",
         "Unknown animal")
}

# Testing the function
animal_sound("dog")  # Output: "Bark"
animal_sound("cat")  # Output: "Meow"
animal_sound("cow")  # Output: "Moo"
animal_sound("bird") # Output: "Unknown animal"

Exercise 16: Grade to GPA Conversion

# Testing the function
grade_to_gpa("A")  # Output: 4
grade_to_gpa("C")  # Output: 2
grade_to_gpa("F")  # Output: 0
grade_to_gpa("E")  # Output: "Invalid grade"

Task: Write a function called grade_to_gpa() that takes a letter grade (A, B, C, D, F) as input and returns the corresponding GPA (A = 4, B = 3, C = 2, D = 1, F = 0). Use switch() to map the grades to GPA values.

Solution

grade_to_gpa <- function(grade) {
  switch(grade,
         "A" = 4,
         "B" = 3,
         "C" = 2,
         "D" = 1,
         "F" = 0,
         "Invalid grade")
}

# Testing the function
grade_to_gpa("A")  # Output: 4
grade_to_gpa("C")  # Output: 2
grade_to_gpa("F")  # Output: 0
grade_to_gpa("E")  # Output: "Invalid grade"

Exercise: The apply() function

Here are four exercises using the apply() function in R, along with solutions for each.

Exercise 17: Row Sums of a Matrix

# Testing the function
mat <- matrix(1:9, nrow = 3, byrow = TRUE)

row_sums(mat)  

Task: Write a function called row_sums() that takes a matrix as input and uses the apply() function to calculate the sum of each row.

Solution

row_sums <- function(mat) {
  apply(mat, 1, sum)
}

# Testing the function
mat <- matrix(1:9, nrow = 3, byrow = TRUE)

row_sums(mat)  

Exercise 18: Column Means of a Matrix

# Testing the function
mat <- matrix(1:12, nrow = 3, byrow = TRUE)

column_means(mat)

Task: Write a function called column_means() that takes a matrix as input and uses apply() to calculate the mean of each column.

Solution

column_means <- function(mat) {
  apply(mat, 2, mean)
}

# Testing the function
mat <- matrix(1:12, nrow = 3, byrow = TRUE)

column_means(mat)

Exercise 19: Calculate Maximum in Each Row of a Data Frame

# Testing the function
df <- data.frame(
  a = c(1, 5, 3),
  b = c(4, 2, 6),
  c = c(7, 8, 3)
)

row_maximums(df)

Task: Write a function called row_maximums() that takes a data frame with numeric values as input and uses apply() to find the maximum value in each row.

Solution

row_maximums <- function(df) {
  apply(df, 1, max)
}

# Testing the function
df <- data.frame(
  a = c(1, 5, 3),
  b = c(4, 2, 6),
  c = c(7, 8, 3)
)

row_maximums(df)

Exercise 20: Calculate Range of Each Column in a Matrix

# Testing the function
mat <- matrix(c(3, 8, 1, 9, 4, 6, 5, 7, 2), nrow = 3, byrow = TRUE)

column_ranges(mat)

Task: Write a function called column_ranges() that takes a matrix as input and uses apply() to calculate the range (difference between maximum and minimum) of each column.

Solution

column_ranges <- function(mat) {
  apply(mat, 2, function(x) max(x) - min(x))
}

# Testing the function
mat <- matrix(c(3, 8, 1, 9, 4, 6, 5, 7, 2), nrow = 3, byrow = TRUE)

column_ranges(mat)

Exercise: The sapply() function

Here are four exercises using the sapply() function in R, with solutions for each.

Exercise 21: Square Each Element in a Vector

# Testing the function
vec <- c(1, 2, 3, 4, 5)
square_elements(vec)  

Task: Write a function called square_elements() that takes a numeric vector as input and uses sapply() to return a vector where each element is squared.

Solution

square_elements <- function(vec) {
  sapply(vec, function(x) x^2)
}

# Testing the function
vec <- c(1, 2, 3, 4, 5)
square_elements(vec)  

Exercise 22: Find the Length of Each Element in a List of Strings

# Testing the function
str_list <- list("apple", "banana", "cherry", "date")
string_lengths(str_list)

Task: Write a function called string_lengths() that takes a list of strings as input and uses sapply() to return a vector with the length of each string.

Solution

string_lengths <- function(str_list) {
  sapply(str_list, nchar)
}

# Testing the function
str_list <- list("apple", "banana", "cherry", "date")
string_lengths(str_list)

Exercise 23: Check if Each Number in a Vector is Even

# Testing the function
vec <- c(1, 2, 3, 4, 5, 6)
is_even(vec)

Task: Write a function called is_even() that takes a numeric vector as input and uses sapply() to return a logical vector indicating whether each element is even.

Solution

is_even <- function(vec) {
  sapply(vec, function(x) x %% 2 == 0)
}

# Testing the function
vec <- c(1, 2, 3, 4, 5, 6)
is_even(vec)

Exercise 24: Convert Temperatures from Celsius to Fahrenheit in a Vector

# Testing the function
temp_celsius <- c(0, 20, 37, 100)
celsius_to_fahrenheit(temp_celsius)

Task: Write a function called celsius_to_fahrenheit() that takes a numeric vector of temperatures in Celsius and uses sapply() to return the temperatures converted to Fahrenheit.

\[ \text{fahrenheit } = \dfrac{9\times\text{celsius}}{5}+32\]

Solution

celsius_to_fahrenheit <- function(temp_celsius) {
  sapply(temp_celsius, function(x) x * 9/5 + 32)
}

# Testing the function
temp_celsius <- c(0, 20, 37, 100)
celsius_to_fahrenheit(temp_celsius)

Exercise: The tapply() function

Here are four exercises to practice using the tapply() function in R, along with solutions for each.

Exercise 25: Calculate Mean by Group

# Testing the function
values <- c(10, 15, 14, 23, 19, 25, 18, 20)
groups <- factor(c("A", "A", "B", "B", "A", "B", "A", "B"))
mean_by_group(values, groups)

Task: Write a function called mean_by_group() that takes a numeric vector of values and a factor vector of groups as input. Use tapply() to calculate the mean of the values for each group.

Solution

mean_by_group <- function(values, groups) {
  tapply(values, groups, mean)
}

# Testing the function
values <- c(10, 15, 14, 23, 19, 25, 18, 20)
groups <- factor(c("A", "A", "B", "B", "A", "B", "A", "B"))
mean_by_group(values, groups)

Exercise 26: Sum by Category

# Testing the function
values <- c(5, 10, 15, 20, 25, 30)
categories <- factor(c("X", "Y", "X", "Y", "X", "Y"))
sum_by_category(values, categories)

Task: Write a function called sum_by_category() that takes a numeric vector of values and a factor vector of categories. Use tapply() to calculate the sum of values in each category.

Solution

sum_by_category <- function(values, categories) {
  tapply(values, categories, sum)
}

# Testing the function
values <- c(5, 10, 15, 20, 25, 30)
categories <- factor(c("X", "Y", "X", "Y", "X", "Y"))
sum_by_category(values, categories)

Exercise 27: Find Maximum Value by Group

# Testing the function
values <- c(3, 7, 12, 5, 8, 14, 9, 11)
groups <- factor(c("G1", "G1", "G2", "G2", "G1", "G2", "G1", "G2"))
max_by_group(values, groups)

Task: Write a function called max_by_group() that takes a numeric vector of values and a factor vector of groups as input. Use tapply() to find the maximum value for each group.

Solution

max_by_group <- function(values, groups) {
  tapply(values, groups, max)
}

# Testing the function
values <- c(3, 7, 12, 5, 8, 14, 9, 11)
groups <- factor(c("G1", "G1", "G2", "G2", "G1", "G2", "G1", "G2"))
max_by_group(values, groups)

Exercise 28: Count Elements by Group

# Testing the function
values <- c(1, 2, 3, 4, 5, 6, 7, 8)
groups <- factor(c("A", "B", "A", "B", "A", "B", "A", "B"))
count_by_group(values, groups)

Task: Write a function called count_by_group() that takes a vector and a factor vector of groups as input. Use tapply() to count the number of elements in each group.

Solution

count_by_group <- function(values, groups) {
  tapply(values, groups, length)
}

# Testing the function
values <- c(1, 2, 3, 4, 5, 6, 7, 8)
groups <- factor(c("A", "B", "A", "B", "A", "B", "A", "B"))
count_by_group(values, groups)

Exercise: The assign() function

Exercise 29: Create Multiple Variables with a Loop

# Testing the function
create_vars(c("a", "b", "c"))
print(a)  # 1
print(b)  # 2
print(c)  # 3

Task: Write a function called create_vars() that takes a vector of names and assigns the values 1, 2, 3, etc., to each name as a variable in the global environment. For example, if the input vector is c("a", "b", "c"), create variables a, b, and c with values 1, 2, and 3, respectively.

Solution

create_vars <- function(names) {
  for (i in seq_along(names)) {
    assign(names[i], i, envir = .GlobalEnv)
  }
}

# Testing the function
create_vars(c("a", "b", "c"))
print(a)  # 1
print(b)  # 2
print(c)  # 3

Exercise 30: Dynamically Create a Series of Vectors

# Testing the function
create_vectors(3)
print(vec1)
print(vec2)
print(vec3)

Task: Write a function called create_vectors() that takes an integer n as input and dynamically creates n vectors (vec1, vec2, …, vecN) in the global environment, where each vector contains numbers from 1 to 10.

Solution

create_vectors <- function(n) {
  for (i in 1:n) {
    assign(paste0("vec", i), 1:10, envir = .GlobalEnv)
  }
}

# Testing the function
create_vectors(3)

# Output:
# vec1 = 1 2 3 4 5 6 7 8 9 10
# vec2 = 1 2 3 4 5 6 7 8 9 10
# vec3 = 1 2 3 4 5 6 7 8 9 10
print(vec1)
print(vec2)
print(vec3)

Exercise 31: Assign Calculated Values to Variable Names

# Testing the function
calculate_assign(c(2, 4, 6))

print(calc1)  # 4
print(calc2)  # 16
print(calc3)  # 36

Task: Write a function called calculate_assign() that takes a numeric vector and creates variables named calc1, calc2, etc., where each variable is assigned the square of each value in the vector.

Solution

calculate_assign <- function(values) {
  for (i in seq_along(values)) {
    assign(paste0("calc", i), values[i]^2, envir = .GlobalEnv)
  }
}

# Testing the function
calculate_assign(c(2, 4, 6))

# Output:
# calc1 = 4, calc2 = 16, calc3 = 36
print(calc1)  # 4
print(calc2)  # 16
print(calc3)  # 36

Exercise 32: Create Named Data Frames

# Testing the function
create_dataframes(c("df1", "df2", "df3"))

print(df1)
print(df2)
print(df3)

Task: Write a function called create_dataframes() that takes a list of data frame names and creates an empty data frame for each name. Each data frame should have two columns, A and B, in the global environment.

Solution

create_dataframes <- function(df_names) {
  for (name in df_names) {
    df <- data.frame(A = numeric(), B = numeric())
    assign(name, df, envir = .GlobalEnv)
  }
}

# Testing the function
create_dataframes(c("df1", "df2", "df3"))

# Output:
# df1, df2, and df3 created with columns A and B, but no rows.
print(df1)
print(df2)
print(df3)