---
title: "Project 4: Errors, Date & Time, and Loop Speed"
author: "Boluwatife Ajibade"
date: "December 07, 2025"
format:
word: default
pdf: default
---
# π¦ Environment Setup
This chunk installs and loads the necessary packages, specifically `tidyverse` (which includes `dplyr` and `ggplot2`) and `lubridate`, which are essential for date/time manipulation and efficient coding practices.
```{r setup}'''
# Install packages if they are not already installed
if (!requireNamespace("tidyverse", quietly = TRUE)) {
install.packages("tidyverse")
}
if (!requireNamespace("lubridate", quietly = TRUE)) {
install.packages("lubridate")
}
# Load the necessary packages and suppress startup messages for cleaner output
suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(lubridate))
This section addresses Rβs profiling and debugging tools and solves common R code errors.
The following functions are used in R for performance profiling (identifying bottlenecks) and debugging (finding the source of errors).
| Function | Purpose | Explanation |
|---|---|---|
| (a) Turn on the profiler | Rprof() |
Starts the R profiler, which records the amount of time spent on function calls. |
| (b) Calculate time spent in functions | summaryRprof() |
Reads the output file from Rprof() and
summarizes the execution time spent in each function. |
| (c) Show the sequence of calls | traceback() |
Prints the call stack after an error occurs, showing the sequence of functions that led to the error. |
| (d) Debug an error in a function | debug() |
Sets a flag on a specific function, causing execution
to pause and enter the interactive debugger (browser())
when that function is called. |
| (e) Investigate the error environment | recover() |
Used after an error occurs (often set globally via
options(error = recover)). It allows the user to navigate
the call stack (traceback) and investigate the environment
of any function on the stack. |
This section provides the fixes for the common R syntax and logical errors listed.
Error Type: Syntax Error
(<text>:3:0: unexpected end of input)
The original code snippet:
myString <- "Good things come in threes
Fix and Explanation: The string begins with a double quote but does not end with one before the line break. R requires strings to be properly enclosed on the same line (unless using a multiline string feature which wasnβt used here). The fix is to close the string.
```{r part1_2a_fix}βββ # FIX: Close the string with a double quote on the same line. my_string <- βGood things come in threesβ
my_string
### (2b) Problem: Misspelled Function
**Error Type:** Name Error (`could not find function "means"`)
The original code snippet:
```r
age <- c(28, 48, 47, 71, 22, 80, 48, 30, 31)
means(age)
Fix and Explanation: The user misspelled the
built-in function mean(). R is case-sensitive and function
names must be spelled correctly.
```{r part1_2b_fix}βββ age <- c(28, 48, 47, 71, 22, 80, 48, 30, 31)
result_mean <- mean(age)
result_mean
### (2c) Problem: Object Not Found
**Error Type:** Name Error (`object 'name_of_a_variable_that_doesnt_exist' not found`)
The original code snippet:
```r
name_of_a_variable_that_doesnt_exist + 1 * pi^2
Fix and Explanation: The error occurred because the variable was used before it was assigned a value. The fix is to first assign a value to the object.
```{r part1_2c_fix}βββ # FIX: Assign a value to the variable before use. name_of_a_variable_that_doesnt_exist <- 5
result_calc <- name_of_a_variable_that_doesnt_exist + 1 * pi^2
result_calc
### (2d) Problem: File Access/Path Error
**Error Type:** File/I/O Error (`zip file 'C:\Users\mans\Data\some_file.xlsx' cannot be opened`)
**Fix and Explanation:**
This error is often caused by one of three things:
1. **File Not Found:** The file path is incorrect or the file was moved/deleted.
2. **Permissions:** R does not have permission to read that directory.
3. **Invalid Path Syntax:** In R (especially on Windows), backslashes (`\`) can be problematic because they are used as escape characters.
The fix is to replace the single backslashes with either double backslashes (`\\`) or forward slashes (`/`). A forward slash is universally safer in R for path specification.
**Example Fix (Conceptual, as file doesn't exist):**
```r
# Conceptual Fix: Replacing backslashes with forward slashes
# original_path <- "C:\Users\mans\Data\some_file.xlsx"
fixed_path <- "C:/Users/mans/Data/some_file.xlsx"
# The command that caused the error (e.g., read_excel) would be run with the fixed path.
# readxl::read_excel(fixed_path)
Error Type: Syntax/Operator Error
(attempt to apply non-function)
The original code snippet:
1+2(2+3)
Fix and Explanation: In R, as in many programming
languages, multiplication must be explicitly denoted with the
multiplication operator (*). R interprets
2(2+3) as an attempt to call a function named
2 with the argument (2+3), which is not
valid.
```{r part1_2e_fix}βββ # FIX: Insert the multiplication operator () between 2 and (2+3). result_math <- 1 + 2 (2 + 3)
result_math
-----
# π
Part 2: Date and Time Formatting and Operations
This section demonstrates various date and time format codes and performs date arithmetic.
## 3\. Date Format Examples
The `format()` function is used to convert a date or time object into a character string based on specified codes. The examples below use a base date object created from `2025-07-25 09:05:01`.
```{r part2_3_base_date}'''
# Create a base POSIXct date/time object for demonstration
base_datetime <- as.POSIXct("2025-07-25 09:05:01", tz = "America/Chicago")
| Code | Description | Example R Code | Example Output | Explanation |
|---|---|---|---|---|
(a) %a |
Abbreviated weekday name. | format(base_datetime, "%a") |
Fri |
The abbreviated name of the day of the week (Friday). |
(b) %c |
Locale-specific date and time. | format(base_datetime, "%c") |
Fri Jul 25 09:05:01 2025 |
A full, standard date and time string for the current locale. |
(c) %j |
Day of the year (001-366). | format(base_datetime, "%j") |
206 |
The 206th day of the year 2025. |
(d) %m |
Month as a decimal number (01-12). | format(base_datetime, "%m") |
07 |
The month of July, represented as the number 07. |
(e) %p |
AM/PM indicator. | format(base_datetime, "%p") |
AM |
The morning indicator for a time before noon. |
(f) %S |
Seconds as a decimal number (00-61). | format(base_datetime, "%S") |
01 |
The seconds component of the time (01 second). |
(g) %x |
Locale-specific date representation. | format(base_datetime, "%x") |
07/25/25 |
A common short date format (MM/DD/YY) for the US locale. |
This section uses the lubridate package
for robust and accurate date and time calculations.
The result should be the number of days between the two dates.
```{r part2_4a_subtract_date}βββ # Define the dates date_end <- as.Date(β2021-01-01β) date_start <- as.Date(β2020-01-01β)
date_difference <- date_end - date_start
date_difference
**Output Explanation (4a):**
The output shows a **difftime** object of 366 days. This is correct because 2020 was a leap year, containing 366 days.
### (4b) Subtract Time "2022-11-08 03:14:35 PST" from "2022-11-09 26:14:35 PST"
The time "26:14:35" is not a standard format and must be corrected before calculation. "26 hours" is equivalent to 24 hours (1 day) plus 2 hours, meaning the time is actually 02:14:35 on the *next* day (2022-11-10). The `lubridate::ymd_hms()` function handles non-standard times gracefully by rolling them over.
```{r part2_4b_subtract_time}'''
# Define the times using lubridate::ymd_hms, which handles the "26" hour rollover
time_end <- ymd_hms("2022-11-09 26:14:35", tz = "PST") # This becomes 2022-11-10 02:14:35
time_start <- ymd_hms("2022-11-08 03:14:35", tz = "PST")
# Subtract the times (result is a difftime object)
time_difference <- time_end - time_start
# Display the result
time_difference
Output Explanation (4b): The difference is
47 hours (1 day and 23 hours). This results from
time_end rolling over to November 10th (48 hours from
start) and then correcting for the one hour difference in the hours
component (02:xx:xx vs 03:xx:xx). Specifically, itβs 1 day and 23 hours:
\((24 \text{ hours} \times 2 \text{ days}) - 1
\text{ hour} = 47 \text{ hours}\).
Assuming we have a date-time object, we can extract the seconds of the day and the day of the week.
```{r part2_4c_extract_seconds_day}βββ # Create a sample POSIXct object sample_datetime <- as.POSIXct(β2025-07-25 15:30:00β, tz = βUTCβ)
seconds_of_day <- hour(sample_datetime) * 3600 + minute(sample_datetime) * 60 + second(sample_datetime)
day_of_week <- weekdays(sample_datetime)
cat(βSample Date/Time:β, as.character(sample_datetime), ββ) cat(βSeconds of the Day:β, seconds_of_day, ββ) cat(βDay of the Week:β, day_of_week, ββ)
### (4d) Find Intervals Between the Dates
Intervals represent the exact span of time between two date-time points. We can use the difference from part (4a) to create an interval.
```{r part2_4d_interval}'''
# Define start and end points
date_start_i <- as_datetime("2023-05-15 10:00:00")
date_end_i <- as_datetime("2023-05-20 14:30:00")
# Create an interval object using lubridate::interval()
time_interval <- interval(date_start_i, date_end_i)
# Display the interval
time_interval
# Calculate the length of the interval in hours (as a demonstration)
length_in_hours <- time_interval / hours(1)
# Display the length
cat("Length of interval in hours:", length_in_hours)
We can use seq.Date() in base R or
add_with_rollback() with days(0) in
lubridate for robustness.
```{r part2_4e_monthly_sequence}βββ # Define the starting date start_date <- as.Date(β2020-04-21β)
monthly_sequence <- seq.Date( from = start_date, by = βmonthβ, length.out = 5 )
monthly_sequence
-----
# π» Part 3: Loop and Apply Functions
This section demonstrates the use of R's `apply` family functions for efficient iteration.
## 5\. Demonstrating `apply` Functions
The `apply` functions are typically more compact and often faster than standard `for` loops, especially for simple operations on lists and vectors.
### (5a) `lapply()`: List Apply
**Purpose:** Applies a function over a **list** or **vector** and returns the result as a **list**.
```{r part2_5a_lapply}'''
# Create a list of three vectors
data_list <- list(
set_a = c(10, 20, 30),
set_b = c(5, 15, 25),
set_c = c(100, 200, 300)
)
# Use lapply to calculate the mean of each vector in the list
# The result will be a list containing the three calculated means.
lapply_result <- lapply(
X = data_list,
FUN = mean
)
# Display the result
lapply_result
Explanation of Use (5a): lapply()
iterated over the three elements (set_a,
set_b, set_c) of data_list. For
each element, it applied the mean() function. Since the
output structure is always a list, the result is a list
containing the calculated means (20, 15, and 200).
sapply(): Simplify ApplyPurpose: Applies a function over a list or vector and attempts to simplify the result to the lowest possible dimension, usually a vector or a matrix.
```{r part2_5b_sapply}βββ # Use sapply on the same list as above # The output will be simplified from a list to a named numeric vector. sapply_result <- sapply( X = data_list, FUN = mean )
sapply_result
**Explanation of Use (5b):**
`sapply()` performed the exact same operation as `lapply()`. However, because the results were all single numeric values, `sapply()` simplified the output structure from a list into a **named numeric vector**, which is often more convenient for data analysis.
### (5c) `vapply()`: Vector Apply
**Purpose:** Similar to `sapply()`, but it requires a **template** (`FUN.value`) to be specified for the expected output format. This makes the code safer and faster because R knows in advance the type and length of the result.
```{r part2_5c_vapply}'''
# Define the expected output format: a single numeric value (0.0) for each element
output_template <- c(mean = 0.0)
# Use vapply to calculate the mean of each vector
# If the output didn't match the template (e.g., if one mean returned two numbers),
# vapply would stop with an error, ensuring data consistency.
vapply_result <- vapply(
X = data_list,
FUN = mean,
FUN.value = output_template # Required template for expected output structure
)
# Display the result
vapply_result
Explanation of Use (5c): vapply()
enforced that the result of mean() for every element must
be a single numeric value (matching
FUN.value = c(mean = 0.0)). It also returned a
named numeric vector, similar to sapply().
The primary benefit is safety and reliability: it acts
as a check, preventing unexpected output types or lengths, which is
critical in robust coding.