If you have any questions regarding the assignment instructions and the R Markdown template, please post it on the discussion board Questions on completing Assessment 2.

Setup

library(dplyr): Manipulating data allows for merging datasets, creating columns, filtering data. library(tidyr): cleaning up and reorganising data library(lubridate): orchestrates working with dates and times library(ggplot2): Implementation of graph visualisations library(knitr): Report documentation

Insert and load the packages you need to produce the report here:

library(magrittr)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
## 
## Attaching package: 'tidyr'
## The following object is masked from 'package:magrittr':
## 
##     extract
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(ggplot2)
library(knitr)

Instructions

Follow the instructions given in the Assessment brief to fill out the template below. Remember to include R codes and outputs and explain your working and results in plain text.

Data Description

Write your plain text here.

You may use a bullet list like this:

Dataset 1: Uber Bookings

represents individual uber ride bookings. Each row represents one booking and contains 80 observations across 9 variables. Includes booking/customer IDs, date and time, booking status, vehicle type, payment method, ride distance and booking value. - sample size: creates object called n giving it a value of 80. n communicates how many observations the user intends to generate. - seed result: seed was set so the same random data is generated each time. - create booking IDs: paste0(“B”) pastes B in front of 1:N all the way up to 80 observations - Create customer IDs: customer_id <- creates a variable that stores the results. past0(“c”, 1:60) creates 60 customer IDS. Sample() randomly selects from these customers, while n represents the 80 booking observations. replace = TRUE allows the same customer to be selected more than once. - Generate booking dates: date <- creates a variable called date and stores the formed data inside.Sample going to randomly select something. Seq notifies sample the range from which it can select from dates. as.date sets the date time period start to finish. n selects 80 dates due to 80 observations. Replace = True indicates a date can be selected more than once. - Generate booking dates: time <- creates a variable column named time. Paste0 joins pieces together. sample randly selects an hour from (0:23 to 80 times, 80 indicated by n. Replace = True indicates can be repeated. “:” indicates place colon inbetween hour and minutes. hours is indicated first followed by minutes described in military time. - Generate booking status: booking_status <- Create variable name called book status to store data inside. Sample() tells r to randomly select values. C(“completed”, “cancelled”, “incomplete”) c representing combine in R in compiling a vector list of choices such as completed, cancelled and incomplete. 3 possible booking statuses which r can select from. N indicating make 80 selections based on the 80 observations of the booking. Replace = True, statuses can be chosen multiple times. - Generate ride distance using a evenly spread distribution: ride distance <- creates variables called ride_distance to store generated data in. runif() generates random numbers spread out across a specific range. N generates 80 values (observations.) min = 2 sets the smallest distance the runif can be generated to 2km and max = 35 is the largest distance 35km. - ride_distance_km: ride_distance_km <- round(ride_distance, digits = 1) within ride_distance_km store the rounded 1 decimal digits within riding_distance_km. - Generate correlated booking values: a <- 5 indicates starting base price. b <- 2 the increase of cost per distance, $2 per km. S <- 4 standard deviation indicates randomness. This allows for longer ride distances to be valued at a higher rate. - Generate random error: creates a variable called error. rnorm() generates random numbers from no preconceived numbers. n, generate 80 random numbers. Mean = 0 centre the numbers around 0. SD = s, standard deviation and s = 4 based on previous commands. - Booking value on ride distance and random error: booking_value <-. create a variable called booking_value to store the calculated prices. a is the starting base of 5 + B ride distance $2 per km + error to add random variation. then round each bookign value to 2 decimal digits.
- Create the dataset: take the entirety of the data set variables created and form them into a data frame titled uber_bookings. - Display observations: show me the first couple variables/rows of data.frame created.

# sample size
n <- 80

# seed result for reproduction
SEED <- 123

set.seed(SEED)

# Create booking IDs
booking_id <- paste0("B", 1:n)

# Create customer IDs
customer_id <- sample(
  paste0("c", 1:60),
  n,
  replace = TRUE
)

# Generate booking dates
date <- sample(
  seq(as.Date("2026-01-01"), as.Date("2026-03-31"), by = "day"),
  n,
  replace = TRUE
)

# Generate booking times
time <- paste0(
  sample (0:23, n, replace = TRUE), # Hours
  ":",
  sample(0:59, n, replace = TRUE) # Minutes
)

# Generate booking status
booking_status <-sample(
  c("Completed", "Cancelled", "Incomplete"),
  n,
  replace = TRUE
)

# Generate vehicle type
vehicle_type <- sample(
  c("UberX", "Comfort", "UberXL"),
  n,
  replace = TRUE
)

# Generate payment method
payment_method <- sample(
  c("Card", "paypal", "Cash"),
  n, 
  replace = TRUE
)

# Generate ride distance using a evenly spread distribution
ride_distance_km <- runif(
  n,
  min = 2,
  max = 35
)

ride_distance_km <- round(ride_distance_km, digits = 1)

# Generate correlated booking values

# set the intercept
a <- 5 

# set the slope
b <- 2

s <- 4

# Generate random error
error <- rnorm(
  n,
  mean = 0,
  sd = s
)

# Booking value on ride distance and random error
booking_value <- a + b * ride_distance_km + error

booking_value <- round(booking_value, digits = 2)

# Add outliers to numeric variables
booking_value[1] <- 200
ride_distance_km[2] <- 100

# Add 3 missing values
booking_status[10] <- NA
payment_method[20] <- NA
ride_distance_km[30] <- NA

# Create the dataset
uber_bookings <- data.frame(
  booking_id,
  customer_id,
  date,
  time, 
  booking_status,
  vehicle_type,
  booking_value,
  ride_distance_km,
  payment_method
)

colSums(is.na(uber_bookings))
##       booking_id      customer_id             date             time 
##                0                0                0                0 
##   booking_status     vehicle_type    booking_value ride_distance_km 
##                1                0                0                1 
##   payment_method 
##                1
# Display observations
head(uber_bookings)

Dataset 2: Uber Customers

# setting sample size
n_customers <-60

# set a different seed 
SEED2 <- 456
set.seed(SEED2)

# Create customer IDs
customer_id <-paste0("c", 1:n_customers)

# Generate customer ratings
customer_rating <- runif(
  n_customers,
  min = 3.5,
  max = 5
)

customer_rating <- round(customer_rating, digits = 1)

# Generate number of cancelled rides
cancelled_rides <- sample(
  0:4,
  n_customers, 
  replace = TRUE
)

# Generate number of incomplete rides
incomplete_rides <- sample(
  0:2,
  n_customers,
  replace = TRUE
)

# Add outliers to numeric variables
customer_rating[customer_id == "c3"] <- 1.5
cancelled_rides[customer_id == "c5"] <- 15
incomplete_rides[customer_id == "c6"] <- 8

#generate cancellation reasons
Cancellation_reason <-ifelse(
  cancelled_rides ==0,
  "no cancellations",
  sample(
    c("Driver too far away",
      "Changed plans",
      "Incorrect pick up location",
      "Long wait time"),
    n_customers, 
    replace = TRUE
  )
)

# Generate city
city <- sample(
  c("Adelaide", "Melbourne", "Sydney", "Brisbane"),
  n_customers,
  replace = TRUE
)

# Generate membership type
membership_type <- sample (
  c("standard","uber one"),
  n_customers,
  replace = TRUE
)

# 3 missing values
customer_rating[10] <- NA
Cancellation_reason[18] <- NA
city[25] <- NA

# Dataset
uber_customers <-data.frame(
  customer_id,
  customer_rating,
  cancelled_rides,
  Cancellation_reason,
  incomplete_rides,
  city,
  membership_type
)

# Observation data.frame
head(uber_customers)

Merge

Create a new data frame called uber_data and store the merged data inside. Start with uber_bookings, then use left_join() to add matching information from uber_customers using customer_id. - uber_data <- store the result here - Uber_bookings: use this data set first - %>% then onto next step - left join (uber_customers) add matching data from uber customers - by = “customer_id” use customer_id to match rows. Using customer ID to see what matches with what.

uber_data <- uber_bookings %>%
  left_join(uber_customers, by ="customer_id")

head(uber_data)
# missing values
colSums(is.na(uber_data))
##          booking_id         customer_id                date                time 
##                   0                   0                   0                   0 
##      booking_status        vehicle_type       booking_value    ride_distance_km 
##                   1                   0                   0                   1 
##      payment_method     customer_rating     cancelled_rides Cancellation_reason 
##                   1                   1                   0                   1 
##    incomplete_rides                city     membership_type 
##                   0                   3                   0
# booking_status
uber_data$booking_status <- as.character(uber_data$booking_status)
uber_data$booking_status[is.na(uber_data$booking_status)] <- "unknown"
uber_data$booking_status <- as.factor(uber_data$booking_status)

# Ride_distance_km
uber_data$ride_distance_km[is.na(uber_data$ride_distance_km)] <-
  mean(uber_data$ride_distance_km, na.rm = TRUE)

# payment_method
uber_data$payment_method <- as.character(uber_data$payment_method)
uber_data$payment_method[is.na(uber_data$payment_method)] <- "unknown"
uber_data$payment_method <- as.factor(uber_data$payment_method)

# remaining values
colSums(is.na(uber_data))
##          booking_id         customer_id                date                time 
##                   0                   0                   0                   0 
##      booking_status        vehicle_type       booking_value    ride_distance_km 
##                   0                   0                   0                   0 
##      payment_method     customer_rating     cancelled_rides Cancellation_reason 
##                   0                   1                   0                   1 
##    incomplete_rides                city     membership_type 
##                   0                   3                   0

Understand

  • Uber_data str(): displays structure of variable type of each variable such as date identifies with date, character identifies with character and numeric is numeric, checking to see if they are aligned correctly.
  • uber_data %>% summary(): takes the uber_data variables and summarises it into minimum, 1st quarter 25%, (median 2nd quarter 50%), mean the average and 3rd quarter %75 and max.
# Inspect merged dataset uber_data

# Inspect data type, variable structures.
uber_data %>% str()
## 'data.frame':    80 obs. of  15 variables:
##  $ booking_id         : chr  "B1" "B2" "B3" "B4" ...
##  $ customer_id        : chr  "c31" "c15" "c51" "c14" ...
##  $ date               : Date, format: "2026-03-13" "2026-03-27" ...
##  $ time               : chr  "7:5" "19:49" "15:29" "23:30" ...
##  $ booking_status     : Factor w/ 4 levels "Cancelled","Completed",..: 2 3 1 3 1 2 1 1 1 4 ...
##  $ vehicle_type       : chr  "Comfort" "UberX" "UberX" "UberXL" ...
##  $ booking_value      : num  200 16.1 25.2 62.6 72.2 ...
##  $ ride_distance_km   : num  32.5 100 12.4 28.5 34.6 12.6 2 34.7 6.9 3.6 ...
##  $ payment_method     : Factor w/ 4 levels "Card","Cash",..: 2 1 1 2 2 2 2 3 1 1 ...
##  $ customer_rating    : num  5 4.4 4.8 4.7 1.5 4.1 4.9 4.1 3.6 5 ...
##  $ cancelled_rides    : num  4 4 2 0 1 4 2 4 0 3 ...
##  $ Cancellation_reason: chr  "Incorrect pick up location" "Driver too far away" "Changed plans" "no cancellations" ...
##  $ incomplete_rides   : num  2 1 2 0 0 0 2 2 0 2 ...
##  $ city               : chr  "Melbourne" "Adelaide" "Adelaide" "Brisbane" ...
##  $ membership_type    : chr  "uber one" "uber one" "standard" "uber one" ...
# convert data type, variable structures.
uber_data <- uber_data %>%
  mutate(
    booking_status = as.factor(booking_status),
    vehicle_type = as.factor(vehicle_type),
    payment_method = as.factor(payment_method),
    Cancellation_reason = as.factor(Cancellation_reason),
    city = as.factor(city),
    membership_type = as.factor(membership_type)
  )

# display data type, variable structures.
str(uber_data)
## 'data.frame':    80 obs. of  15 variables:
##  $ booking_id         : chr  "B1" "B2" "B3" "B4" ...
##  $ customer_id        : chr  "c31" "c15" "c51" "c14" ...
##  $ date               : Date, format: "2026-03-13" "2026-03-27" ...
##  $ time               : chr  "7:5" "19:49" "15:29" "23:30" ...
##  $ booking_status     : Factor w/ 4 levels "Cancelled","Completed",..: 2 3 1 3 1 2 1 1 1 4 ...
##  $ vehicle_type       : Factor w/ 3 levels "Comfort","UberX",..: 1 2 2 3 2 1 1 3 1 2 ...
##  $ booking_value      : num  200 16.1 25.2 62.6 72.2 ...
##  $ ride_distance_km   : num  32.5 100 12.4 28.5 34.6 12.6 2 34.7 6.9 3.6 ...
##  $ payment_method     : Factor w/ 4 levels "Card","Cash",..: 2 1 1 2 2 2 2 3 1 1 ...
##  $ customer_rating    : num  5 4.4 4.8 4.7 1.5 4.1 4.9 4.1 3.6 5 ...
##  $ cancelled_rides    : num  4 4 2 0 1 4 2 4 0 3 ...
##  $ Cancellation_reason: Factor w/ 5 levels "Changed plans",..: 3 2 1 5 1 4 2 3 5 2 ...
##  $ incomplete_rides   : num  2 1 2 0 0 0 2 2 0 2 ...
##  $ city               : Factor w/ 4 levels "Adelaide","Brisbane",..: 3 1 1 2 1 3 3 3 2 1 ...
##  $ membership_type    : Factor w/ 2 levels "standard","uber one": 2 2 1 2 1 1 2 1 2 2 ...
# display statistic summary in Q1, Q2 and Q3.
uber_data %>% summary()
##      booking_id    customer_id      date                   time   
##  Length   :80   Length   :80   Min.   :2026-01-01   Length   :80  
##  N.unique :80   N.unique :44   1st Qu.:2026-01-25   N.unique :77  
##  N.blank  : 0   N.blank  : 0   Median :2026-02-15   N.blank  : 0  
##  Min.nchar: 2   Min.nchar: 2   Mean   :2026-02-17   Min.nchar: 3  
##  Max.nchar: 3   Max.nchar: 3   3rd Qu.:2026-03-15   Max.nchar: 5  
##                                Max.   :2026-03-31                 
##                                                                   
##     booking_status  vehicle_type booking_value    ride_distance_km
##  Cancelled :30     Comfort:32    Min.   :  3.27   Min.   :  2.00  
##  Completed :24     UberX  :20    1st Qu.: 21.20   1st Qu.: 10.10  
##  Incomplete:25     UberXL :28    Median : 39.70   Median : 17.65  
##  unknown   : 1                   Mean   : 40.21   Mean   : 18.32  
##                                  3rd Qu.: 54.20   3rd Qu.: 24.90  
##                                  Max.   :200.00   Max.   :100.00  
##                                                                   
##  payment_method customer_rating cancelled_rides 
##  Card   :23     Min.   :1.500   Min.   : 0.000  
##  Cash   :31     1st Qu.:3.900   1st Qu.: 0.000  
##  paypal :25     Median :4.400   Median : 2.000  
##  unknown: 1     Mean   :4.322   Mean   : 2.275  
##                 3rd Qu.:4.800   3rd Qu.: 3.250  
##                 Max.   :5.000   Max.   :15.000  
##                 NAs    :1                       
##                  Cancellation_reason incomplete_rides        city   
##  Changed plans             :21       Min.   :0.000    Adelaide :16  
##  Driver too far away       :19       1st Qu.:0.000    Brisbane :24  
##  Incorrect pick up location:10       Median :1.000    Melbourne:26  
##  Long wait time            : 9       Mean   :0.925    Sydney   :11  
##  no cancellations          :20       3rd Qu.:2.000    NAs      : 3  
##  NAs                       : 1       Max.   :8.000                  
##                                                                     
##  membership_type
##  standard:30    
##  uber one:50    
##                 
##                 
##                 
##                 
## 
# names of variables 
names(uber_data)
##  [1] "booking_id"          "customer_id"         "date"               
##  [4] "time"                "booking_status"      "vehicle_type"       
##  [7] "booking_value"       "ride_distance_km"    "payment_method"     
## [10] "customer_rating"     "cancelled_rides"     "Cancellation_reason"
## [13] "incomplete_rides"    "city"                "membership_type"
# This is a chunk where you inspect the types of variables, data structures, check the attributes in the data and apply proper data type conversions

Manipulate Data

A new variable was created named vehicle category. This was created from the existing different car types Uber supplies. UberX is categorised as standard, comfort as comfort and UberXL as larger vehicle.

  • uber_data <- uber_data %>%: use existing merged data set of uber_data and make changes then save it back as uber_data
  • mutate(: creates a new variable
  • vehicle_category = case_when(: creates a new category and assigned a condition
  • vehicle_type == “UberX” ~ “Standard”,: if the vehicle is UberX ~ lavel it as standard and store into a new category.
uber_data <- uber_data %>%
  mutate(
    vehicle_category = case_when(
      vehicle_type == "UberX" ~ "Standard",
      vehicle_type == "Comfort" ~ "Comfort",
      vehicle_type == "UberXL" ~ "Larger Vehicle",
    )
  )

head(uber_data)

Scan I

  • colSums(is.na(uber_data)): (is.na find the missing na within the uber_data) once this is done count the missing values in each column. Find the Nas and count them by column.

  • Numeric data is often replaced with the mean

  • categorical variable replace the missing value with unknown.

colSums(is.na(uber_data))
##          booking_id         customer_id                date                time 
##                   0                   0                   0                   0 
##      booking_status        vehicle_type       booking_value    ride_distance_km 
##                   0                   0                   0                   0 
##      payment_method     customer_rating     cancelled_rides Cancellation_reason 
##                   0                   1                   0                   1 
##    incomplete_rides                city     membership_type    vehicle_category 
##                   0                   3                   0                   0
colSums(uber_data == "", na.rm = TRUE)
##          booking_id         customer_id                date                time 
##                   0                   0                   0                   0 
##      booking_status        vehicle_type       booking_value    ride_distance_km 
##                   0                   0                   0                   0 
##      payment_method     customer_rating     cancelled_rides Cancellation_reason 
##                   0                   0                   0                   0 
##    incomplete_rides                city     membership_type    vehicle_category 
##                   0                   0                   0                   0
sum(uber_data$city == "Unknown", na.rm = TRUE)
## [1] 0
sum(uber_data$Cancellation_reason == "Unknown", na.rm = TRUE)
## [1] 0
# Convert missing numeric rating value to the average. 
uber_data$customer_rating[is.na(uber_data$customer_rating)] <-
  mean(uber_data$customer_rating, na.rm = TRUE)

sum(is.na(uber_data$customer_rating))
## [1] 0
# Convert factor to character
uber_data$Cancellation_reason <- as.character(uber_data$Cancellation_reason)

# Replace missing value with unknown
uber_data$Cancellation_reason[is.na(uber_data$Cancellation_reason)] <-"unknown"

#change back to factor
uber_data$Cancellation_reason <- as.factor(uber_data$Cancellation_reason)

table(uber_data$Cancellation_reason)
## 
##              Changed plans        Driver too far away 
##                         21                         19 
## Incorrect pick up location             Long wait time 
##                         10                          9 
##           no cancellations                    unknown 
##                         20                          1
uber_data$city <- as.character(uber_data$city)

uber_data$city[is.na(uber_data$city)] <- "unknown"

uber_data$city <- as.factor(uber_data$city)

table(uber_data$Cancellation_reason)
## 
##              Changed plans        Driver too far away 
##                         21                         19 
## Incorrect pick up location             Long wait time 
##                         10                          9 
##           no cancellations                    unknown 
##                         20                          1
sum(is.na(uber_data$Cancellation_reason))
## [1] 0

Scan II

boxplots were uesed to scan the numeric variables for outliers. Outliers were identified in booking value (200), ride distance (100), customer rating (1.5), cancelled rides (15), and incomplete rides (8). The outliers were replaced with the mean of the remaining values for each variable. The boxplots were then checked again to confirm the extreme outliers had been treated.

Ride distance boxplot: Q1 (bottom of box): est 10km -> 25% of rides are 10km or less median (black line): est 17-18km ->average ride distance Q3 (top of box): about 25km ->75% are 25km or less max/top of whiskers: 35km outliers: removed none.

Cancelled rides boxplot: lowest: 0 Q1(25%): 0 median (50%): 2 cancelled rides Q3 (75%) 3 cancelled rides Highest: 4 cancelled rides outliers: removed none

Booking Value: booking values had a median of approx $40. The middle 50% of bookings ranged from approx $21 to 54, while the highest non-outlier booking value was approx $73. outliers removed.

sapply(uber_data, is.numeric)
##          booking_id         customer_id                date                time 
##               FALSE               FALSE               FALSE               FALSE 
##      booking_status        vehicle_type       booking_value    ride_distance_km 
##               FALSE               FALSE                TRUE                TRUE 
##      payment_method     customer_rating     cancelled_rides Cancellation_reason 
##               FALSE                TRUE                TRUE               FALSE 
##    incomplete_rides                city     membership_type    vehicle_category 
##                TRUE               FALSE               FALSE               FALSE
boxplot(uber_data$customer_rating,
        main = "Customer Rating")

boxplot(uber_data$booking_value,
        main = "booking value")

boxplot(uber_data$ride_distance_km,
         main = "ride_distance_km")

boxplot(uber_data$cancelled_rides,
        main = "cancelled_rides")

boxplot(uber_data$incomplete_rides,
        main = "incomplete_rides")

max(uber_data$cancelled_rides)
## [1] 15
max(uber_customers$cancelled_rides)
## [1] 15
# outliers to Averages
uber_data$booking_value[uber_data$booking_value == 200] <-
  mean(uber_data$booking_value[uber_data$booking_value != 200])
max(uber_data$booking_value)
## [1] 72.23
boxplot(uber_data$booking_value,
        main = "booking Value")

#removing outliers
uber_data$ride_distance_km[uber_data$ride_distance_km == 100] <-
  mean(uber_data$ride_distance_km[uber_data$ride_distance_km != 200])
max(uber_data$ride_distance_km)
## [1] 34.7
boxplot(uber_data$ride_distance_km,
        main = "ride distance (km)")

#removing outliers
uber_data$customer_rating[uber_data$customer_rating == 1.5] <-
  mean(uber_data$customer_rating[uber_data$customer_rating !=1.5])
min(uber_data$customer_rating)
## [1] 3.6
boxplot(uber_data$customer_rating,
        main = "Customer Rating")

#removing outliers
uber_data$cancelled_rides[uber_data$cancelled_rides == 15] <-
  mean(uber_data$cancelled_rides[uber_data$cancelled_rides !=15])
max(uber_data$cancelled_rides)
## [1] 4
boxplot(uber_data$cancelled_rides,
        main = "cancelled rides")

#removing outliers
uber_data$incomplete_rides[uber_data$incomplete_rides == 8] <-
  mean(uber_data$incomplete_rides[uber_data$incomplete_rides != 8])
max(uber_data$incomplete_rides)
## [1] 2
boxplot(uber_data$incomplete_rides,
        main = "incomplete_rides")

Transform

Changing KM distance to M

uber_data <- uber_data %>%
  mutate(
    ride_distance_m = ride_distance_km * 1000
  )

head(uber_data[, c("ride_distance_km", "ride_distance_m")])

Summary statistics

Vehicle category: Standard had the highest average rating at 4.46, followed by larger vehicle at 4.34 and comfort at 4.31. Distance vs rating: correlation = 0.036, meaning no relationship between ride distance and customer rating. City: Adleaide had the highest average rating at 4.54, followed by Melbourne 4.40, Sydney 4.31, and Brisbane 4.15. Total booking valuey = $3,054.61 within the synethetic dataset.

# average rating based on vehicle type
uber_data %>%
  group_by(vehicle_category) %>%
  summarise(
    average_rating = mean(customer_rating)
  )
# reviews grouped by city
uber_data %>%
  group_by(city) %>%
  summarise(
    average_rating = mean(customer_rating)
  )
# Correlation between ride distance and customer rating
cor(uber_data$ride_distance_km, uber_data$customer_rating)
## [1] -0.03256928
# Booking value
sum(uber_data$booking_value)
## [1] 3054.613