This final class has two main parts:
A suggested class structure is:
# Creating objects
x <- 10
y <- 4
x + y
## [1] 14
x - y
## [1] 6
x * y
## [1] 40
x / y
## [1] 2.5
x^2
## [1] 100
sqrt(x)
## [1] 3.162278
# Creating a vector
numbers <- c(3, 7, 2, 9, 5)
length(numbers)
## [1] 5
sum(numbers)
## [1] 26
mean(numbers)
## [1] 5.2
min(numbers)
## [1] 2
max(numbers)
## [1] 9
numbers[2]
## [1] 7
numbers[2:4]
## [1] 7 2 9
numbers[numbers > 5]
## [1] 7 9
x <- seq(from = 0, to = 10, by = 2)
x
## [1] 0 2 4 6 8 10
y <- c(5, 8, NA, 12, 4)
mean(y)
## [1] NA
mean(y, na.rm = TRUE)
## [1] 7.25
is.na(y)
## [1] FALSE FALSE TRUE FALSE FALSE
y[!is.na(y)]
## [1] 5 8 12 4
Do not use the following expression to identify missing values:
y == NA
Use:
is.na(y)
## [1] FALSE FALSE TRUE FALSE FALSE
students <- data.frame(
name = c("Ali", "Sara", "John", "Maria"),
midterm = c(75, 82, 68, 91),
final = c(80, 88, 74, 94)
)
students
## name midterm final
## 1 Ali 75 80
## 2 Sara 82 88
## 3 John 68 74
## 4 Maria 91 94
str(students)
## 'data.frame': 4 obs. of 3 variables:
## $ name : chr "Ali" "Sara" "John" "Maria"
## $ midterm: num 75 82 68 91
## $ final : num 80 88 74 94
summary(students)
## name midterm final
## Length:4 Min. :68.00 Min. :74.0
## Class :character 1st Qu.:73.25 1st Qu.:78.5
## Mode :character Median :78.50 Median :84.0
## Mean :79.00 Mean :84.0
## 3rd Qu.:84.25 3rd Qu.:89.5
## Max. :91.00 Max. :94.0
students$midterm
## [1] 75 82 68 91
students[students$final >= 80, ]
## name midterm final
## 1 Ali 75 80
## 2 Sara 82 88
## 4 Maria 91 94
students$average <- (students$midterm + students$final) / 2
students
## name midterm final average
## 1 Ali 75 80 77.5
## 2 Sara 82 88 85.0
## 3 John 68 74 71.0
## 4 Maria 91 94 92.5
grade_letter <- function(mark) {
if (mark >= 90) {
return("A")
} else if (mark >= 80) {
return("B")
} else if (mark >= 70) {
return("C")
} else if (mark >= 60) {
return("D")
} else {
return("F")
}
}
grade_letter(84)
## [1] "B"
for (i in c(1,7,4)) {
print(i^2)
}
## [1] 1
## [1] 49
## [1] 16
In many cases, vectorized R code is shorter and more efficient:
(1:5)^2
## [1] 1 4 9 16 25
x <- seq(-5, 5, length.out = 200)
y <- x^2
plot(
x,
y,
type = "l",
lwd = 2,
main = "The Function y = x^2",
xlab = "x",
ylab = "y"
)
abline(h = 0, v = 0, lty = 2)
Common values for the type argument include:
plot(x, y, type = "p") # Points
plot(x, y, type = "l") # Lines
plot(x, y, type = "b") # Both points and lines
Consider the following vector:
values <- c(12, 7, 15, NA, 9, 20, 4)
Complete the following tasks:
mean(values, na.rm = TRUE)
## [1] 11.16667
values[values > 10 & !is.na(values)]
## [1] 12 15 20
values[!is.na(values)]^2
## [1] 144 49 225 81 400 16
clean_values <- values[!is.na(values)]
plot(
clean_values,
type = "b",
main = "Non-Missing Values",
xlab = "Index",
ylab = "Value"
)
By the end of this section, students should be able to:
The general structure of a function is:
function_name <- function(arguments) {
# Commands
result <- ...
return(result)
}
The main components are:
Define a function that calculates the square of a number:
square <- function(x) {
result <- x^2
return(result)
}
Test the function:
square(4)
## [1] 16
square(-3)
## [1] 9
square(c(1, 2, 3, 4))
## [1] 1 4 9 16
R automatically returns the result of the last evaluated expression. Therefore, the same function can be written more compactly:
square <- function(x) {
x^2
}
A linear function has the form
\[ f(x) = mx + b. \]
Define it in R:
linear_function <- function(x, m = 1, b = 0) {
m * x + b
}
Test the function:
linear_function(x = 3)
## [1] 3
linear_function(
x = 3,
m = 2,
b = 5
)
## [1] 11
linear_function(
x = c(-2, -1, 0, 1, 2),
m = 2,
b = 1
)
## [1] -3 -1 1 3 5
x <- seq(-5, 5, length.out = 200)
y <- linear_function(x, m = 2, b = 1)
plot(
x,
y,
type = "l",
lwd = 2,
main = "Linear Function: f(x) = 2x + 1",
xlab = "x",
ylab = "f(x)"
)
abline(h = 0, v = 0, lty = 2)
A quadratic function has the form
\[ f(x) = ax^2 + bx + c. \]
quadratic <- function(x, a = 1, b = 0, c = 0) {
a * x^2 + b * x + c
}
Test the function:
quadratic(2)
## [1] 4
quadratic(
x = 2,
a = 1,
b = -2,
c = -3
)
## [1] -3
x <- seq(-5, 5, length.out = 400)
y <- quadratic(x, a = 1, b = -2, c = -3)
plot(
x,
y,
type = "l",
lwd = 2,
main = "Quadratic Function",
xlab = "x",
ylab = "f(x)"
)
abline(h = 0, v = 0, lty = 2)
points(
x = c(-1, 3),
y = c(0, 0),
pch = 19
)
The plotted function is
\[ f(x) = x^2 - 2x - 3, \]
with roots \(x=-1\) and \(x=3\).
We now combine R functions and mathematical functions.
plot_function <- function(
fun,
lower = -5,
upper = 5,
n = 400,
main = "Graph of a Mathematical Function",
xlab = "x",
ylab = "f(x)"
) {
if (!is.function(fun)) {
stop("'fun' must be an R function.")
}
if (lower >= upper) {
stop("'lower' must be smaller than 'upper'.")
}
if (n < 2) {
stop("'n' must be at least 2.")
}
x <- seq(
from = lower,
to = upper,
length.out = n
)
y <- fun(x)
plot(
x,
y,
type = "l",
lwd = 2,
main = main,
xlab = xlab,
ylab = ylab
)
abline(
h = 0,
v = 0,
lty = 2
)
invisible(
data.frame(
x = x,
y = y
)
)
}
plot_function(
fun = function(x) x^2 - 4,
lower = -4,
upper = 4,
main = "f(x) = x^2 - 4"
)
plot_function(
fun = function(x) x^3 - 3 * x,
lower = -3,
upper = 3,
main = "f(x) = x^3 - 3x"
)
plot_function(
fun = sin,
lower = -2 * pi,
upper = 2 * pi,
main = "f(x) = sin(x)"
)
plot_function(
fun = function(x) exp(-x),
lower = 0,
upper = 5,
main = "f(x) = exp(-x)"
)
plot_function(
fun = function(x) exp(-x^2),
lower = -3,
upper = 3,
main = "f(x) = exp(-x^2)"
)
Write an R function for
\[ f(x) = ax^3 + bx^2 + cx + d. \]
cubic <- function(x, a, b, c, d) {
# Complete this function
}
cubic <- function(x, a = 1, b = 0, c = 0, d = 0) {
a * x^3 + b * x^2 + c * x + d
}
Test the function:
cubic(
x = 2,
a = 1,
b = -2,
c = 1,
d = 3
)
## [1] 5
Plot the function:
plot_function(
fun = function(x) {
cubic(
x,
a = 1,
b = -2,
c = -1,
d = 2
)
},
lower = -3,
upper = 4,
main = "A Cubic Function"
)
A numerical approximation to the derivative of a function is
\[ f'(x) \approx \frac{f(x+h)-f(x-h)}{2h}. \]
numerical_derivative <- function(fun, x, h = 0.0001) {
if (!is.function(fun)) {
stop("'fun' must be a function.")
}
if (h <= 0) {
stop("'h' must be positive.")
}
(fun(x + h) - fun(x - h)) / (2 * h)
}
For \(f(x)=x^2\), the exact derivative is \(f'(x)=2x\).
f <- function(x) {
x^2
}
numerical_derivative(
fun = f,
x = 3
)
## [1] 6
The result should be approximately 6.
x <- seq(-4, 4, length.out = 300)
y <- f(x)
dy <- numerical_derivative(f, x)
plot(
x,
y,
type = "l",
lwd = 2,
ylim = range(c(y, dy)),
main = "A Function and Its Numerical Derivative",
xlab = "x",
ylab = "Value"
)
lines(
x,
dy,
lwd = 2,
lty = 2
)
abline(
h = 0,
v = 0,
lty = 3
)
legend(
"top",
legend = c(
"f(x) = x^2",
"Approximate derivative"
),
lty = c(1, 2),
lwd = 2
)
Write and plot the function
\[ f(x) = \cos(x) + \frac{x}{5}, \qquad -2\pi \leq x \leq 2\pi. \]
final_function <- function(x) {
cos(x) + x / 5
}
plot_function(
fun = final_function,
lower = -2 * pi,
upper = 2 * pi,
main = "f(x) = cos(x) + x/5"
)
This lesson combines the main R skills covered in the course: