Code
library(tidyverse)
library(tidyquant) # For graphing format
library(kableExtra) # For styling table
<- read_csv("../00_data/data_raw/WATVA_survey.csv")
riders_raw
# riders_raw %>% skimr::skim()
The economic impact study carried out by Daniel Lee Consulting LLC for the Wisconsin ATV Association uncovered a significant finding: ATV/UTV riders collectively spent $4.2 billion in Wisconsin during 2023. This report delves into the survey analysis results, providing insights into rider spending habits and other intriguing characteristics.
The NOHVIS Group, in collaboration with the Wisconsin ATV Association, undertook an in-person survey at trailheads from April 2023 to October 2023 to collect data on ATV/UTV riders. A total of 1,072 riders participated in the survey, out of which 948 responses were deemed usable for the purposes of this study.
library(tidyverse)
library(tidyquant) # For graphing format
library(kableExtra) # For styling table
<- read_csv("../00_data/data_raw/WATVA_survey.csv")
riders_raw
# riders_raw %>% skimr::skim()
<- riders_raw %>%
riders_renamed #filter for actual survey responses
# filter(!Status %in% c("Survey Preview", "{\"ImportId\":\"status\"}", "Response Type")) %>%
# filter for actual questions
select(7:(ncol(.)-2)) %>%
set_names("ride_for_recreation",
"participate_2023",
"age",
"state",
"state_other",
"income",
"second_home",
"day_trips",
"overnight_trips",
"overnight_trips_n",
"overnight_trips_food",
"overnight_trips_transport",
"overnight_trips_recreate",
"overnight_trips_souvenir",
"overnight_trips_entrance",
"overnight_trips_lodging",
"day_trips_food",
"day_trips_transport",
"day_trips_recreate",
"day_trips_souvenir",
"day_trips_entrance",
"ATV_UTV",
"ATV_UTV_new",
"ATV_new_n",
"UTV_new_n",
"ATV_UTV_new_dollar",
"ATV_UTV_new_pct",
"ATV_UTV_used",
"ATV_used_n",
"UTV_used_n",
"ATV_UTV_used_dollar",
"ATV_UTV_used_pct",
"Towing",
"Towing_new",
"Towing_new_dollar",
"Towing_new_pct",
"Towing_used",
"Towing_used_dollar",
"Towing_used_pct",
"spend_prep_for_trip",
"spend_prep_for_trip_apparel",
"spend_prep_for_trip_accessories",
"spend_prep_for_trip_maintenance",
"spend_prep_for_trip_insurance",
"spend_prep_for_trip_govt",
"spend_prep_for_trip_other",
"winter_riding_pct",
"road_route_touring_pct",
"ATV_owned",
"UTV_owned",
"ATV_UTV_purposes",
"Trail_Riding",
"Road_Route_Touring",
"Commuting_to_Work",
"Farming",
"Hunting",
"Shopping",
"ATV_UTV_purposes_Other") %>%
# NA in State should other than Big Six
mutate(state = replace_na(state, "Other")) %>%
mutate(across(c(starts_with(c("overnight_trips", "day_trips", "spend_prep_for_trip_")),
contains(c("_new_", "_used_")),
ends_with(c("_pct", "_owned"))), as.numeric)) %>%
mutate(across(c(where(is.character), -ATV_UTV_purposes, -ATV_UTV_purposes_Other), factor)) %>%
mutate(income = factor(income,
levels = c("$150,000 or more","$125,000 to $149,999",
"$100,000 to $124,999","$75,000 to $99,999",
"$50,000 to $74,999","$35,000 to $49,999",
"$25,000 to $34,999","Less than $25,000","Prefer not to answer"))) %>%
# Add unique identification # to each response
mutate(ID = as.factor(row_number()))
# Breakouts by recreational rider and participation in 2023
%>% count(ride_for_recreation, participate_2023)
riders_renamed
# Breakouts by day_trips and overnight_trips
%>%
riders_renamed group_by(day_trips > 0, overnight_trips > 0) %>%
summarise(n = n()) %>%
filter(`day_trips > 0` == TRUE | `overnight_trips > 0` == TRUE) %>%
ungroup() %>%
add_tally(wt = n)
# Remove unusable responses.
<- riders_renamed %>%
rec_riders_2023
# Reduces to 1,023 from 1,072
filter(ride_for_recreation == "Yes", participate_2023 == "Yes") %>%
# Reduces to 948 from 1,023
filter(day_trips > 0 | overnight_trips > 0) %>%
# Move ID to the first column
select(ID, everything(), -ride_for_recreation, -participate_2023,
-age, -state_other, -income, -second_home, - ATV_UTV_purposes,
-c(winter_riding_pct:ATV_UTV_purposes_Other))
# Correct the reporting errors.
<- rec_riders_2023 %>%
riders_clean
# Drop ATV_UTV and Towing
select(-ATV_UTV, -Towing) %>%
# Replace responses with NA for the follow-up Q for Riders who reported no purchase of new ATV/UTV
mutate(ATV_new_n = if_else(str_detect(ATV_UTV_new, "No"), NA, ATV_new_n )) %>%
mutate(UTV_new_n = if_else(str_detect(ATV_UTV_new, "No"), NA, UTV_new_n )) %>%
mutate(ATV_UTV_new_dollar = if_else(str_detect(ATV_UTV_new, "No"), NA, ATV_UTV_new_dollar)) %>%
mutate(ATV_UTV_new_pct = if_else(str_detect(ATV_UTV_new, "No"), NA, ATV_UTV_new_pct)) %>%
# Replace responses with NA for the follow-up Q for Riders who reported no purchase of used ATV/UTV
mutate(ATV_used_n = if_else(str_detect(ATV_UTV_used, "No"), NA, ATV_used_n )) %>%
mutate(UTV_used_n = if_else(str_detect(ATV_UTV_used, "No"), NA, UTV_used_n )) %>%
mutate(ATV_UTV_used_dollar = if_else(str_detect(ATV_UTV_used, "No"), NA, ATV_UTV_used_dollar)) %>%
mutate(ATV_UTV_used_pct = if_else(str_detect(ATV_UTV_used, "No"), NA, ATV_UTV_used_pct)) %>%
# Replace responses with NA for the follow-up Q for Riders who reported no purchase of new Towing T
mutate(Towing_new_dollar = if_else(str_detect(Towing_new, "No"), NA, Towing_new_dollar)) %>%
mutate(Towing_new_pct = if_else(str_detect(Towing_new, "No"), NA, Towing_new_pct)) %>%
# Replace responses with NA for the follow-up Q for Riders who reported no purchase of used Towing T
mutate(Towing_used_dollar = if_else(str_detect(Towing_used, "No"), NA, Towing_used_dollar)) %>%
mutate(Towing_used_pct = if_else(str_detect(Towing_used, "No"), NA, Towing_used_pct))
To ensure the precision of spending estimates, a rigorous process of outlier removal was implemented on spending-related survey data subsequent to applying the cubic transformation.
Outliers typically exhibit extreme values, either significantly larger than the median plus 1.5 times the interquartile range (IQR) or considerably smaller than the median minus 1.5 times the IQR.
Utilizing the cubic transformation results in a more normalized distribution of spending, thus providing a more conservative approach to outlier identification. This method helps to enhance the reliability of the data analysis process.
<- riders_clean %>%
riders_outlierRemoved
# Revise ATV price to be per unit
# replace_na(list(ATV_new_n = 0, UTV_new_n = 0, ATV_used_n = 0, UTV_used_n = 0)) %>%
# mutate(ATV_UTV_new_dollar = ATV_UTV_new_dollar / (ATV_new_n + UTV_new_n),
# ATV_UTV_used_dollar = ATV_UTV_used_dollar / (ATV_used_n + UTV_used_n)) %>%
# Outlier removal step2: Tukey’s procedure
pivot_longer(names_to = "categories", values_to = "spending", where(is.numeric)) %>%
group_by(categories) %>%
mutate(spending_cubed = spending ^ (1/3),
upper_whisker = boxplot.stats(spending_cubed)$stats[5],
lower_whisker = boxplot.stats(spending_cubed)$stats[1],
spending = ifelse(spending_cubed > upper_whisker | spending_cubed < lower_whisker,
NA, spending)) %>%
ungroup() %>%
select(-spending_cubed,-upper_whisker,-lower_whisker) %>%
pivot_wider(names_from = categories, values_from = spending)
# Save the wrangled data
write_rds(riders_outlierRemoved, "../00_data/data_wrangled/01_riders_outlierRemoved.rds")
<- rec_riders_2023 %>%
fig_outlier select(starts_with("overnight_trips_"), -overnight_trips_n) %>%
#outlier removel
pivot_longer(names_to = "categories", values_to = "spending", everything()) %>%
group_by(categories) %>%
mutate(spending_median = median(spending, na.rm = TRUE)) %>%
ungroup() %>%
# Remove "overnight_trips_" from texts
mutate(categories = str_remove(categories, "overnight_trips_")) %>%
ggplot(aes(spending^(1/3), fct_reorder(categories, spending_median), fill = categories)) +
geom_boxplot(show.legend = NULL) +
labs(title = "with cubic transformation") +
scale_fill_tq() +
scale_x_continuous(labels = scales::dollar, breaks = seq(0,80,10)) +
theme_tq() +
labs(
title = "Figure 5: Expenditure Outlier Example",
subtitle = "Distributions of Overnight Trip Expenditures",
x = "Expenditure ^ (1/3) (i.e., Cubic Root)",
y = ""
)
fig_outlier
write_rds(fig_outlier, "../00_data/figures/01_fig_outlier.rds")
The dots in the figure indicate outliers, with those on the right side of the box representing extremely large values exceeding the median plus 1.5 times the IQR. These outliers were excluded from the calculation of average expenditure by category. For instance, expenditures of $1,000 or more per trip were deemed outliers and excluded when estimating the average overnight trip spending on food. Conversely, dots on the left side of the box represent extremely small values below the median minus 1.5 times the IQR, which were also removed. For example, instances of $0 spending (indicating no expenditure) were considered outliers and excluded when estimating overnight trip spending on food. This process ensures that outliers do not unduly influence the calculation of average expenditure, leading to more accurate and reliable results.
In 2023, Wisconsin residents reported an average of 21.9 day trips and 5 overnight trips. Conversely, non-residents reported an average of 10.6 day trips and 6.3 overnight trips during the same period.
An intriguing finding is that non-resident riders indicated more day trips than overnight trips, despite the distances from their homes to ATV trails. This observation suggests that non-residents may predominantly select ATV trails situated near the border, which are not far from their residences.
<- riders_outlierRemoved %>%
n_trips #create profiles by trip types
mutate(state = case_when(
== "Wisconsin" ~ "Wisconsin",
state != "Wisconsin" ~ "Out of State"
state %>%
)) mutate(state = factor(state, levels = c("Wisconsin", "Out of State"))) %>%
group_by(state) %>%
summarise(avg_day_trips = mean(day_trips, na.rm = TRUE),
avg_overnight_trips = mean(overnight_trips, na.rm = TRUE),
se_day_trips = sd(day_trips, na.rm = TRUE)/sqrt(n()),
se_overnight_trips = sd(overnight_trips, na.rm = TRUE)/sqrt(n()),
sample_size = n())
# save the file
write_rds(n_trips, "../00_data/data_wrangled/01_n_trips.rds")
%>%
n_trips set_names("State", "Day", "Overnight", "Day", "Overnight", "Sample Size") %>%
::kable(digits = 1, caption = "Average Number of Trips per Year") %>%
knitradd_header_above(c(" " = 1, "Estimate" = 2, "Standard Error" = 2, " " = 1), align = "c")
State | Day | Overnight | Day | Overnight | Sample Size |
---|---|---|---|---|---|
Wisconsin | 21.9 | 5.0 | 0.8 | 0.2 | 831 |
Out of State | 10.6 | 6.3 | 1.3 | 0.7 | 117 |
# Estimate spending, standard errors, and sample size
<- riders_outlierRemoved %>%
exp_trip #select trip expenditure
select(!starts_with("ATV") & !starts_with("UTV") & !starts_with("Tow") & !starts_with("spend")) %>%
#create profiles by trip types
mutate(state = case_when(
== "Wisconsin" ~ "Wisconsin",
state != "Wisconsin" ~ "Out of State"
state %>%
)) mutate(state = fct_relevel(state, "Wisconsin")) %>%
select(-day_trips,-overnight_trips,-overnight_trips_n) %>%
pivot_longer(-c(ID, state), names_to = "categories", values_to = "spending") %>%
group_by(state, categories) %>%
summarise(estimate = mean(spending, na.rm = TRUE),
se = sd(spending, na.rm = TRUE)/sqrt(n()),
sample_size = n()) %>%
ungroup()
# Save the data
write_rds(exp_trip, "../00_data/data_wrangled/01_exp_trip.rds")
# Get total
<- exp_trip %>%
total filter(str_detect(categories, "day")) %>%
group_by(state) %>%
summarise(total = sum(estimate))
# Table for day trip expenditure
%>%
exp_trip pivot_wider(names_from = state,
names_sep = ".",
values_from = c(estimate, se, sample_size)) %>%
filter(str_detect(categories, "day")) %>%
mutate(categories = str_remove(categories, "day_trips_")) %>%
arrange(desc(`estimate.Wisconsin`)) %>%
# Add row of total
::add_row(categories = "total",
tibbleestimate.Wisconsin = total$total[total$state == "Wisconsin"],
`estimate.Out of State` = total$total[total$state == "Out of State"]) %>%
set_names("Categories", "Resident", "Nonresident",
"Resident", "Nonresident",
"Resident", "Nonresident") %>%
::kable(digits = 1, caption = "Day Trip Spending per Trip") %>%
knitradd_header_above(c(" " = 1, "Estimate" = 2, "Standard Error" = 2, "Sample Size" = 2), align = "c")
Categories | Resident | Nonresident | Resident | Nonresident | Resident | Nonresident |
---|---|---|---|---|---|---|
food | 95.0 | 106.0 | 2.0 | 4.9 | 831 | 117 |
transport | 71.0 | 87.9 | 1.8 | 5.7 | 831 | 117 |
recreate | 55.9 | 52.4 | 2.2 | 5.0 | 831 | 117 |
souvenir | 31.2 | 32.9 | 1.4 | 4.1 | 831 | 117 |
entrance | 27.6 | 14.4 | 1.9 | 2.0 | 831 | 117 |
total | 280.6 | 293.7 | NA | NA | NA | NA |
# Get total
<- exp_trip %>%
total filter(str_detect(categories, "overnight")) %>%
group_by(state) %>%
summarise(total = sum(estimate))
# Table for overnight trip expenditure
%>%
exp_trip pivot_wider(names_from = state,
names_sep = ".",
values_from = c(estimate, se, sample_size)) %>%
filter(str_detect(categories, "overnight")) %>%
mutate(categories = str_remove(categories, "overnight_trips_")) %>%
arrange(desc(`estimate.Wisconsin`)) %>%
# Add row of total
::add_row(categories = "total",
tibbleestimate.Wisconsin = total$total[total$state == "Wisconsin"],
`estimate.Out of State` = total$total[total$state == "Out of State"]) %>%
set_names("Categories", "Resident", "Nonresident",
"Resident", "Nonresident",
"Resident", "Nonresident") %>%
::kable(digits = 1, caption = "Overnight Trip Spending per Trip") %>%
knitradd_header_above(c(" " = 1, "Estimate" = 2, "Standard Error" = 2, "Sample Size" = 2), align = "c")
Categories | Resident | Nonresident | Resident | Nonresident | Resident | Nonresident |
---|---|---|---|---|---|---|
food | 229.8 | 250.2 | 5.6 | 14.2 | 831 | 117 |
lodging | 202.6 | 231.8 | 7.8 | 27.3 | 831 | 117 |
transport | 153.1 | 149.7 | 4.0 | 10.1 | 831 | 117 |
recreate | 113.7 | 110.4 | 4.4 | 9.8 | 831 | 117 |
souvenir | 61.0 | 84.0 | 3.2 | 12.2 | 831 | 117 |
entrance | 33.0 | 35.1 | 1.9 | 7.3 | 831 | 117 |
total | 793.2 | 861.1 | NA | NA | NA | NA |
During day trips, resident riders in Wisconsin spent an average of $281, while nonresident riders spent slightly more at $294. The breakdown of itemized spending by residency is illustrated in the plot above.
Among day-trip expenses, ATV/UTV riders allocate the majority of their spending to gasoline and food. Notably, non-residents tend to spend more per trip compared to residents.
# Graph for day trip expenditure
<- exp_trip %>%
fig_spending_per_day_trip filter(str_detect(categories, "day_trips")) %>%
mutate(categories = str_remove(categories, "day_trips_")) %>%
ggplot(aes(estimate, fct_reorder(categories, estimate))) +
geom_point() +
geom_errorbar(aes(xmin = estimate - 1.96*se,
xmax = estimate + 1.96*se)) +
scale_x_continuous(labels = scales::dollar) +
facet_wrap(~state) +
labs(
title = "Figure 6: Day Trip Spending per Trip",
subtitle = "95 Confidence Interval",
x = NULL,
y = NULL
+
) ::theme_tq()
tidyquant
fig_spending_per_day_trip
write_rds(fig_spending_per_day_trip, "../00_data/figures/01_fig_spending_per_day_trip.rds")
During overnight trips, resident riders in Wisconsin spent an average of $793, while nonresident riders spent slightly more at $861. The breakdown of itemized spending by residency is illustrated in the plot above.
On overnight trips, ATV/UTV riders tend to spend more compared to their day trips, with lodging and food being the primary expenses. Similar to day trips, non-residents likely spend more per trip compared to residents.
# Graph for overnight trip expenditure
<- exp_trip %>%
fig_spending_per_overnight_trip filter(str_detect(categories, "overnight_trips")) %>%
mutate(categories = str_remove(categories, "overnight_trips_")) %>%
ggplot(aes(estimate, fct_reorder(categories, estimate))) +
geom_point() +
geom_errorbar(aes(xmin = estimate - 1.96*se,
xmax = estimate + 1.96*se)) +
scale_x_continuous(labels = scales::dollar) +
facet_wrap(~state) +
labs(
title = "Figure 7: Overnight Trip Spending per Trip",
subtitle = "95 Confidence Interval",
x = NULL,
y = NULL
+
) ::theme_tq()
tidyquant
fig_spending_per_overnight_trip
write_rds(fig_spending_per_overnight_trip, "../00_data/figures/01_fig_spending_per_overnight_trip.rds")
# Estimate spending, standard errors, and sample size
<- riders_outlierRemoved %>%
exp_equipment #create profiles by trip types
mutate(state = case_when(
== "Wisconsin" ~ "Wisconsin",
state != "Wisconsin" ~ "Out of State"
state %>%
)) mutate(state = fct_relevel(state, "Wisconsin")) %>%
# Count all riders by state
add_count(state, name = "n_state_all") %>%
#filter for only those who spend $ on equipment
filter(spend_prep_for_trip == "Yes") %>%
# Count those riders who bought equipment
add_count(state, name = "n_state_spend") %>%
#select trip expenditure
select(state, starts_with("n_"), starts_with("spend"), -spend_prep_for_trip) %>%
pivot_longer(starts_with("spend"), names_to = "categories", values_to = "spending") %>%
mutate(categories = str_remove(categories, "spend_prep_for_trip_")) %>%
group_by(state, categories) %>%
summarise(estimate = mean(spending, na.rm = TRUE),
se = sd(spending, na.rm = TRUE)/sqrt(n()),
pct_buying = mean(n_state_spend)/mean(n_state_all),
sample_size = mean(n_state_spend)) %>%
ungroup()
# Save the data
write_rds(exp_equipment, "../00_data/data_wrangled/01_exp_equipment.rds")
Resident ATV/UTV owners in Wisconsin allocate an average of $1,867 annually on equipment, while nonresident ATV/UTV owners spend slightly less at $1,444. The breakdown of itemized spending by residency is illustrated in the plot above.
In contrast to trip expenditures, Wisconsin residents tend to invest more in equipment and accessories compared to non-residents. This disparity in spending patterns may be explained by non-resident ATV/UTV owners choosing to purchase equipment items such as accessories and vehicle maintenance services closer to their homes, within their own state.
Regarding spending on equipment and accessories for their trips, nearly half of the ATV/UTV owners made purchases within Wisconsin in 2023. Specifically, 54.3% (451 out of 831) of residents and 39.3% (46 out of 117) of non-residents made purchases within Wisconsin during the same period.
# Get total
<- exp_equipment %>%
total group_by(state) %>%
summarise(total = sum(estimate))
# Create a table
%>%
exp_equipment pivot_wider(names_from = state,
names_sep = "_",
values_from = c(estimate, se,pct_buying, sample_size)) %>%
arrange(desc(`estimate_Wisconsin`)) %>%
# Add row of total
::add_row(categories = "total",
tibbleestimate_Wisconsin = total$total[total$state == "Wisconsin"],
`estimate_Out of State` = total$total[total$state == "Out of State"]) %>%
set_names(names(.) %>% str_replace_all("_", " ") %>% str_replace("se", "Standard Error") %>% str_to_title()) %>%
mutate(across(c(starts_with("Estimate"), starts_with("Standard")), ~scales::dollar(., accuracy = 1)),
across(starts_with("Pct"), ~scales::percent(., accuracy = 0.1))) %>%
set_names("Categories", "Resident", "Nonresident",
"Resident", "Nonresident",
"Resident", "Nonresident",
"Resident", "Nonresident") %>%
::kable(digits = 1, align = c("lrrrrrrrr"), caption = "Annual Equipment Spending per ATV/UTV Owner") %>%
knitradd_header_above(c(" " = 1, "Estimate" = 2, "Standard Error" = 2, "Percent of riders who bought equipment" = 2, "Sample Size" = 2), align = "c")
Categories | Resident | Nonresident | Resident | Nonresident | Resident | Nonresident | Resident | Nonresident |
---|---|---|---|---|---|---|---|---|
accessories | $806 | $484 | $44 | $74 | 48.7% | 39.3% | 405 | 46 |
maintenance | $404 | $336 | $17 | $37 | 48.7% | 39.3% | 405 | 46 |
insurance | $300 | $321 | $10 | $30 | 48.7% | 39.3% | 405 | 46 |
apparel | $203 | $189 | $12 | $25 | 48.7% | 39.3% | 405 | 46 |
govt | $86 | $76 | $3 | $8 | 48.7% | 39.3% | 405 | 46 |
other | $68 | $38 | $4 | $5 | 48.7% | 39.3% | 405 | 46 |
total | $1,867 | $1,444 | NA | NA | NA | NA | NA | NA |
# Create a graph
library(tidytext) # For reorder_within()
<- exp_equipment %>%
fig_spending_equipment_per_rider ggplot(aes(estimate,
::reorder_within(categories, estimate, state))) +
tidytextgeom_point() +
geom_errorbar(aes(xmin = estimate - 1.96*se,
xmax = estimate + 1.96*se)) +
scale_x_continuous(labels = scales::dollar) +
facet_wrap(~state, scales = "free_y") +
scale_y_reordered() +
labs(
title = "Figure 8: Annual Equipment Spending per ATV/UTV Owner",
subtitle = "95 Confidence Interval",
x = NULL,
y = NULL
+
) ::theme_tq()
tidyquant
fig_spending_equipment_per_rider
write_rds(fig_spending_equipment_per_rider, "../00_data/figures/01_fig_spending_equipment_per_rider.rds")
#ATV_UTV spending
<- riders_outlierRemoved %>%
exp_ATV_UTV # Count all responses
add_tally(name = "n_all") %>%
#filter for only those who spend $ on ATV_UTV
filter(ATV_UTV_new_dollar > 0 | ATV_UTV_used_dollar > 0) %>%
#select trip expenditure
select(ID, starts_with("n_"), (ends_with("dollar") & contains("ATV_UTV"))) %>%
pivot_longer(ends_with("dollar"), names_to = "categories", values_to = "spending", values_drop_na = TRUE) %>%
group_by(categories) %>%
summarise(estimate = mean(spending),
se = sd(spending)/sqrt(n()),
pct_buying = n()/mean(n_all),
sample_size = n()) %>%
ungroup()
#Towing truck spending
<- riders_outlierRemoved %>%
exp_Towing # Count all responses
add_tally(name = "n_all") %>%
#filter for only those who spend $ on OHRV
filter(Towing_new_dollar > 0 | Towing_used_dollar > 0) %>%
#select trip expenditure
select(ID, starts_with("n_"), (ends_with("dollar") & contains("Towing"))) %>%
pivot_longer(ends_with("dollar"), names_to = "categories", values_to = "spending", values_drop_na = TRUE) %>%
group_by(categories) %>%
summarise(estimate = mean(spending, na.rm = TRUE),
se = sd(spending, na.rm = TRUE)/sqrt(n()),
pct_buying = n()/mean(n_all),
sample_size = n()) %>%
ungroup()
# Combine spending on OHRV and towing truck
<- rbind(exp_ATV_UTV, exp_Towing) %>%
exp_vehicle mutate(categories = str_remove(categories, "_dollar")) %>%
mutate(categories = case_when(
== "ATV_UTV_new" ~ "New ATV_UTV",
categories == "ATV_UTV_used" ~ "Used ATV_UTV",
categories == "Towing_new" ~ "New Towing Truck",
categories == "Towing_used" ~ "Used Towing Truck"
categories
))
# Save the data
write_rds(exp_vehicle, "../00_data/data_wrangled/01_exp_vehicle.rds")
# Create table
%>%
exp_vehicle mutate(across(c(estimate, se), ~scales::dollar(.,accuracy = 1)),
pct_buying = scales::percent(pct_buying, accuracy = 0.1)) %>%
set_names("Categories", "Spending", "Standard Error",
"Pct Buying", "Sample Size") %>%
::kable(digits = 1, caption = "Spending on Vehicle per Buyer") knitr
Categories | Spending | Standard Error | Pct Buying | Sample Size |
---|---|---|---|---|
New ATV_UTV | $28,136 | $1,234 | 7.6% | 72 |
Used ATV_UTV | $10,977 | $1,542 | 3.9% | 37 |
New Towing Truck | $60,882 | $2,725 | 4.3% | 41 |
Used Towing Truck | $36,571 | $3,440 | 1.5% | 14 |
# Create graph
<- exp_vehicle %>%
fig_spending_vehicle_per_rider ggplot(aes(estimate,
fct_reorder(categories, estimate))) +
geom_point() +
geom_errorbar(aes(xmin = estimate - 1.96*se,
xmax = estimate + 1.96*se)) +
scale_x_continuous(labels = scales::dollar) +
labs(
title = "Figure 9: Spending on Vehicle per Buyer",
subtitle = "95 Confidence Interval",
x = NULL,
y = NULL
+
) ::theme_tq()
tidyquant
fig_spending_vehicle_per_rider
write_rds(fig_spending_vehicle_per_rider, "../00_data/figures/01_fig_spending_vehicle_per_rider.rds")
The survey revealed that 7.6% of riders purchased a new ATV or UTV in Wisconsin during 2023, with an average expenditure of $28,000 per person. Furthermore, 3.9% of respondents acquired a used ATV or UTV, spending an average of $11,000.
In addition to ATV/UTV purchases, the survey identified that 4.3% of participants bought a new towing truck, spending an average of $61,000 per person. Similarly, 1.5% of respondents opted for a used towing truck, with an average expenditure of $37,000.
These spending figures represent a significant increase of over 80% compared to the findings reported in the 2020 New Hampshire study1. It’s important to note that while spending per person does not necessarily equate to the price per unit, as individuals may purchase multiple units, this substantial increase between the two studies likely reflects inflation, particularly in vehicle prices since the pandemic.
The inflation in vehicle prices may also explain the notable decrease in the proportion of respondents who purchased vehicles, as reported in the 2020 New Hampshire study, with most proportions declining by nearly half. This decline in vehicle purchases can be attributed to the considerable increases in vehicle prices.
#ATV_UTV usage
<- riders_outlierRemoved %>%
usage_ATV_UTV
filter(ATV_UTV_new_pct > 0 | ATV_UTV_used_pct > 0) %>%
# Count riders who bought either new or used ATV/UTV
add_tally(name = "n_ATV_UTV_new_used") %>%
#select trip expenditure
select(ID, starts_with("n_"), matches("ATV.*_pct")) %>%
pivot_longer(ends_with("pct"), names_to = "categories", values_to = "usage", values_drop_na = TRUE) %>%
group_by(categories) %>%
summarise(estimate = mean(usage),
se = sd(usage)/sqrt(n()),
sample_size = n()) %>%
ungroup()
#Towing truck usage
<- riders_outlierRemoved %>%
usage_Towing
filter(Towing_new_pct > 0 | Towing_used_pct > 0) %>%
# Count riders who bought either new or used ATV/UTV
add_tally(name = "n_Towing_new_used") %>%
#select trip expenditure
select(ID, starts_with("n_"), matches("Towing.*_pct")) %>%
pivot_longer(ends_with("pct"), names_to = "categories", values_to = "usage", values_drop_na = TRUE) %>%
group_by(categories) %>%
summarise(estimate = mean(usage),
se = sd(usage)/sqrt(n()),
sample_size = n()) %>%
ungroup()
# Combine usages of ATV_UTV and towing truck
<- rbind(usage_ATV_UTV, usage_Towing) %>%
usage_vehicle mutate(categories = str_remove(categories, "_pct")) %>%
mutate(categories = case_when(
== "ATV_UTV_new" ~ "New ATV_UTV",
categories == "ATV_UTV_used" ~ "Used ATV_UTV",
categories == "Towing_new" ~ "New Towing Truck",
categories == "Towing_used" ~ "Used Towing Truck"
categories
))
# Save the data
write_rds(usage_vehicle, "../00_data/data_wrangled/01_usage_vehicle.rds")
# Create table
%>%
usage_vehicle # mutate(across(c(estimate, se), ~scales::percent(.,accuracy = 0.1))) %>%
set_names("Categories", "Pct Trail Riding", "Standard Error", "Sample Size") %>%
::kable(digits = 1, caption = "Usage of Vehicles") knitr
Categories | Pct Trail Riding | Standard Error | Sample Size |
---|---|---|---|
New ATV_UTV | 75.1 | 2.7 | 80 |
Used ATV_UTV | 66.0 | 5.0 | 43 |
New Towing Truck | 35.2 | 5.1 | 45 |
Used Towing Truck | 30.7 | 7.3 | 16 |
# Create graph
<- usage_vehicle %>%
fig_usage_vehicle_per_rider ggplot(aes(estimate,
fct_reorder(categories, estimate))) +
geom_point() +
geom_errorbar(aes(xmin = estimate - 1.96*se,
xmax = estimate + 1.96*se)) +
# scale_x_continuous(labels = scales::percent) +
labs(
title = "Figure 10: Usage of Vehicles",
subtitle = "95 Confidence Interval",
y = NULL,
x = "Percent Use for Trail Riding",
caption = "The survey asked, ' Thinking of the usage in 2023 of the NEW ATV or UTV
you bought or will buy, what percentage is for trail riding?'
A similar question was asked regarding the towing truck usage."
+
) ::theme_tq()
tidyquant
fig_usage_vehicle_per_rider
write_rds(fig_usage_vehicle_per_rider, "../00_data/figures/01_fig_usage_vehicle_per_rider.rds")
Vehicles serve purposes beyond recreational riding activity, necessitating careful consideration when estimating the economic contributions of ATV/UTV riders. To ensure accuracy, vehicle spending should only be attributed to recreational riding activity, excluding other uses like commuting, shopping, or other outdoor recreational pursuits such as hunting.
Respondents who purchased a new ATV/UTV in Wisconsin during 2023 reported using the vehicle for recreational riding 75.1% of the time. Similarly, individuals who purchased a new towing truck in Wisconsin during the same period reported allocating the vehicle for recreational riding 35.2% of the time. These percentages provide valuable insights for refining economic estimations, facilitating more accurate assessments of economic contributions.
The survey also inquired about rider characteristics beyond their spending behaviors. Unlike the spending data presented earlier, the data in this section have not been adjusted for outliers. They represent raw data collected from the survey. However, obvious reporting errors were rectified. For instance, if someone reported a value exceeding 100% for a question regarding the percentage of their winter riding compared to their total riding time, that data point was excluded. It’s important to note that the data presented in this section are not utilized in measuring the economic contribution of riders.
<- riders_outlierRemoved %>%
riders left_join(riders_renamed %>%
select(ID, age, state_other, income, second_home,
c(winter_riding_pct:ATV_UTV_purposes_Other)))
<- c("winter_riding_pct", "road_route_touring_pct", "ATV_owned", "UTV_owned")
numeric_vec <- c("state", "state_other", "age", "income", "second_home", "Trail_Riding", "Road_Route_Touring",
factor_vec "Commuting_to_Work", "Farming", "Hunting", "Shopping")
<- riders %>%
riders_clean select(ID, state, age:ATV_UTV_purposes_Other, -ATV_UTV_purposes, -ATV_UTV_purposes_Other) %>%
# Set max at 100% where it must not be higher than 100%
mutate(across(contains("pct"), function(x) if_else(x > 100, NA, x))) %>%
# Set max # of vehicles owned at 20
# mutate(across(contains("own"), function(x) if_else(x > 20, NA, x))) %>%
# State: Wisconsin versus Others
mutate(state = case_when(
== "Wisconsin" ~ "Resident",
state != "Wisconsin" ~ "nonResident"
state %>%
))
# Convert character to numeric
mutate(across(all_of(numeric_vec), as.numeric)) %>%
# Convert character to factor
mutate(across(all_of(factor_vec), as_factor))
Riders typically fall within the middle age range. Age groups under 35 constitute less than 7% of both resident and nonresident riders. The largest age demographic falls within the 55-64 years old bracket.
<- riders_clean %>%
fig_rider_age filter(!is.na(age), age != "invalid") %>%
group_by(state) %>%
count (age) %>%
add_tally(wt = n) %>%
mutate(pct = (n/nn*100) %>% round(1),
pct_txt = paste0(pct, "%")) %>%
ungroup() %>%
ggplot(aes(n, age, fill = state)) +
geom_col() +
geom_text(aes(label = pct_txt), hjust = -0.1) +
theme_tq() +
theme(legend.position = "none") +
scale_fill_tq() +
expand_limits(x = c(0,350)) +
facet_wrap(~state, scales = "free_x") +
labs(
title = "Age Distribution of Riders",
y = "Age Categories",
x = "Number of Survey Responses",
caption = "The survey asked, 'What is your age?'"
)
fig_rider_age
write_rds(fig_rider_age, "../00_data/figures/01_fig_rider_age.rds")
The overwhelming majority of riders originate from within Wisconsin, with 87.7% reporting residency within the state. The second-largest group, comprising only 5.4% of riders, hails from Illinois, a statistic likely reflective of residents from Chicago and its surrounding areas. It’s noteworthy that nonresident riders in Wisconsin predominantly come from neighboring states.
<- riders %>%
fig_rider_state_of_origin count(state, sort = T) %>%
add_tally(wt = n) %>%
mutate(pct = (n/nn*100) %>% round(1),
pct_txt = paste0(pct, "%")) %>%
ggplot(aes(n, fct_reorder(state, n))) +
geom_col(fill = "midnightblue") +
geom_text(aes(label = pct_txt), hjust = -0.1) +
theme_tq() +
expand_limits(x = c(0, 1000)) +
labs(title = "State of Origin",
subtitle = "ATVing in Wisconsin during 2020",
y = NULL,
x = "Number of Survey Responses",
caption = "Other includes Florida, Pennsylvania, Tennessee, New York, and Arizona.
The survey asked, 'In which state do you current reside?'")
fig_rider_state_of_origin
write_rds(fig_rider_state_of_origin, "../00_data/figures/01_fig_rider_state_of_origin.rds")
Many riders possess second homes, indicating a propensity for multiple residences within the riding community. Approximately 25% of resident riders reported owning a second home. Notably, this percentage is even higher among nonresident riders, suggesting a greater prevalence of secondary residences among those who ride in Wisconsin but reside elsewhere.
<- riders_clean %>%
fig_rider_second_home
filter(!is.na(second_home)) %>%
ggplot(aes(state, fill = second_home)) +
geom_bar(position = "fill") +
theme_tq() +
scale_fill_tq() +
scale_y_continuous(labels = scales::percent_format()) +
# expand_limits(x = c(0, 5)) +
labs(title = "Second Home Ownership",
subtitle = "ATVing in Wisconsin during 2023",
y = "Proportion",
x = NULL, fill = NULL,
caption = "The survey asked, 'Do you own a second home in Wisconsin?'")
fig_rider_second_home
write_rds(fig_rider_second_home, "../00_data/figures/01_fig_rider_second_home.rds")
Riders tend to have higher household incomes. Among both resident and nonresident riders, the highest income group, earning $150,000 or more per year, ranks at the top. However, while this income bracket is the highest for both groups, it constitutes a significantly larger proportion of the total among nonresidents compared to residents.
<- riders_clean %>%
fig_rider_income
filter(!is.na(income), income != "Prefer not to answer") %>%
mutate(income = fct_rev(income)) %>%
group_by(state) %>%
count(income, sort = T) %>%
add_tally(wt = n) %>%
mutate(pct = (n/nn*100) %>% round(1),
pct_txt = paste0(pct, "%"))%>%
ungroup() %>%
ggplot(aes(n, income, fill = state)) +
geom_text(aes(label = pct_txt), hjust = -0.01) +
geom_col() +
facet_wrap(~state) +
theme_tq() +
theme(legend.position = "none") +
scale_fill_tq() +
expand_limits(x = c(0, 220)) +
labs(title = "Houehold Income of Riders",
subtitle = "ATVing in Wisconsin during 2023",
y = NULL,
x = "Number of Survey Responses",
caption = "The survey asked, 'What is your total household income?'")
fig_rider_income
write_rds(fig_rider_income, "../00_data/figures/01_fig_rider_income.rds")
Among surveyed riders, a substantial majority, accounting for 75%, reported that their winter riding activities constitute less than 20% of their total riding time. Interestingly, winter riding seems to be even less common among nonresident riders. For instance, the median nonresident rider, as indicated by the horizontal line in the box of the plot, reported no winter riding at all. In contrast, the median resident rider indicated that winter riding comprises approximately 10% of their total riding time.
<- riders_clean %>%
fig_rider_winter_riding
# Remove reporting errors
filter(winter_riding_pct <= 100) %>%
ggplot(aes(state, winter_riding_pct, fill = state)) +
geom_boxplot() +
theme_tq() +
theme(legend.position = "none") +
scale_fill_tq() +
labs(title = "Percent of Winter Riding in Total",
subtitle = "ATVing in Wisconsin during 2023",
y = "Percent of Winter Riding",
x = NULL,
caption = "The survey asked, 'Thinking of ATV/UTV recreational riding in 2023,
what percentage will be for winter riding?'")
fig_rider_winter_riding
write_rds(fig_rider_winter_riding, "../00_data/figures/01_fig_rider_winter_riding.rds")
Road route touring appears to be highly popular among surveyed riders. For resident riders, 50% indicated that road route touring constitutes between 20% and 60% of their total riding time, as depicted by the height of the box in the plot. Similarly, nonresident riders exhibit a comparable distribution, albeit slightly lower. The median resident rider, represented by the horizontal line in the box of the plot, reported that road route touring makes up approximately 30% of their total riding time.
<- riders_clean %>%
fig_rider_road_route_touring
# Remove reporting errors
filter(road_route_touring_pct <= 100) %>%
ggplot(aes(state, road_route_touring_pct, fill = state)) +
geom_boxplot() +
theme_tq() +
theme(legend.position = "none") +
scale_fill_tq() +
labs(title = "Percent of Road Route Touring in Total",
subtitle = "ATVing in Wisconsin during 2023",
y = "Percent of Road Route Touring",
x = NULL,
caption = "The survey asked, 'Thinking of ATV / UTV riding in 2023,
what percentage will be for only road route touring?'")
fig_rider_road_route_touring
write_rds(fig_rider_road_route_touring, "../00_data/figures/01_fig_rider_road_route_touring.rds")
The majority of riders, regardless of residence status, own one or two vehicles. However, there are outliers within the resident group. For instance, one rider reported owning 65 vehicles, while another reported owning 25 vehicles. These outliers likely represent rental businesses. It’s worth noting that rental businesses are not within the scope of this study and are not considered in measuring the economic contribution of riders.
<- riders_clean %>%
fig_rider_n_ATV_UTV_owned
group_by(state) %>%
mutate(ATV_UTV_owned = ATV_owned + UTV_owned) %>%
count(ATV_UTV_owned) %>%
filter(!is.na(ATV_UTV_owned)) %>%
add_tally(wt = n) %>%
mutate(pct = (n/nn * 100) %>% round(1)) %>%
mutate(pct_txt = paste0(pct,"%")) %>%
ungroup() %>%
ggplot(aes(n, ATV_UTV_owned %>% as.factor() %>% fct_rev(), fill = state)) +
geom_col() +
geom_text(aes(label = pct_txt), hjust = -0.1)+
theme_tq() +
theme(legend.position = "none") +
scale_fill_tq() +
expand_limits(x = c(0, 160)) +
facet_wrap(~state) +
labs(title = "Number of ATV/UTVs Owned",
subtitle = "ATVing in Wisconsin during 2023",
y = "Number of ATVs or UTVs",
x = "Number of Survey Responses",
caption = "The survey asked, 'How many ATVs do you, or will you own in 2023?'
The same question was asked for UTVs.")
fig_rider_n_ATV_UTV_owned
write_rds(fig_rider_n_ATV_UTV_owned, "../00_data/figures/01_fig_rider_n_ATV_UTV_owned.rds")
Among ATV/UTV riders, trail riding emerges as the most prevalent usage, closely followed by road route touring. In response to inquiries about the various uses of their ATV/UTVs, a vast majority of riders indicated a preference for trail riding, with 94% of residents and 97% of nonresidents reporting enjoyment in this activity. Additionally, 79% of surveyed riders identified road route touring as a favored activity, while 74% of nonresident riders shared this sentiment.
Furthermore, hunting emerged as a significant activity for riders, alongside other notable purposes such as shopping, farming, and commuting to work. In the survey’s “other” category, respondents mentioned engaging in activities like fishing and plowing, further illustrating the diverse range of purposes for which ATV/UTVs are utilized.
<- riders_clean %>%
fig_rider_purposes_of_riding select(ID, state, Trail_Riding:Shopping) %>%
pivot_longer(-c(ID, state)) %>%
mutate(value = value %>% as.character() %>% as.integer() %>% as.logical()) %>%
group_by(state, name) %>%
summarise(#n = sum(value),
#total = n(),
pct = (mean(value, na.rm = TRUE) * 100) %>% round(0)) %>%
ungroup() %>%
mutate(pct_txt = paste0(pct,"%")) %>%
mutate(name = name %>% str_replace_all("_", " ") %>% stringr::str_to_title()) %>%
ggplot(aes(pct, fct_reorder(name, pct), fill = state)) +
geom_col() +
facet_wrap(~state) +
geom_text(aes(label = pct_txt), hjust = -0.1) +
theme_tq() +
theme(legend.position = "none") +
scale_fill_tq() +
expand_limits(x = c(0, 120)) +
labs(title = "Purposes of ATV/UTV Riding",
subtitle = "ATVing in Wisconsin during 2023",
x = "Percent in Total Survey Responses",
y = NULL,
caption = "The survey asked, 'Thinking of the usage in 2023
of your ATV(s) or UTV(s), check all that applies.'")
fig_rider_purposes_of_riding
write_rds(fig_rider_purposes_of_riding, "../00_data/figures/01_fig_rider_purposes_of_riding.rds")
Accessed on 2/26/2024 at https://www.nhstateparks.org/getmedia/d0c3e291-63e1-463c-9c2c-37e7b1b0a8fc/2020-OHRV-Economic-Study-2021.aspx#:~:text=It%20was%20estimated%20that%20OHRV,during%20the%20calendar%20year%202020.↩︎