Tesla has become a leader in the new energy vehicle (NEV) market, especially in electric vehicles. In 2023, its Model Y, Model 3, and Model X led U.S. EV sales by a wide margin, with nearly 4 hundred thousand units sold for Model Y, 2.2 hundred thousand units for Model 3, and 23 thousand units for Model X.
However, existing studies mainly focus on factors like technology, pricing, and consumer preferences, without exploring how these factors combine to affect Tesla’s market leadership. This project aims to identify the key factors driving Tesla’s market leadership in electric vehicles, model the relationships between electric range, sale price, and vehicle type using machine learning, and evaluate the model’s performance for accuracy and reliability. Although the dataset is large, there may be limitations, such as the loss of significant amounts of data during the data cleaning process. Nonetheless, the results will provide valuable insights for policymakers, manufacturers, and consumers.
We began by collecting initial data from the Washington State open data portal, which includes Electric Vehicle Title and Registration Activity.
library(ggplot2)
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(cluster)
library(scales)
library(cowplot)
df <- read.csv('/Users/fizz_n_w/Desktop/UM Study/WQD7004/GP/Electric_Vehicle_Title_and_Registration_Activity_20241104.csv', stringsAsFactors = FALSE)
head(df)
## Clean.Alternative.Fuel.Vehicle.Type VIN..1.10. DOL.Vehicle.ID Model.Year
## 1 Battery Electric Vehicle (BEV) 1N4BZ0CP3G 348273537 2016
## 2 Battery Electric Vehicle (BEV) 5YJ3E1EB7K 244708467 2019
## 3 Battery Electric Vehicle (BEV) 5YJ3E1EB7K 244708467 2019
## 4 Battery Electric Vehicle (BEV) 1N4AZ1CPXK 4664348 2019
## 5 Plug-in Hybrid Electric Vehicle (PHEV) YV4H600A3P 227359303 2023
## 6 Battery Electric Vehicle (BEV) 1N4AZ1CPXK 4664348 2019
## Make Model Primary.Use Electric.Range Odometer.Reading
## 1 NISSAN Leaf Passenger 84 44004
## 2 TESLA Model 3 Passenger 220 0
## 3 TESLA Model 3 Passenger 220 50
## 4 NISSAN Leaf Passenger 150 0
## 5 VOLVO XC90 Passenger 32 0
## 6 NISSAN Leaf Passenger 150 46865
## Odometer.Reading.Description New.or.Used.Vehicle
## 1 Actual Mileage Used
## 2 Odometer reading is not collected at time of renewal New
## 3 Actual Mileage New
## 4 Odometer reading is not collected at time of renewal Used
## 5 Odometer reading is not collected at time of renewal Used
## 6 Actual Mileage Used
## Sale.Price Sale.Date Base.MSRP Transaction.Type
## 1 0 March 20 2024 0 Transfer Title
## 2 0 0 Original Registration
## 3 58100 February 06 2019 0 Original Title
## 4 0 0 Registration at time of Transfer
## 5 0 0 Registration Renewal
## 6 22491 March 15 2023 0 Transfer Title
## Transaction.Date Year County City State Postal.Code
## 1 March 27 2024 2024 Jefferson PORT TOWNSEND WA 98368
## 2 February 28 2019 2019 King BELLEVUE WA 98007
## 3 February 28 2019 2019 King BELLEVUE WA 98007
## 4 March 23 2023 2023 King ISSAQUAH WA 98027
## 5 January 05 2024 2024 King ISSAQUAH WA 98027
## 6 March 23 2023 2023 King ISSAQUAH WA 98027
## X2019.HB.2042..Clean.Alternative.Fuel.Vehicle..CAFV..Eligibility
## 1 HB 2042 Eligibility Requirements not met
## 2 HB 2042 Eligibility Requirements not met
## 3 HB 2042 Eligibility Requirements not met
## 4 HB 2042 Eligibility Requirements not met
## 5 HB 2042 Eligibility Requirements not met
## 6 Clean Alternative Fuel Vehicle
## Meets.2019.HB.2042.Electric.Range.Requirement
## 1 true
## 2 true
## 3 true
## 4 true
## 5 true
## 6 true
## Meets.2019.HB.2042.Sale.Date.Requirement
## 1 false
## 2 false
## 3 false
## 4 false
## 5 false
## 6 true
## Meets.2019.HB.2042.Sale.Price.Value.Requirement
## 1 false
## 2 false
## 3 false
## 4 false
## 5 false
## 6 true
## X2019.HB.2042..Battery.Range.Requirement
## 1 Battery range requirement is met
## 2 Battery range requirement is met
## 3 Battery range requirement is met
## 4 Battery range requirement is met
## 5 Battery range requirement is met
## 6 Battery range requirement is met
## X2019.HB.2042..Purchase.Date.Requirement
## 1 This transaction type is not eligible for the tax exemption
## 2 This transaction type is not eligible for the tax exemption
## 3 Vehicle purchase was before August 01, 2019
## 4 This transaction type is not eligible for the tax exemption
## 5 This transaction type is not eligible for the tax exemption
## 6 Purchase date requirement is met
## X2019.HB.2042..Sale.Price.Value.Requirement
## 1 This transaction type is not eligible for the tax exemption
## 2 This transaction type is not eligible for the tax exemption
## 3 The sale price is too high
## 4 This transaction type is not eligible for the tax exemption
## 5 This transaction type is not eligible for the tax exemption
## 6 Sale price/value requirement is met
## Electric.Vehicle.Fee.Paid Transportation.Electrification.Fee.Paid
## 1 Not Applicable Not Applicable
## 2 No No
## 3 Not Applicable Not Applicable
## 4 Yes Yes
## 5 Yes Yes
## 6 Not Applicable Not Applicable
## Hybrid.Vehicle.Electrification.Fee.Paid X2020.GEOID Legislative.District
## 1 Not Applicable 53031950603 24
## 2 No 53033023201 48
## 3 Not Applicable 53033023201 48
## 4 No 53033032104 5
## 5 No 53033032104 5
## 6 Not Applicable 53033032104 5
## Electric.Utility
## 1 BONNEVILLE POWER ADMINISTRATION||PUGET SOUND ENERGY INC||PUD NO 1 OF JEFFERSON COUNTY
## 2 PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA)
## 3 PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA)
## 4 PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA)
## 5 PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA)
## 6 PUGET SOUND ENERGY INC||CITY OF TACOMA - (WA)
names(df)
## [1] "Clean.Alternative.Fuel.Vehicle.Type"
## [2] "VIN..1.10."
## [3] "DOL.Vehicle.ID"
## [4] "Model.Year"
## [5] "Make"
## [6] "Model"
## [7] "Primary.Use"
## [8] "Electric.Range"
## [9] "Odometer.Reading"
## [10] "Odometer.Reading.Description"
## [11] "New.or.Used.Vehicle"
## [12] "Sale.Price"
## [13] "Sale.Date"
## [14] "Base.MSRP"
## [15] "Transaction.Type"
## [16] "Transaction.Date"
## [17] "Year"
## [18] "County"
## [19] "City"
## [20] "State"
## [21] "Postal.Code"
## [22] "X2019.HB.2042..Clean.Alternative.Fuel.Vehicle..CAFV..Eligibility"
## [23] "Meets.2019.HB.2042.Electric.Range.Requirement"
## [24] "Meets.2019.HB.2042.Sale.Date.Requirement"
## [25] "Meets.2019.HB.2042.Sale.Price.Value.Requirement"
## [26] "X2019.HB.2042..Battery.Range.Requirement"
## [27] "X2019.HB.2042..Purchase.Date.Requirement"
## [28] "X2019.HB.2042..Sale.Price.Value.Requirement"
## [29] "Electric.Vehicle.Fee.Paid"
## [30] "Transportation.Electrification.Fee.Paid"
## [31] "Hybrid.Vehicle.Electrification.Fee.Paid"
## [32] "X2020.GEOID"
## [33] "Legislative.District"
## [34] "Electric.Utility"
To clean the dataset, we addressed issues in the ‘Sale Price’ column, where many values were zero, likely due to missing or incorrect data. Deleting these rows would have removed 80% of the dataset, so we imputed missing values using the mean sale price for each model and year. This ensured data consistency while preserving most of the dataset for reliable analysis.
# Calculate the average sale price for each model and model year (excluding sale price = 0)
mean_prices <- aggregate(Sale.Price ~ Model + Model.Year, data = subset(df, Sale.Price > 0), FUN = function(x) round(mean(x)))
# Merge the mean sale prices back into the original dataframe
df <- merge(df, mean_prices, by = c("Model", "Model.Year"), all.x = TRUE)
# Replace Sale.Price with the mean where Sale.Price is 0
df$Sale.Price <- ifelse(df$Sale.Price.x == 0, df$Sale.Price.y, df$Sale.Price.x)
# Remove the auxiliary Sale.Price columns
df <- df[, !(names(df) %in% c("Sale.Price.x", "Sale.Price.y"))]
Moreover, erroneous values in the Electric Range column, specifically entries with a value of 0, were identified and addressed. Using reliable external sources such as EPA-estimated electric range values, missing data for affected models across various years were replaced with reasonable estimates. A mapping of (Model Year, Model) to estimated ranges was created, ensuring consistency and accuracy in the dataset.
# Define estimated electric vehicle ranges
estimated_ranges <- list(
`2020_Hardtop` = 110,
`2020_Leaf` = 149,
`2021_Bolt EV` = 259,
`2021_ID.4` = 250,
`2021_Ioniq` = 170,
`2021_Kona Electric` = 258,
`2021_Leaf` = 149,
`2021_Model 3` = 263,
`2021_Model S` = 405,
`2021_Model X` = 371,
`2021_Model Y` = 326,
`2021_Mustang Mach-E` = 270,
`2021_Niro` = 239,
`2021_Taycan` = 227,
`2021_XC40` = 223,
`2021_e-tron` = 222,
`2021_e-tron Sportback` = 218,
`2021_i3` = 153,
`2022_Air` = 520,
`2022_Bolt EUV` = 247,
`2022_Bolt EV` = 259,
`2022_C40` = 226,
`2022_EDV` = 150,
`2022_EQB-Class` = 243,
`2022_EQS-Class Sedan` = 350,
`2022_EV6` = 310,
`2022_F-150` = 230,
`2022_Hardtop` = 110,
`2022_I-PACE` = 234,
`2022_ID.4` = 275,
`2022_Ioniq 5` = 303,
`2022_Kona Electric` = 258,
`2022_Leaf` = 149,
`2022_Model 3` = 272,
`2022_Model S` = 405,
`2022_Model X` = 348,
`2022_Model Y` = 318,
`2022_Mustang Mach-E` = 277,
`2022_Niro` = 253,
`2022_PS2` = 270,
`2022_Q4` = 241,
`2022_R1S` = 316,
`2022_R1T` = 314,
`2022_RS e-tron GT` = 232,
`2022_Taycan` = 238,
`2022_Transit` = 126,
`2022_XC40` = 223,
`2022_e-tron` = 222,
`2022_e-tron GT` = 232,
`2022_e-tron Sportback` = 218,
`2022_i4` = 300,
`2022_iX` = 324,
`2023_ARIYA` = 289,
`2023_Air` = 516,
`2023_Bolt EUV` = 247,
`2023_Bolt EV` = 259,
`2023_C40` = 226,
`2023_EDV` = 150,
`2023_EQB-Class` = 243,
`2023_EQE-Class SUV` = 279,
`2023_EQE-Class Sedan` = 305,
`2023_EQS-Class SUV` = 285,
`2023_EQS-Class Sedan` = 350,
`2023_EV6` = 310,
`2023_F-150` = 240,
`2023_G80` = 282,
`2023_GV60` = 248,
`2023_GV70` = 236,
`2023_Hardtop` = 110,
`2023_I-PACE` = 234,
`2023_ID.4` = 275,
`2023_Ioniq 5` = 303,
`2023_Ioniq 6` = 361,
`2023_Kona Electric` = 258,
`2023_Leaf` = 149,
`2023_Lyriq` = 312,
`2023_Model 3` = 272,
`2023_Model S` = 405,
`2023_Model X` = 348,
`2023_Model Y` = 318,
`2023_Mustang Mach-E` = 277,
`2023_Niro` = 253,
`2023_Ocean` = 360,
`2023_PS2` = 270,
`2023_Q4` = 241,
`2023_R1S` = 316,
`2023_R1T` = 314,
`2023_RS e-tron GT` = 232,
`2023_RZ` = 220,
`2023_Solterra` = 228,
`2023_Taycan` = 238,
`2023_Transit` = 126,
`2023_XC40` = 223,
`2023_bZ4X` = 222,
`2023_e-tron` = 222,
`2023_e-tron GT` = 232,
`2023_i4` = 300,
`2023_i7` = 318,
`2023_iX` = 324
)
# Function to create a unique key based on Model Year and Model
create_key <- function(year, model) {
paste(year, model, sep = "_")
}
# Update Electric Range using the estimated ranges
df$Electric.Range <- sapply(1:nrow(df), function(i) {
key <- create_key(df$Model.Year[i], df$Model[i])
if (is.na(df$Electric.Range[i]) || df$Electric.Range[i] == 0) {
if (!is.null(estimated_ranges[[key]])) {
return(estimated_ranges[[key]])
}
}
return(df$Electric.Range[i])
})
We also removed sale prices below 10,000 and above 100,000, focused on data from 2012–2023, excluded 2024 for consistency, and kept only new vehicles to analyze trends.
# Remove records with unrealistic sale prices
df <- subset(df, Sale.Price >= 10000 & Sale.Price <= 100000)
# Filter vehicles between the years 2012 and 2023
df <- subset(df, Model.Year >= 2012 & Model.Year <= 2023)
# Keep only vehicles marked as "New"
df <- subset(df, New.or.Used.Vehicle == "New")
# Save the final cleaned dataset
write.csv(df, 'updated_imputed_file.csv', row.names = FALSE)
In summary, with 330 thousand rows after cleaning, the goal was to maintain a comprehensive dataset while minimizing the impact of incorrect or missing values, resulting in a dataset that is more accurate and meaningful for further analysis.
The first analysis focuses on understanding market dynamics over time by examining vehicle counts across different brands. A line chart was used to visualize the trend of vehicle counts for each brand by model year. The results show a significant upward trajectory for Tesla compared to its competitors, especially from 2018 onward. Tesla’s growth surpasses all other brands, highlighting its market dominance in electric vehicles.
#Group data by Model Year and Make to calculate the vehicle count
vehicle_counts <- df %>%
group_by(Model.Year, Make) %>%
summarise(VehicleCount = n(), .groups = 'drop')
# 2. Get the list of all brands (Make)
brands <- unique(vehicle_counts$Make)
# 3. Plot the trends for each brands
palette <- c(
"#1F77B4", "#FF7F0E", "#2CA02C", "#D62728", "#9467BD",
"#8C564B", "#E377C2", "#7F7F7F", "#BCBD22", "#17BECF",
"#AEC7E8", "#FFBB78", "#98DF8A", "#FF9896", "#C5B0D5",
"#C49C94", "#F7B6D2", "#C7C7C7", "#DBDB8D", "#9EDAE5",
"#393B79", "#637939", "#8C6D31", "#843C39", "#7B4173",
"#5254A3", "#8CA252", "#BD9E39", "#AD494A", "#A55194",
"#6B6ECF"
)
eda_p1 <- ggplot(vehicle_counts, aes(x = Model.Year, y = VehicleCount, color = Make, group = Make)) +
geom_line(linewidth = 1, alpha = 0.8) +
geom_point(size = 2, alpha = 0.7) +
scale_color_manual(values = palette) +
labs(title = "Vehicle Count Trend by Model Year for Each Brand",
x = "Model Year",
y = "Vehicle Count",
color = "Brands") +
theme_minimal() +
theme(legend.position = "right",
legend.direction = "vertical",
legend.box = "vertical",
legend.key.size = unit(0.5, "lines"),
legend.text = element_text(size = rel(0.5)),
panel.grid.major = element_line(linewidth = 0.5, color = "grey"),
panel.grid.minor = element_line(linewidth = 0.25, color = "lightgrey"),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
legend.background = element_rect(color = "black", fill = NA),
axis.text.x = element_text(size = rel(0.8)),
axis.text.y = element_text(size = rel(0.8)),
plot.title = element_text(hjust = 0.5)) +
scale_x_continuous(breaks = seq(min(vehicle_counts$Model.Year), max(vehicle_counts$Model.Year), by = 1)) +
scale_y_continuous(breaks = seq(0, max(vehicle_counts$VehicleCount), by = 10000)) +
guides(color = guide_legend(ncol = 1))
eda_p1
A box plot was created to illustrate the sale price distribution for the top 10 vehicle models by sales volume. The analysis reveals that whileTesla’s models, such as the Model S, Model X, and Model 3, are among the top sellers, their prices are notably higher than many competitors.Interestingly, this contradicts the general assumption that lower-priced vehicles tend to dominate sales. Tesla’s ability to achieve high salesdespite premium pricing underscores its strong brand value and consumer preference for performance and innovation.
# 1. Calculate the top 10 models by sales volume
top_models <- df %>%
count(Model, sort = TRUE) %>%
head(10) %>%
pull(Model)
# 2. Filter the dataset to include only the top 10 models
filtered_df <- df %>%
filter(Model %in% top_models)
# 3. Create the boxplot for Sale Price distribution by Model
eda_p2 <- ggplot(filtered_df, aes(x = Model, y = Sale.Price)) +
geom_boxplot(outlier.shape = NA, fill = NA, color = "#1F77B4") +
theme_minimal() +
labs(title = "Sale Price by Model",
x = "Model",
y = "Sale Price") +
theme(
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
panel.grid.major = element_line(color = "NA"),
panel.grid.minor = element_line(color = "NA"),
plot.title = element_text(hjust = 0.5)
)
eda_p2
In the electric vehicle market, battery costs dominate pricing, often accounting for a significant portion of the total vehicle cost. For most brands, achieving higher ranges requires larger batteries, which significantly drives up prices. This relationship is evident from the Pearson correlation coefficient of 0.382 for non-Tesla electric vehicles, indicating a positive correlation between range and price. However, Tesla has defied this trend. For its most popular models, the Model 3 and Model Y, the correlation coefficients are -0.119 and -0.040, respectively,showing virtually no relationship between price and range. This is further reflected in Tesla’s pricing and range trends.
# Filter data for Tesla and non-Tesla vehicles
tesla_data <- df[df$Make == "TESLA",]
non_tesla_data <- df[df$Make != "TESLA",]
# Further filter Tesla data by specific models
tesla_model3 <- tesla_data[tesla_data$Model == "Model 3",]
tesla_modely <- tesla_data[tesla_data$Model == "Model Y",]
# Calculate Pearson correlation coefficients
non_tesla_corr <- cor(non_tesla_data[['Electric.Range']], non_tesla_data[['Sale.Price']])
tesla_model3_corr <- cor(tesla_model3[['Electric.Range']], tesla_model3[['Sale.Price']],)
tesla_modely_corr <- cor(tesla_modely[['Electric.Range']], tesla_modely[['Sale.Price']],)
print(paste("Non-Tesla Correlation Coefficient:", round(non_tesla_corr,3)))
## [1] "Non-Tesla Correlation Coefficient: 0.384"
print(paste("Tesla Model 3 Correlation Coefficient:", sprintf("%.3f", tesla_model3_corr)))
## [1] "Tesla Model 3 Correlation Coefficient: -0.119"
print(paste("Tesla Model Y Correlation Coefficient:", sprintf("%.3f", tesla_modely_corr)))
## [1] "Tesla Model Y Correlation Coefficient: -0.040"
This is further reflected in Tesla’s pricing and range trends. Over the years, Tesla has consistently improved the range of its vehicles—both Model 3 and Model Y now exceed 300 miles—while maintaining stable pricing. Unlike other brands, Tesla does not pass the cost of higher ranges directly to consumers, making its vehicles far more accessible.
# Filter data for Model 3 and Model Y and exclude 2024 data
t_df <- df[df$Model %in% c('Model 3', 'Model Y') & df$Year < 2024,]
# Group by year and model to calculate average electric range and sale price
average_data <- t_df %>%
group_by(Year, Model) %>%
summarise(
ElectricRange = mean(Electric.Range),
SalePrice = mean(Sale.Price),
.groups = "drop"
)
# Make plots
average_data_for_plot <- average_data %>%
group_by(Year) %>%
mutate(
ModelCount = n(),
AdjustedPosition = ifelse(ModelCount == 1,
-0.2,
ifelse(Model == "Model 3", -0.2, 0.2))
) %>%
ungroup()
sub_p1 <- ggplot(
average_data_for_plot, aes(x = as.factor(Year), y = ElectricRange, fill = Model)
) +
geom_bar(
aes(x = as.numeric(as.factor(Year)) + AdjustedPosition),
stat = "identity",
width = 0.4,
position = "identity"
) +
scale_fill_manual(values = c("Model 3" = "#3C6682", "Model Y" = "#45A778")
)+
scale_x_continuous(
breaks = 1:length(unique(average_data$Year)),
labels = unique(average_data$Year)
) +
scale_y_continuous(
breaks = seq(0,max(average_data_for_plot$ElectricRange), by = 20),
)+
coord_cartesian(
ylim = c(min(average_data_for_plot$ElectricRange)-10, max(average_data_for_plot$ElectricRange)+10)
) +
labs(
title = "Average Electric Range Over Time for Model 3 and Model Y",
y = "Average Range (miles)",
x = "Model Release Date in Years"
) +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
panel.grid.major = element_line(color = "NA"),
panel.grid.minor = element_line(color = "NA"))
sub_p2 <- ggplot(
average_data_for_plot, aes(x = as.factor(Year), y = SalePrice, fill = Model)
) +
geom_bar(
aes(x = as.numeric(as.factor(Year)) + AdjustedPosition),
stat = "identity",
width = 0.4,
position = "identity"
) +
scale_fill_manual(values = c("Model 3" = "#6AAAEA", "Model Y" = "#AA6AEA")
)+
scale_x_continuous(
breaks = 1:length(unique(average_data$Year)),
labels = unique(average_data$Year)
) +
scale_y_continuous(
breaks = seq(0,max(average_data_for_plot$SalePrice), by = 2500),
)+
coord_cartesian(
ylim = c(min(average_data_for_plot$SalePrice)-1000, max(average_data_for_plot$SalePrice)+1000)
) +
labs(
title = "Average Sale Price Over Time for Model 3 and Model Y",
y = "Average Price (in USD)",
x = "Model Release Date in Years"
) +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
panel.grid.major = element_line(color = "NA"),
panel.grid.minor = element_line(color = "NA"))
eda_p3 <- plot_grid(sub_p1, sub_p2, ncol = 1)
eda_p3
In contrast, non-Tesla models have seen sharp price increases over time as manufacturers struggle to balance rising battery costs with performance improvements. Tesla, however, has maintained stable pricing for its core models, as seen in the Model 3 and Model Y pricing trends. This ability to decouple battery costs from vehicle pricing has become one of Tesla’s most defining advantages.
nt_df <- df[df$Make != "Tesla" & df$Year < 2024,]
nt_average_df <- nt_df %>%
group_by(Year) %>%
summarise(
SalePrice = mean(Sale.Price)
)
eda_p4 <- ggplot(
nt_average_df, aes(x = Year, y = SalePrice,)
) +
geom_bar(
stat = "identity", position = "dodge", fill = "#701070"
) +
scale_x_continuous(
breaks = 1:length(unique(nt_average_df$Year)),
labels = unique(nt_average_df$Year)
) +
scale_y_continuous(
breaks = seq(0,max(nt_average_df$SalePrice)+10000, by = 10000),
) +
coord_cartesian(
ylim = c(10000,max(nt_average_df$SalePrice))
) +
labs(title = "Average Car Price Over Time for Non-Tesla Models",
y = "Average Price (in USD)",
x = "Model Release Date in Years") +
theme_minimal()+
theme(plot.title = element_text(hjust = 0.5),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
panel.grid.major = element_line(color = "NA"),
panel.grid.minor = element_line(color = "NA")
)
eda_p4
In order to analyze the differences between Tesla and other electric vehicles in terms of electric range, price, and sales volume, we utilized the K-Means clustering algorithm to categorize various EV models. The following code implements data processing and visualization to highlight the distinctions in positioning and market performance between Tesla and its competitors. This approach allows us to objectively compare Tesla’s dominance in the EV market with other manufacturers, offering insights into their respective strategies and consumer appeal.
# Exclude Tesla as a single entity and separate its models
tesla_models <- c('Model 3', 'Model Y', 'Model S', 'Model X')
df$Make_Model <- paste(df$Make, df$Model.Year, sep = " ")
df$Make_Model[df$Model %in% tesla_models] <- paste(df$Model[df$Model %in% tesla_models], df$Model.Year[df$Model %in% tesla_models], sep = " ")
# Calculate mean values per Make_Model
model_mean <- df %>%
group_by(Make_Model) %>%
summarise(
Electric_Range = mean(Electric.Range, na.rm = TRUE),
Sale_Price = mean(Sale.Price, na.rm = TRUE)
)
# Calculate sales per Make_Model
model_sales <- df %>%
count(Make_Model, name = "Sales")
# Merge the data
final_data <- merge(model_mean, model_sales, by = "Make_Model")
# Keep top 20 Make_Model by sales
top_20 <- final_data %>%
top_n(20, wt = Sales)
# Prepare data for clustering
X <- final_data %>%
select(Electric_Range, Sale_Price)
# Standardize the features before clustering
scaled_X <- scale(X)
# Apply KMeans clustering
set.seed(42)
kmeans_result <- kmeans(scaled_X, centers = 4)
final_data$Cluster <- kmeans_result$cluster
# Adjust size of the circles by scaling down further
final_data <- final_data %>%
mutate(Scaled_Sales = Sales / max(Sales) * 300) # Reduced the scaling factor
# Plot the scatter plot with clusters
ggplot(final_data, aes(x = Electric_Range, y = Sale_Price)) +
geom_point(aes(size = Scaled_Sales, color = as.factor(Cluster)), alpha = 0.7, shape = 21, stroke = 1) +
scale_size(range = c(3, 15)) + # Smaller range for circle sizes
geom_text(data = top_20, aes(label = Make_Model), size = 2, vjust = -1, alpha = 0.8) + # Reduced text size
labs(
title = "Average Sale Price vs Electric Range by Model and Year with Clusters",
x = "Average Electric Range (miles)",
y = "Average Sale Price ($)",
color = "Cluster"
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 14), # Reduced title size
axis.title = element_text(size = 12), # Reduced axis title size
axis.text = element_text(size = 10) # Reduced axis text size
)
The K-Means clustering visualization clearly highlights Tesla models
(such as the Model 3 and Model Y) as distinct in terms of their balance
between high electric range, competitive pricing, and strong sales
performance. These models are concentrated in the mid-to-high range
segment, reflecting Tesla’s dominance in this market category. In
contrast, other brands’ vehicles are more dispersed across various
clusters, showcasing a wider diversity in market positioning. This
analysis underscores Tesla’s strategic focus on creating vehicles that
resonate with both performance-oriented and cost-conscious consumers,
while competitors explore niche and broader market segments.
The Random Forest model complemented this analysis by accurately classifying vehicle types based on sale price and electric range. The Random Forest model serves as a practical tool for other manufacturers aiming to learn from Tesla’s success. By analyzing the relationship between sale price and electric range, the model offers a blueprint for optimizing vehicle offerings. Manufacturers can use the insights to adjust pricing strategies and vehicle specications, emulating Tesla’s balance of affordability and performance to enhance their market competitiveness.
if (!require(tidyverse)) install.packages("tidyverse")
## Loading required package: tidyverse
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.4 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.1
## ✔ readr 2.1.5
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ readr::col_factor() masks scales::col_factor()
## ✖ purrr::discard() masks scales::discard()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ lubridate::stamp() masks cowplot::stamp()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
if (!require(caret)) install.packages("caret")
## Loading required package: caret
## Loading required package: lattice
##
## Attaching package: 'caret'
##
## The following object is masked from 'package:purrr':
##
## lift
if (!require(randomForest)) install.packages("randomForest")
## Loading required package: randomForest
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
##
## Attaching package: 'randomForest'
##
## The following object is masked from 'package:dplyr':
##
## combine
##
## The following object is masked from 'package:ggplot2':
##
## margin
if (!require(ggplot2)) install.packages("ggplot2")
library(tidyverse)
library(caret)
library(randomForest)
library(ggplot2)
# Function to categorize models
categorize_model <- function(model) {
case_when(
model == "Model 3" ~ "Model 3",
model == "Model Y" ~ "Model Y",
model == "Model X" ~ "Model X",
model == "Model S" ~ "Model S",
TRUE ~ "Others"
)
}
# Apply categorization
df$Model_Categorized <- sapply(df$Model, categorize_model)
# Convert to factor
df$Model_Categorized <- as.factor(df$Model_Categorized)
# Prepare features and target
X <- df[, c("Sale.Price", "Electric.Range")]
y <- df$Model_Categorized
# Split the dataset
set.seed(42)
train_index <- createDataPartition(y, p = 0.8, list = FALSE)
X_train <- X[train_index, ]
X_test <- X[-train_index, ]
y_train <- y[train_index]
y_test <- y[-train_index]
# Train Random Forest model
rf_model <- randomForest(
x = X_train,
y = y_train,
ntree = 100
)
# Model Evaluation
# Make predictions
y_pred <- predict(rf_model, X_test)
# Calculate accuracy
accuracy <- confusionMatrix(y_pred, y_test)$overall["Accuracy"]
cat("Accuracy:", round(accuracy, 2), "\n")
## Accuracy: 1
# Classification report
conf_matrix <- confusionMatrix(y_pred, y_test)
print(conf_matrix)
## Confusion Matrix and Statistics
##
## Reference
## Prediction Model 3 Model S Model X Model Y Others
## Model 3 12549 0 0 0 50
## Model S 2 2661 0 0 2
## Model X 0 0 1205 0 6
## Model Y 0 0 0 14675 0
## Others 15 2 4 0 35128
##
## Overall Statistics
##
## Accuracy : 0.9988
## 95% CI : (0.9985, 0.999)
## No Information Rate : 0.5307
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9981
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Model 3 Class: Model S Class: Model X
## Sensitivity 0.9986 0.99925 0.99669
## Specificity 0.9991 0.99994 0.99991
## Pos Pred Value 0.9960 0.99850 0.99505
## Neg Pred Value 0.9997 0.99997 0.99994
## Prevalence 0.1895 0.04017 0.01824
## Detection Rate 0.1893 0.04014 0.01818
## Detection Prevalence 0.1900 0.04020 0.01827
## Balanced Accuracy 0.9989 0.99959 0.99830
## Class: Model Y Class: Others
## Sensitivity 1.0000 0.9984
## Specificity 1.0000 0.9993
## Pos Pred Value 1.0000 0.9994
## Neg Pred Value 1.0000 0.9981
## Prevalence 0.2213 0.5307
## Detection Rate 0.2213 0.5298
## Detection Prevalence 0.2213 0.5302
## Balanced Accuracy 1.0000 0.9988
# Visualize confusion matrix
confusion_plot <- as.data.frame.matrix(conf_matrix$table)
ggplot(data = as.data.frame(as.table(conf_matrix$table)),
aes(x = Prediction, y = Reference, fill = Freq)) +
geom_tile() +
geom_text(aes(label = Freq)) +
scale_fill_gradient(low = "#F0F0F0", high = "#4682B4") +
theme_minimal() +
theme(panel.background = element_rect(fill = "#F8F8F8"),
plot.background = element_rect(fill = "#F8F8F8")) +
labs(title = "Confusion Matrix")
1.The model accuracy is 99.88% (95% CI: 0.9985-0.999), the model performs very well.
2.1 Sensitivity/Specificity: Measures how accurately the model recognizes each model, e.g., Model Y achieves 100% recognition.
2.2 Prevalence: Shows the percentage distribution of each model in the dataset, e.g., Others at 53.07% and Model Y at 22.13%.
2.3 Kappa Coefficient 0.9981: It shows that the model prediction results have a very high consistency with the actual labels.
2.4 Mcnemar’s Test P-Value : NA , because the Random Forest model generates multi-category predictions instead of binary classification, this test is not applicable and this indicator can be ignored.
2.5 No Information Rate 0.5307: indicates the proportion of the largest category (Others) in the dataset, which is used to assess whether the model is superior to simple guessing.
2.6 P-Value < 2.2e-16 indicates that the model prediction is significantly better than random prediction.
3.Confusion matrix is shown: Model 3: 12,549 correct predictions with a very low misclassification rate Model Y: 14675 correct predictions, completely accurate predictions Model X: 1205 correct predictions with a few false positives Model S: 2,661 correct predictions with very few false positives. Others: 35128 correct predictions
# Feature Importance and Prediction
# Feature importance
importance <- importance(rf_model)
importance_df <- data.frame(
Feature = rownames(importance),
Importance = importance[,1]
)
# standardization
importance_df$Importance <- importance_df$Importance / sum(importance_df$Importance)
print(importance_df)
## Feature Importance
## Sale.Price Sale.Price 0.2716921
## Electric.Range Electric.Range 0.7283079
# Make prediction for new data
new_data <- data.frame(
"Sale.Price" = 50000,
"Electric.Range" = 300
)
predicted_model <- predict(rf_model, new_data)
cat("\nPredicted Model:", as.character(predicted_model))
##
## Predicted Model: Others
# Save model
saveRDS(rf_model, "model_classifier_miles.rds")
4.Feature Importance (normalized result, sum of all feature importance is 1):
Electric Range: about 0.73 (high impact); Sale Price: about 0.27 (medium impact).
5.The test sample (Sale Price: 50,000, Range: 450) was predicted in the “Others” category.
Additionally, a user-friendly prediction tool was developed to allow users to input sale price and electric range, providing immediate predictions for the most likely vehicle type.
if (!require(shiny)) install.packages("shiny")
library(shiny)
# Load Saved Model
rf_model <- readRDS("model_classifier_miles.rds")
# Using the Shiny Application
ui <- fluidPage(
titlePanel("Electric Vehicle Model Predictor"),
sidebarLayout(
sidebarPanel(
numericInput("sale_price", "Enter Sale Price ($):", value = 50000),
numericInput("electric_range", "Enter Electric Range (mile):", value = 300),
actionButton("predict", "Predict Model")
),
mainPanel(
h4("Prediction Result:"),
verbatimTextOutput("prediction")
)
)
)
server <- function(input, output) {
observeEvent(input$predict, {
new_data <- data.frame(
"Sale.Price" = input$sale_price,
"Electric.Range" = input$electric_range
)
predicted_model <- predict(rf_model, new_data)
output$prediction <- renderText({
paste("Predicted Model:", predicted_model)
})
})
}
shinyApp(ui = ui, server = server)
The application is available at Electric Vehicle Model Predictor.
This tool provides an easy-to-use interface where users can: - Input the sale price (in USD) - Input the electric range (in mile) - Get immediate predictions for the most likely EV model
A Random Forest model was developed to classify vehicles based on sale price and electric range. This model not only helps manufacturers understand the factors driving Tesla’s success but also provides actionable guidance for optimizing their own pricing and specications. Additionally, a user-friendly prediction tool was created, enabling users to input data and receive immediate predictions of the most likely vehicle type, making the ndings practical and accessible for both industry stakeholders and consumers.
The team collaborated effectively, leveraging individual skills to drive the project forward. Time management was excellent, enabling the team to complete the project on schedule. Regular review meetings allowed the team to evaluate deliverables and identify future improvement opportunities.
The raw data contained missing values and outliers, which made data cleaning more complex. Lack of domain expertise in the automotive field limited the understanding of the data’s context and meaning.
Expand the dataset to include global data to enhance the model’s generalizability. Reallocate time to provide more room for model testing and optimization, improving the quality of results.
Tesla’s leadership in the electric vehicle (EV) market is clear, thanks to its strong performance since 2018 with models like the Model Y, Model 3, and Model X. A key part of Tesla’s success is its smart pricing and range strategy. Tesla has managed to offer vehicles like the Model 3 and Model Y with over 300 miles of range, without raising prices too much. This has allowed Tesla to attract a wide range of customers by balancing high quality with affordable pricing.
Clustering analysis shows that Tesla leads the mid-range market, offering long-range cars at reasonable prices, while other brands mostly stick to budget or premium markets. A machine learning model, like Random Forest, has also shown great success in predicting the types of Tesla cars, which can help competitors improve their strategies.
Tesla’s success comes from its technology, pricing flexibility, and smart market positioning, which help it stand out in the competitive EV industry. For EV adoption to grow, policymakers should focus on improving infrastructure, advancing battery technology, and promoting affordable pricing. This research sets the stage for further studies and the use of machine learning tools to understand the EV market better, helping researchers and manufacturers improve their strategies.