For my Week 1 assignment, I selected the NYSERDA Electric Vehicle Drive Clean Rebate Data: Beginning 2017. The dataset was published by the New York State Energy Research and Development Authority and contains completed rebate applications with information about vehicle manufacturers, models, counties, EV types, transaction types, estimated emissions reductions, and rebate amounts. I selected this dataset because I am an electrical engineer, I am passionate about electric vehicles, and I want to understand how New York’s rebate program supports their purchase or lease.
My main question is: How do vehicle manufacturer, model, EV type, and transaction type relate to the number and amount of Drive Clean rebates issued in New York State? I downloaded the original data from the New York State Open Data website and stored a fixed copy in my public GitHub repository to make the analysis reproducible. I will review the data structure, select the variables relevant to my question, and assign clear column names. I will then compare the number of completed rebate applications, total rebate dollars, and average rebate amounts across manufacturers, vehicle models, EV types, and transaction types using summary tables and visualizations.
I anticipate that the dataset may contain missing values in some categorical variables and records that appear similar because multiple customers can receive rebates for the same vehicle model. Because the dataset does not include a unique application identifier, I will not automatically remove repeated-looking rows. I will also convert the submission date into a proper date format, document all cleaning decisions, and use a public GitHub URL so that the analysis can be reproduced.
After reviewing the available columns, I found that the dataset does not include a direct electric-range variable. Therefore, I adjusted the analysis to focus on vehicle manufacturers, models, EV types, transaction types, completed rebate applications, and rebate amounts. Electric range could be added in a future analysis by combining this dataset with another reliable vehicle-data source.
The original CSV was downloaded from the New York State Open Data website and stored as a fixed file in my public GitHub repository. The R code reads the CSV through its GitHub Raw URL so that the analysis can run in another environment without using a local file path.
data_url <- paste0(
"https://raw.githubusercontent.com/",
"howtwo388-cyber/DATA607-Week1-Electric-Vehicles/",
"main/data/ev_drive_clean_rebates.csv"
)
ev_raw <- read_csv(
data_url,
col_types = cols(
ZIP = col_character()
)
)
dim(ev_raw)
## [1] 241983 11
names(ev_raw)
## [1] "Data through Date"
## [2] "Submitted Date"
## [3] "Make"
## [4] "Model"
## [5] "County"
## [6] "ZIP"
## [7] "EV Type"
## [8] "Transaction Type"
## [9] "Annual GHG Emissions Reductions (MT CO2e)"
## [10] "Annual Petroleum Reductions (gallons)"
## [11] "Rebate Amount (USD)"
Each row represents one completed rebate application. I selected the variables that are relevant to the analysis and assigned clear, consistent column names. The rebate amount is the main target variable.
ev <- ev_raw %>%
transmute(
submitted_date = `Submitted Date`,
manufacturer = Make,
model = Model,
county = County,
ev_type = `EV Type`,
transaction_type = `Transaction Type`,
annual_ghg_reduction_mt =
`Annual GHG Emissions Reductions (MT CO2e)`,
rebate_amount_usd = `Rebate Amount (USD)`
)
glimpse(ev)
## Rows: 241,983
## Columns: 8
## $ submitted_date <chr> "05/28/2020", "06/26/2025", "03/30/2017", "03/…
## $ manufacturer <chr> "Tesla", "Kia", "Audi", "Toyota", "Kia", "Toyo…
## $ model <chr> "Model Y", "Sportage", "A3 e-tron", "Prius Pri…
## $ county <chr> NA, NA, "Albany", "Albany", "Albany", "Albany"…
## $ ev_type <chr> "BEV", "PHEV", "PHEV", "PHEV", "BEV", "PHEV", …
## $ transaction_type <chr> "Purchase", "Lease", "Purchase", "Purchase", "…
## $ annual_ghg_reduction_mt <dbl> 3.093, 1.689, 1.629, 2.955, 2.718, 2.955, 2.64…
## $ rebate_amount_usd <dbl> 2000, 500, 500, 1100, 1700, 1100, 1700, 1700, …
Before performing the analysis, I checked the selected variables for missing values. I did not automatically remove repeated-looking rows because multiple customers may receive rebates for the same vehicle model on the same date.
missing_values <- ev %>%
summarise(
across(
everything(),
~ sum(is.na(.))
)
)
missing_values
## # A tibble: 1 × 8
## submitted_date manufacturer model county ev_type transaction_type
## <int> <int> <int> <int> <int> <int>
## 1 0 0 0 2 0 4
## # ℹ 2 more variables: annual_ghg_reduction_mt <int>, rebate_amount_usd <int>
The submission date was converted from text into a date variable. Missing county and transaction-type values were labeled as “Unknown” so that the corresponding applications remain in the analysis.
ev_clean <- ev %>%
mutate(
submitted_date = mdy(submitted_date),
county = replace_na(county, "Unknown"),
transaction_type = replace_na(
transaction_type,
"Unknown"
)
)
quality_summary <- tibble(
number_of_rows = nrow(ev_clean),
number_of_columns = ncol(ev_clean),
remaining_missing_values = sum(is.na(ev_clean))
)
quality_summary
## # A tibble: 1 × 3
## number_of_rows number_of_columns remaining_missing_values
## <int> <int> <int>
## 1 241983 8 0
I first calculated the total number of completed applications, total rebate dollars, average rebate amount, and median rebate amount. These values provide an overall view of the Drive Clean Rebate program represented in the dataset.
overall_summary <- ev_clean %>%
summarise(
completed_applications = n(),
total_rebate_dollars =
sum(rebate_amount_usd, na.rm = TRUE),
average_rebate =
mean(rebate_amount_usd, na.rm = TRUE),
median_rebate =
median(rebate_amount_usd, na.rm = TRUE)
)
overall_summary_display <- overall_summary %>%
transmute(
`Completed Applications` = format(
completed_applications,
big.mark = ",",
scientific = FALSE
),
`Total Rebate Dollars` = scales::dollar(
total_rebate_dollars,
accuracy = 1
),
`Average Rebate` = scales::dollar(
average_rebate,
accuracy = 0.01
),
`Median Rebate` = scales::dollar(
median_rebate,
accuracy = 1
)
)
knitr::kable(
overall_summary_display,
align = "rrrr",
caption = "Overall Drive Clean Rebate Summary"
)
| Completed Applications | Total Rebate Dollars | Average Rebate | Median Rebate |
|---|---|---|---|
| 241,983 | $213,492,600 | $882.26 | $500 |
I compared manufacturers using the number of completed rebate applications, total rebate dollars, and average rebate amount. The table displays the ten manufacturers with the largest number of completed applications.
manufacturer_summary <- ev_clean %>%
group_by(manufacturer) %>%
summarise(
completed_applications = n(),
total_rebate_dollars =
sum(rebate_amount_usd, na.rm = TRUE),
average_rebate =
mean(rebate_amount_usd, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(completed_applications)) %>%
slice_head(n = 10)
manufacturer_summary_display <- manufacturer_summary %>%
transmute(
Manufacturer = manufacturer,
`Completed Applications` = scales::comma(
completed_applications
),
`Total Rebate Dollars` = scales::dollar(
total_rebate_dollars,
accuracy = 1
),
`Average Rebate` = scales::dollar(
average_rebate,
accuracy = 0.01
)
)
knitr::kable(
manufacturer_summary_display,
align = "lrrr",
caption = "Top 10 Manufacturers by Completed Rebate Applications"
)
| Manufacturer | Completed Applications | Total Rebate Dollars | Average Rebate |
|---|---|---|---|
| Tesla | 108,237 | $87,522,500 | $808.62 |
| Toyota | 36,015 | $36,307,400 | $1,008.12 |
| Jeep | 17,398 | $8,855,600 | $509.00 |
| Chevrolet | 13,411 | $24,650,300 | $1,838.07 |
| Hyundai | 11,000 | $12,162,400 | $1,105.67 |
| Kia | 9,402 | $8,184,600 | $870.52 |
| Ford | 8,578 | $6,682,400 | $779.02 |
| BMW | 7,608 | $4,201,500 | $552.25 |
| Honda | 5,846 | $6,288,500 | $1,075.69 |
| Volvo | 4,729 | $2,560,400 | $541.43 |
manufacturer_plot <- manufacturer_summary %>%
mutate(
rank = row_number(),
color_group = case_when(
rank == 1 ~ "1st Place",
rank == 2 ~ "2nd Place",
rank == 3 ~ "3rd Place",
TRUE ~ "Other"
)
)
ggplot(
manufacturer_plot,
aes(
x = reorder(manufacturer, completed_applications),
y = completed_applications,
fill = color_group
)
) +
geom_col() +
geom_text(
aes(label = scales::comma(completed_applications)),
hjust = -0.1,
size = 3
) +
coord_flip() +
scale_fill_manual(
values = c(
"1st Place" = "#08306B",
"2nd Place" = "#2171B5",
"3rd Place" = "#6BAED6",
"Other" = "#D9D9D9"
),
name = "Rank"
) +
scale_y_continuous(
labels = scales::comma,
expand = expansion(mult = c(0, 0.18))
) +
labs(
title = "Top 10 Manufacturers by Rebate Applications",
subtitle = "The three leading manufacturers are highlighted",
x = NULL,
y = "Completed Applications"
) +
theme_minimal() +
theme(
legend.position = "bottom"
)
I grouped the data by manufacturer and vehicle model to identify the models associated with the largest number of completed rebate applications. I also calculated total rebate dollars and the average rebate for each model.
model_summary <- ev_clean %>%
group_by(manufacturer, model) %>%
summarise(
completed_applications = n(),
total_rebate_dollars =
sum(rebate_amount_usd, na.rm = TRUE),
average_rebate =
mean(rebate_amount_usd, na.rm = TRUE),
.groups = "drop"
) %>%
mutate(
vehicle_model = paste(manufacturer, model)
) %>%
arrange(desc(completed_applications)) %>%
slice_head(n = 10)
model_summary_display <- model_summary %>%
transmute(
`Vehicle Model` = vehicle_model,
`Completed Applications` =
scales::comma(completed_applications),
`Total Rebate Dollars` =
scales::dollar(total_rebate_dollars, accuracy = 1),
`Average Rebate` =
scales::dollar(average_rebate, accuracy = 0.01)
)
knitr::kable(
model_summary_display,
align = "lrrr",
caption = "Top 10 Vehicle Models by Completed Rebate Applications"
)
| Vehicle Model | Completed Applications | Total Rebate Dollars | Average Rebate |
|---|---|---|---|
| Tesla Model Y | 65,720 | $43,336,000 | $659.40 |
| Tesla Model 3 | 32,694 | $39,274,500 | $1,201.28 |
| Toyota Prius Prime | 14,282 | $13,307,100 | $931.74 |
| Jeep Wrangler | 11,215 | $5,764,100 | $513.96 |
| Toyota RAV4 Prime | 9,903 | $11,074,800 | $1,118.33 |
| Chevrolet Bolt | 6,181 | $12,362,000 | $2,000.00 |
| Jeep Grand Cherokee | 6,096 | $3,048,000 | $500.00 |
| Tesla Model X | 5,856 | $2,928,500 | $500.09 |
| Toyota RAV4 | 5,345 | $2,972,000 | $556.03 |
| Chevrolet Equinox EV | 4,471 | $8,942,000 | $2,000.00 |
model_plot <- model_summary %>%
mutate(
rank = row_number(),
color_group = case_when(
rank == 1 ~ "1st Place",
rank == 2 ~ "2nd Place",
rank == 3 ~ "3rd Place",
TRUE ~ "Other"
)
)
ggplot(
model_plot,
aes(
x = reorder(vehicle_model, completed_applications),
y = completed_applications,
fill = color_group
)
) +
geom_col() +
geom_text(
aes(label = scales::comma(completed_applications)),
hjust = -0.1,
size = 3
) +
coord_flip() +
scale_fill_manual(
values = c(
"1st Place" = "#54278F",
"2nd Place" = "#756BB1",
"3rd Place" = "#9E9AC8",
"Other" = "#D9D9D9"
),
name = "Rank"
) +
scale_y_continuous(
labels = scales::comma,
expand = expansion(mult = c(0, 0.18))
) +
labs(
title = "Top 10 Vehicle Models by Rebate Applications",
subtitle = "The three leading models are highlighted",
x = NULL,
y = "Completed Applications"
) +
theme_minimal() +
theme(legend.position = "bottom")
The dataset classifies vehicles as Battery Electric Vehicles (BEV) or Plug-in Hybrid Electric Vehicles (PHEV). I compared their number of completed applications, share of all applications, total rebate dollars, and typical rebate amounts.
ev_type_summary <- ev_clean %>%
group_by(ev_type) %>%
summarise(
completed_applications = n(),
percentage_of_applications =
n() / nrow(ev_clean),
total_rebate_dollars =
sum(rebate_amount_usd, na.rm = TRUE),
average_rebate =
mean(rebate_amount_usd, na.rm = TRUE),
median_rebate =
median(rebate_amount_usd, na.rm = TRUE),
average_ghg_reduction =
mean(annual_ghg_reduction_mt, na.rm = TRUE),
.groups = "drop"
)
ev_type_summary_display <- ev_type_summary %>%
transmute(
`EV Type` = ev_type,
`Completed Applications` =
scales::comma(completed_applications),
`Percentage of Applications` =
scales::percent(
percentage_of_applications,
accuracy = 0.1
),
`Total Rebate Dollars` =
scales::dollar(total_rebate_dollars, accuracy = 1),
`Average Rebate` =
scales::dollar(average_rebate, accuracy = 0.01),
`Median Rebate` =
scales::dollar(median_rebate, accuracy = 1),
`Average GHG Reduction` =
round(average_ghg_reduction, 2)
)
knitr::kable(
ev_type_summary_display,
align = "lrrrrrr",
caption = "Comparison of BEV and PHEV Rebate Applications"
)
| EV Type | Completed Applications | Percentage of Applications | Total Rebate Dollars | Average Rebate | Median Rebate | Average GHG Reduction |
|---|---|---|---|---|---|---|
| BEV | 164,001 | 67.8% | $152,948,700 | $932.61 | $500 | 2.88 |
| PHEV | 77,982 | 32.2% | $60,543,900 | $776.38 | $500 | 1.52 |
ggplot(
ev_type_summary,
aes(
x = ev_type,
y = average_rebate,
fill = ev_type
)
) +
geom_col(width = 0.65) +
geom_text(
aes(label = scales::dollar(average_rebate)),
vjust = -0.5,
size = 4
) +
scale_fill_manual(
values = c(
"BEV" = "#1B9E77",
"PHEV" = "#D95F02"
)
) +
scale_y_continuous(
labels = scales::dollar,
expand = expansion(mult = c(0, 0.12))
) +
labs(
title = "Average Rebate by EV Type",
subtitle = "Battery electric versus plug-in hybrid vehicles",
x = "EV Type",
y = "Average Rebate"
) +
theme_minimal() +
theme(
legend.position = "none"
)
I compared purchases and leases to determine how transaction type relates to the number and amount of rebates. Records with an unknown transaction type are retained in the table for transparency but excluded from the visualization.
transaction_summary <- ev_clean %>%
group_by(transaction_type) %>%
summarise(
completed_applications = n(),
percentage_of_applications =
n() / nrow(ev_clean),
total_rebate_dollars =
sum(rebate_amount_usd, na.rm = TRUE),
average_rebate =
mean(rebate_amount_usd, na.rm = TRUE),
median_rebate =
median(rebate_amount_usd, na.rm = TRUE),
.groups = "drop"
)
transaction_summary_display <- transaction_summary %>%
transmute(
`Transaction Type` = transaction_type,
`Completed Applications` =
scales::comma(completed_applications),
`Percentage of Applications` =
scales::percent(
percentage_of_applications,
accuracy = 0.1
),
`Total Rebate Dollars` =
scales::dollar(total_rebate_dollars, accuracy = 1),
`Average Rebate` =
scales::dollar(average_rebate, accuracy = 0.01),
`Median Rebate` =
scales::dollar(median_rebate, accuracy = 1)
)
knitr::kable(
transaction_summary_display,
align = "lrrrrr",
caption = "Comparison of Rebate Applications by Transaction Type"
)
| Transaction Type | Completed Applications | Percentage of Applications | Total Rebate Dollars | Average Rebate | Median Rebate |
|---|---|---|---|---|---|
| Lease | 110,670 | 45.7% | $92,591,700 | $836.65 | $500 |
| Purchase | 131,309 | 54.3% | $120,898,400 | $920.72 | $500 |
| Unknown | 4 | 0.0% | $2,500 | $625.00 | $500 |
The dataset contains 241,983 completed rebate applications and more than $213 million in total rebates. The average rebate was about $882, but the median was $500.
Tesla had the most applications, and the Tesla Model Y was the most common model. However, the most popular vehicles did not always receive the highest average rebate. The Chevrolet Bolt and Equinox EV had an average rebate of $2,000.
BEVs represented 67.8% of the applications and had an average rebate of about $933. PHEVs represented 32.2% and had an average rebate of about $776. Purchases were slightly more common than leases and also had a higher average rebate.
The results show that a few manufacturers and models received most of the rebates. BEVs had more applications and higher average rebates than PHEVs. Purchases also had slightly higher average rebates than leases.
This dataset only includes completed rebate applications. It does not include electric range or vehicle price. A future analysis could add this information and compare results by year and county. The analysis should also be updated when new data becomes available.
OpenAI. (2026). ChatGPT [Large language model]. https://chat.openai.com/. Accessed September 3, 2026.
ChatGPT was used to help interpret the assignment requirements, organize the planned approach, edit the English writing, and provide step-by-step guidance. I reviewed the final text to ensure that it accurately represents my interests and intended analysis.