Introduction

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.

Planned Approach

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.

Anticipated Data Challenges

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.

Data Loading and Scope

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)"

Data Preparation

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, …

Data Quality Check

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>

Data Cleaning

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

Overall Rebate Summary

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"
)
Overall Drive Clean Rebate Summary
Completed Applications Total Rebate Dollars Average Rebate Median Rebate
241,983 $213,492,600 $882.26 $500

Comparison by Manufacturer

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"
)
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"
  )

Comparison by Vehicle Model

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"
)
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")

Comparison by EV Type

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"
)
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"
  )

Comparison by Transaction Type

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"
)
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

Findings

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.

Conclusions and Recommendations

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.

AI Use

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.