International College of Digital Innovation, CMU
October 31, 2024
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.
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:
In the previous code block we have the following parts:
The output of the return() function can be a vector, matrix, data frame, list, plot, or another object types.
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?
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:
As an example, the following calls are equivalent.
\(~\)
\(~\)
\(~\)
\(~\)
\(~\)
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
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
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.
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
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.
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.
\(~\)
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
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
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
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]
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.
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
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.
break
: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
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
\(~\)
\(~\)
\(~\) Use loop for
\(~\) Use apply()
Set MARGIN =1 and run again.
Caution
What is the object type from apply()
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
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 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
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.
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?
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
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.
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.
# 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.
# 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"
# 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"
# 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"
Certainly! Here are four exercises to practice using for
loops in R, with solutions provided for each one.
# 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.
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.
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))
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.
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!”.
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.
# 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.
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.
# 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"
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"
# 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"
# 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.
Here are four exercises using the apply()
function in R, along with solutions for each.
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.
Task: Write a function called column_means()
that takes a matrix as input and uses apply()
to calculate the mean of each column.
# 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.
# 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.
Here are four exercises using the sapply()
function in R, with solutions for each.
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.
# 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.
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.
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\]
Here are four exercises to practice using the tapply()
function in R, along with solutions for each.
# 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.
# 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.
# 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.
# 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.
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.
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.
# 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.
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)