library(lmtest)
## Warning: package 'lmtest' was built under R version 4.4.3
## Loading required package: zoo
## Warning: package 'zoo' was built under R version 4.4.3
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(car)
## Warning: package 'car' was built under R version 4.4.3
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.4.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:car':
##
## recode
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(purrr)
## Warning: package 'purrr' was built under R version 4.4.3
##
## Attaching package: 'purrr'
## The following object is masked from 'package:car':
##
## some
library(moments)
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.4.3
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.4.3
## corrplot 0.95 loaded
library(glmnet)
## Warning: package 'glmnet' was built under R version 4.4.3
## Loading required package: Matrix
##
## Attaching package: 'Matrix'
## The following objects are masked from 'package:tidyr':
##
## expand, pack, unpack
## Loaded glmnet 4.1-10
library(sandwich)
## Warning: package 'sandwich' was built under R version 4.4.3
library(nortest)
library(tibble)
## Warning: package 'tibble' was built under R version 4.4.3
df <- read.csv('bmw.csv')
# Tổng quan dữ liệu
str(df)
## 'data.frame': 10781 obs. of 9 variables:
## $ model : chr " 5 Series" " 6 Series" " 5 Series" " 1 Series" ...
## $ year : int 2014 2018 2016 2017 2014 2016 2017 2018 2017 2016 ...
## $ price : int 11200 27000 16000 12750 14500 14900 16000 16250 14250 14250 ...
## $ transmission: chr "Automatic" "Automatic" "Automatic" "Automatic" ...
## $ mileage : int 67068 14827 62794 26676 39554 35309 38538 10401 42668 36099 ...
## $ fuelType : chr "Diesel" "Petrol" "Diesel" "Diesel" ...
## $ tax : int 125 145 160 145 160 125 125 145 30 20 ...
## $ mpg : num 57.6 42.8 51.4 72.4 50.4 60.1 60.1 52.3 62.8 68.9 ...
## $ engineSize : num 2 2 3 1.5 3 2 2 1.5 2 2 ...
Dữ liệu có 10,781 quan trắc với 9 biến.
# Kiểm tra giá trị biến model
sapply(df[, sapply(df, is.character)], function(x) length(unique(x)))
## model transmission fuelType
## 24 3 5
Bộ dữ liệu gồm 24 mẫu xe khác nhau, đào sâu vào biến model xem ta có thể gom nhóm chúng hay không.
unique(df$model)
## [1] " 5 Series" " 6 Series" " 1 Series" " 7 Series" " 2 Series" " 4 Series"
## [7] " X3" " 3 Series" " X5" " X4" " i3" " X1"
## [13] " M4" " X2" " X6" " 8 Series" " Z4" " X7"
## [19] " M5" " i8" " M2" " M3" " M6" " Z3"
Có thể thấy có 5 dòng BMW chính ở đây là dòng Series, dòng X, dòng Z, dòng M, dòng i. với:
# Gom nhóm biến model
df <- df %>%
mutate(model_group = case_when(
grepl("Series", model) ~ "Series",
grepl("X", model) ~ "SUV (X)",
grepl("Z", model) ~ "Roadster (Z)",
grepl("i", model) ~ "Electric (i)",
grepl("M", model) ~ "Performance (M)",
TRUE ~ "Other"
))
table(df$model_group)
##
## Electric (i) Performance (M) Roadster (Z) Series SUV (X)
## 60 210 115 7945 2451
# Kiểm tra giá trị biến transmission
table(df$transmission)
##
## Automatic Manual Semi-Auto
## 3588 2527 4666
# Kiểm tra giá trị biến fuelType
table(df$fuelType)
##
## Diesel Electric Hybrid Other Petrol
## 7027 3 298 36 3417
# Kiểm tra giá trị biến model
table(df$model)
##
## 1 Series 2 Series 3 Series 4 Series 5 Series 6 Series 7 Series 8 Series
## 1969 1229 2443 995 1056 108 106 39
## i3 i8 M2 M3 M4 M5 M6 X1
## 43 17 21 27 125 29 8 804
## X2 X3 X4 X5 X6 X7 Z3 Z4
## 288 551 179 468 106 55 7 108
# Giá trị Electric của biến FuelType chỉ có 3 quan trắc nên nhóm quyết định bỏ đi
df <- df[df$fuelType != "Electric", ]
# Kiểm tra biến year
table(df$year)
##
## 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011
## 1 1 1 4 2 3 6 2 12 6 14 16 23 30 41 51
## 2012 2013 2014 2015 2016 2017 2018 2019 2020
## 119 357 501 921 1881 1720 848 3485 733
Vì biến year có ít quan trắc ở các năm cũ và cũng nhiều giá trị, nên nhóm chọn xét biến year ở dạng numeric
# Đổi kiểu dữ liệu biến định tính thành factor
df <- df %>%
mutate(across(where(is.character), as.factor))
str(df)
## 'data.frame': 10778 obs. of 10 variables:
## $ model : Factor w/ 24 levels " 1 Series"," 2 Series",..: 5 6 5 1 7 5 5 2 4 5 ...
## $ year : int 2014 2018 2016 2017 2014 2016 2017 2018 2017 2016 ...
## $ price : int 11200 27000 16000 12750 14500 14900 16000 16250 14250 14250 ...
## $ transmission: Factor w/ 3 levels "Automatic","Manual",..: 1 1 1 1 1 1 1 2 2 1 ...
## $ mileage : int 67068 14827 62794 26676 39554 35309 38538 10401 42668 36099 ...
## $ fuelType : Factor w/ 4 levels "Diesel","Hybrid",..: 1 4 1 1 1 1 1 4 1 1 ...
## $ tax : int 125 145 160 145 160 125 125 145 30 20 ...
## $ mpg : num 57.6 42.8 51.4 72.4 50.4 60.1 60.1 52.3 62.8 68.9 ...
## $ engineSize : num 2 2 3 1.5 3 2 2 1.5 2 2 ...
## $ model_group : Factor w/ 5 levels "Electric (i)",..: 4 4 4 4 4 4 4 4 4 4 ...
# Kiểm tra dữ liệu khuyết
sum(is.na(df))
## [1] 0
Không có dữ liệu khuyết
# Tổng quan phân phối các biến định lượng
numeric_vars <- c("price", "year", "mileage", "tax", "mpg", "engineSize")
summary(df[numeric_vars])
## price year mileage tax
## Min. : 1200 Min. :1996 Min. : 1 Min. : 0.0
## 1st Qu.: 14950 1st Qu.:2016 1st Qu.: 5528 1st Qu.:135.0
## Median : 20475 Median :2017 Median : 18345 Median :145.0
## Mean : 22735 Mean :2017 Mean : 25499 Mean :131.7
## 3rd Qu.: 27940 3rd Qu.:2019 3rd Qu.: 38208 3rd Qu.:145.0
## Max. :123456 Max. :2020 Max. :214000 Max. :580.0
## mpg engineSize
## Min. : 5.50 Min. :0.000
## 1st Qu.: 45.60 1st Qu.:2.000
## Median : 53.30 Median :2.000
## Mean : 56.28 Mean :2.168
## 3rd Qu.: 62.80 3rd Qu.:2.000
## Max. :470.80 Max. :6.600
Ghi nhận thấy có engineSize = 0. EngineSize thực tế chỉ = 0 khi là xe điện vì không có động cơ đốt trong.
n_total <- nrow(df)
n_issue <- sum(df$engineSize == 0 & df$fuelType != "Electric", na.rm = TRUE)
percent_issue <- n_issue / n_total * 100
data.frame(
condition = "engineSize = 0 & fuelType != Electric",
n_rows = n_issue,
percent = percent_issue
)
## condition n_rows percent
## 1 engineSize = 0 & fuelType != Electric 45 0.4175172
Các quan trắc không phù hợp này chỉ chiếm 0.4% bộ dữ liệu, nhóm chọn loại bỏ khỏi bộ dữ liệu .
df <- df %>%
filter(!(engineSize == 0 & fuelType != "Electric"))
# Kiểm tra dữ liệu trùng
sum(duplicated(df))
## [1] 117
sum(duplicated(df))/nrow(df)
## [1] 0.01090096
# Có 117 quang trắc bị trùng hoàn toàn, chiếm 1% bộ dữ liệu, nhóm chọn loại bỏ các quan trắc trùng lặp.
df <- df %>% distinct()
# Kiểm tra các giá trị ngoại lai
count_outliers_iqr <- function(x) {
q1 <- quantile(x, 0.25, na.rm = TRUE)
q3 <- quantile(x, 0.75, na.rm = TRUE)
iqr <- q3 - q1
lower <- q1 - 1.5 * iqr
upper <- q3 + 1.5 * iqr
sum(x < lower | x > upper, na.rm = TRUE)
}
# Tạo bảng kết quả
outlier_table <- tibble(variable = numeric_vars) %>%
mutate(
n_outliers = map_int(variable, ~ count_outliers_iqr(df[[.x]])),
outlier_percent = n_outliers / nrow(df) * 100
) %>%
arrange(desc(outlier_percent))
outlier_table
## # A tibble: 6 × 3
## variable n_outliers outlier_percent
## <chr> <int> <dbl>
## 1 engineSize 4108 38.7
## 2 tax 2692 25.4
## 3 price 470 4.43
## 4 mileage 292 2.75
## 5 mpg 238 2.24
## 6 year 211 1.99
# Vẽ boxplot cho các biến định lượng
par(mfrow = c(2, 3)) # chỉnh layout nếu có 6 biến
for (v in numeric_vars) {
boxplot(df[[v]],
main = paste("Boxplot of", v),
ylab = v,
col = "lightgray")
}
par(mfrow = c(1, 1)) # reset layout
# Hệ số xác định trước khi xử lý dữ liệu ngoại lai
model <- lm(price ~ . - model_group, data = df)
summary(model)$r.squared
## [1] 0.8688227
#Xử lý dữ liệu ngoại lai với phương pháp Winsorization cho những biến có % ngoại lại < 5%
handle_outliers <- function(df, column) {
Q1 <- quantile(df[[column]], 0.25, na.rm = TRUE)
Q3 <- quantile(df[[column]], 0.75, na.rm = TRUE)
IQR <- Q3- Q1
lower_bound <- Q1- 1.5 * IQR
upper_bound <- Q3 + 1.5 * IQR
df[[column]] <- ifelse(df[[column]] < lower_bound, lower_bound, df[[column]])
df[[column]] <- ifelse(df[[column]] > upper_bound, upper_bound, df[[column]])
return(df)
}
df <- handle_outliers(df, 'mileage')
df <- handle_outliers(df, 'mpg')
df <- handle_outliers(df, 'year')
#Hệ số xác định sau khi xử lý dữ liệu ngoại lại
model <- lm(price ~ . - model_group, data = df)
summary(model)$r.squared
## [1] 0.8902131
Có thể thấy, R^2 của mô hình hồi quy tuyến tính OLS có cải thiện sau khi xử lý dữ liệu ngoại lai, tăng từ 0.868 lên 0.89
par(mfrow = c(2, 3)) # chỉnh layout nếu có 6 biến
for (v in numeric_vars) {
boxplot(df[[v]],
main = paste("Boxplot of", v),
ylab = v,
col = "lightgray")
}
par(mfrow = c(1, 1)) # reset layout
summary(df)
## model year price transmission
## 3 Series:2430 Min. :2012 Min. : 1200 Automatic:3499
## 1 Series:1957 1st Qu.:2016 1st Qu.: 14889 Manual :2480
## 2 Series:1186 Median :2017 Median : 20335 Semi-Auto:4637
## 5 Series:1051 Mean :2017 Mean : 22712
## 4 Series: 986 3rd Qu.:2019 3rd Qu.: 27950
## X1 : 797 Max. :2020 Max. :123456
## (Other) :2209
## mileage fuelType tax mpg engineSize
## Min. : 1 Diesel:6979 Min. : 0.0 Min. :19.80 Min. :0.60
## 1st Qu.: 5656 Hybrid: 264 1st Qu.:135.0 1st Qu.:45.60 1st Qu.:2.00
## Median :18673 Other : 36 Median :145.0 Median :53.30 Median :2.00
## Mean :25250 Petrol:3337 Mean :131.9 Mean :53.73 Mean :2.18
## 3rd Qu.:38481 3rd Qu.:145.0 3rd Qu.:62.80 3rd Qu.:2.00
## Max. :87719 Max. :580.0 Max. :88.60 Max. :6.60
##
## model_group
## Electric (i) : 24
## Performance (M): 206
## Roadster (Z) : 114
## Series :7863
## SUV (X) :2409
##
##
# scatter plot
vars <- c("mileage", "year", "engineSize", "mpg", "tax")
for (v in vars) {
p <- ggplot(df, aes_string(x = v, y = "price")) +
geom_point(alpha = 0.4) +
geom_smooth(method = "lm", se = FALSE, color = "red") +
theme_minimal() +
labs(
title = paste("Price vs", v, "with Regression Line"),
x = v,
y = "Price"
)
print(p)
}
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
# Tương quan giữa price với các biến định tính
cat_vars <- c("model_group", "fuelType", "transmission","model")
for (v in cat_vars) {
p <- ggplot(df, aes_string(x = v, y = "price")) +
geom_boxplot(fill = "lightgreen", outlier.alpha = 0.4) +
theme_minimal() +
labs(
title = paste("Price by", v),
x = v,
y = "Price"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p)
}
# Tương quan giữa tax với các biến định tính
cat_vars <- c("model_group", "fuelType", "transmission","model")
for (v in cat_vars) {
p <- ggplot(df, aes_string(x = v, y = "tax")) +
geom_boxplot(fill = "lightgreen", outlier.alpha = 0.4) +
theme_minimal() +
labs(
title = paste("Annual road tax by", v),
x = v,
y = "Annual road tax"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p)
}
Các dòng xe điện có mức thuế hằng năm thấp hơn so với các dòng còn
lại.
# Tương quan giữa mpg với các biến định tính
cat_vars <- c("model_group", "fuelType", "transmission","model")
for (v in cat_vars) {
p <- ggplot(df, aes_string(x = v, y = "mpg")) +
geom_boxplot(fill = "lightgreen", outlier.alpha = 0.4) +
theme_minimal() +
labs(
title = paste("Fuel efficiency by", v),
x = v,
y = "Fuel efficiency"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p)
}
Các dòng xe điện có có mpg lớn hơn (đồng nghĩa với hiệu suất nhiên liệu tốt hơn) so với các dòng xe còn lại. Tuy nhiên các dòng xe điện không được đo bằng mpg và được đo bằng MPGe (Miles Per Gallon equivalent) với 1 gallon xăng ≈ 33.7 kWh điện.
# Tương quan giữa egineSize với các biến định tính
cat_vars <- c("model_group", "fuelType", "transmission","model")
for (v in cat_vars) {
p <- ggplot(df, aes_string(x = v, y = "engineSize")) +
geom_boxplot(fill = "lightgreen", outlier.alpha = 0.4) +
theme_minimal() +
labs(
title = paste("EngineSize by", v),
x = v,
y = "EngineSize"
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p)
}
Các dòng Hiệu suất cao M và SUV có enginesize cao hơn so với các dòng còn lại.Bên cạnh đó, động cơ của các xe lái tự động hoặc bán tự động cũng cao hơn động cơ xe số sàn.
#Histogram biến phụ thuộc Price
hist(df$price,
breaks = 30,
main = "Histogram of Price",
xlab = "Price",
col = "lightblue")
# Có thể thấy biến price tương đối lệch phải
skewness(df$price)
## [1] 1.590796
# Biến đổi log cho biến price
df <- df %>%
mutate(log_price = log(price))
#Histogram biến phụ thuộc Log Price
hist(df$log_price,
breaks = 30,
main = "Histogram of Log Price",
xlab = "Price",
col = "lightblue")
# Biến Price đã đỡ lệch hơn
skewness(df$log_price)
## [1] -0.2325722
# Ma trận tương quan giữa các biến
numeric_vars <- df %>%
select(where(is.numeric))
cor_matrix <- cor(numeric_vars, use = "complete.obs")
corrplot(cor_matrix,
method = "color",
type = "upper",
addCoef.col = "black",
tl.col = "black",
tl.srt = 45,
number.cex = 0.7)
Dựa vào ma trận tương quan, có thể quan sát được các cặp biến có quan hệ tuyến tính mạnh như year-mileage, mileage-price.
# Bỏ biến Price, sử dụng log_price làm biến phụ thuộc
df <- df[, !(names(df) %in% "price")]
# Hồi quy OLS với biến gốc model
model_ols <- lm(log_price ~ .-model_group, data = df)
summary(model_ols)$r.squared
## [1] 0.9173462
# Hồi quy OLS với biến model_group
model_ols <- lm(log_price ~ .-model, data = df)
summary(model_ols)$r.squared
## [1] 0.8838328
Hồi quy OLS với biến model_group cho hệ số xác định là 0.88 thấp hơn 0.91 khi hồi quy với biến gốp model. Tuy nhiên, vì sau khi phân nhóm các giá trị của biến model thành các biến model_group, mô hình sẽ dễ giải thích hơn nên nhóm chọn hồi quy với biến model_group
# Bỏ biến model, sử dụng biến model_group
df <- df[, !(names(df) %in% "model")]
# Tách bộ dữ liệu thành train và test với tỷ lệ 80-20
set.seed(1502) # để tái lập kết quả
n <- nrow(df)
train_index <- sample(seq_len(n), size = 0.8 * n)
train_df <- df[train_index, ]
test_df <- df[-train_index, ]
# Hồi quy OLS với toàn bộ các biến
model_ols <- lm(log_price ~ ., data = train_df)
summary(model_ols)
##
## Call:
## lm(formula = log_price ~ ., data = train_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.02646 -0.09403 -0.00059 0.09578 2.18909
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.168e+02 3.119e+00 -69.495 < 2e-16 ***
## year 1.129e-01 1.544e-03 73.121 < 2e-16 ***
## transmissionManual -1.360e-01 5.353e-03 -25.404 < 2e-16 ***
## transmissionSemi-Auto -8.615e-05 4.436e-03 -0.019 0.985
## mileage -5.828e-06 1.373e-07 -42.446 < 2e-16 ***
## fuelTypeHybrid 3.011e-01 1.327e-02 22.681 < 2e-16 ***
## fuelTypeOther 2.228e-01 3.491e-02 6.380 1.86e-10 ***
## fuelTypePetrol -1.397e-01 6.163e-03 -22.670 < 2e-16 ***
## tax -5.169e-04 3.860e-05 -13.390 < 2e-16 ***
## mpg -8.629e-03 3.066e-04 -28.143 < 2e-16 ***
## engineSize 2.365e-01 4.930e-03 47.974 < 2e-16 ***
## model_groupPerformance (M) -6.073e-01 4.888e-02 -12.423 < 2e-16 ***
## model_groupRoadster (Z) -8.854e-01 4.968e-02 -17.821 < 2e-16 ***
## model_groupSeries -9.169e-01 4.648e-02 -19.725 < 2e-16 ***
## model_groupSUV (X) -7.589e-01 4.673e-02 -16.241 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1674 on 8477 degrees of freedom
## Multiple R-squared: 0.8826, Adjusted R-squared: 0.8824
## F-statistic: 4553 on 14 and 8477 DF, p-value: < 2.2e-16
Hồi quy OLS với toàn bộ các cho hệ số xác định đạt được 0.88 với đa phần các biến đều có ý nghĩa thống kê, ngoại trừtransmissionSemi-Auto và fuelTypeElectric. Kiểm tra Đa cộng tuyến của các biến.
vif(model_ols)
## GVIF Df GVIF^(1/(2*Df))
## year 3.160063 1 1.777657
## transmission 1.436648 2 1.094807
## mileage 3.213909 1 1.792738
## fuelType 3.167628 3 1.211869
## tax 1.704613 1 1.305608
## mpg 4.433772 1 2.105652
## engineSize 2.088852 1 1.445286
## model_group 1.664750 4 1.065783
mpg đang có GVIF^(1/(2*Df)) 2.08, không quá đáng lo nhưng nhóm loại xem thử kết quả đạt được tốt hơn không?
model_ols <- lm(log_price ~ .-mpg, data = train_df)
summary(model_ols)
##
## Call:
## lm(formula = log_price ~ . - mpg, data = train_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.96258 -0.10742 -0.00268 0.10418 2.16099
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.234e+02 3.252e+00 -68.698 < 2e-16 ***
## year 1.159e-01 1.611e-03 71.910 < 2e-16 ***
## transmissionManual -1.397e-01 5.595e-03 -24.971 < 2e-16 ***
## transmissionSemi-Auto 6.328e-03 4.632e-03 1.366 0.172
## mileage -5.977e-06 1.435e-07 -41.665 < 2e-16 ***
## fuelTypeHybrid 1.568e-01 1.280e-02 12.245 < 2e-16 ***
## fuelTypeOther 3.093e-02 3.580e-02 0.864 0.388
## fuelTypePetrol -2.176e-02 4.724e-03 -4.606 4.16e-06 ***
## tax -1.479e-04 3.796e-05 -3.897 9.81e-05 ***
## engineSize 3.091e-01 4.394e-03 70.336 < 2e-16 ***
## model_groupPerformance (M) -5.903e-01 5.111e-02 -11.550 < 2e-16 ***
## model_groupRoadster (Z) -8.200e-01 5.189e-02 -15.803 < 2e-16 ***
## model_groupSeries -8.996e-01 4.860e-02 -18.511 < 2e-16 ***
## model_groupSUV (X) -6.888e-01 4.879e-02 -14.119 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1751 on 8478 degrees of freedom
## Multiple R-squared: 0.8716, Adjusted R-squared: 0.8714
## F-statistic: 4429 on 13 and 8478 DF, p-value: < 2.2e-16
vif(model_ols)
## GVIF Df GVIF^(1/(2*Df))
## year 3.145686 1 1.773608
## transmission 1.429126 2 1.093371
## mileage 3.209113 1 1.791400
## fuelType 1.483725 3 1.067970
## tax 1.508013 1 1.228012
## engineSize 1.517744 1 1.231968
## model_group 1.413823 4 1.044238
Sau khi loại bỏ biến mpg, nhóm thấy vẫn tồn tại 2 biến không có ý nghĩa thống kê với mức ý nghĩa 5%, nhưng hệ số xác định lại giảm, nhóm chọn giữ lại biến mpg. Nhìn vào ma trận tương quan ở trên, nhóm cũng thấy 2 biến year và milage có quan hệ tuyến tính mạnh nhên nhóm sẽ thử loại 1 trong 2 biến.
model_ols <- lm(log_price ~ .-year, data = train_df)
summary(model_ols)
##
## Call:
## lm(formula = log_price ~ . - year, data = train_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.18648 -0.12344 0.00494 0.13107 1.97061
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.128e+01 6.835e-02 164.959 < 2e-16 ***
## transmissionManual -1.804e-01 6.791e-03 -26.571 < 2e-16 ***
## transmissionSemi-Auto 2.409e-02 5.648e-03 4.265 2.02e-05 ***
## mileage -1.363e-05 1.104e-07 -123.424 < 2e-16 ***
## fuelTypeHybrid 3.625e-01 1.691e-02 21.433 < 2e-16 ***
## fuelTypeOther 3.479e-01 4.453e-02 7.814 6.21e-15 ***
## fuelTypePetrol -1.616e-01 7.860e-03 -20.561 < 2e-16 ***
## tax -7.990e-04 4.904e-05 -16.292 < 2e-16 ***
## mpg -1.014e-02 3.906e-04 -25.962 < 2e-16 ***
## engineSize 2.083e-01 6.276e-03 33.183 < 2e-16 ***
## model_groupPerformance (M) -4.781e-01 6.238e-02 -7.664 2.01e-14 ***
## model_groupRoadster (Z) -8.088e-01 6.343e-02 -12.752 < 2e-16 ***
## model_groupSeries -7.932e-01 5.932e-02 -13.373 < 2e-16 ***
## model_groupSUV (X) -6.287e-01 5.962e-02 -10.545 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2138 on 8478 degrees of freedom
## Multiple R-squared: 0.8086, Adjusted R-squared: 0.8083
## F-statistic: 2755 on 13 and 8478 DF, p-value: < 2.2e-16
model_ols <- lm(log_price ~ .-mileage, data = train_df)
summary(model_ols)
##
## Call:
## lm(formula = log_price ~ . - mileage, data = train_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.09443 -0.10432 0.00269 0.10866 2.26932
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -3.195e+02 2.165e+00 -147.563 < 2e-16 ***
## year 1.639e-01 1.071e-03 153.007 < 2e-16 ***
## transmissionManual -1.247e-01 5.886e-03 -21.180 < 2e-16 ***
## transmissionSemi-Auto 2.104e-02 4.853e-03 4.336 1.47e-05 ***
## fuelTypeHybrid 3.057e-01 1.461e-02 20.915 < 2e-16 ***
## fuelTypeOther 1.686e-01 3.842e-02 4.390 1.15e-05 ***
## fuelTypePetrol -1.214e-01 6.769e-03 -17.938 < 2e-16 ***
## tax -3.672e-04 4.232e-05 -8.675 < 2e-16 ***
## mpg -9.132e-03 3.373e-04 -27.069 < 2e-16 ***
## engineSize 2.283e-01 5.425e-03 42.090 < 2e-16 ***
## model_groupPerformance (M) -6.940e-01 5.378e-02 -12.905 < 2e-16 ***
## model_groupRoadster (Z) -9.632e-01 5.467e-02 -17.620 < 2e-16 ***
## model_groupSeries -1.007e+00 5.113e-02 -19.691 < 2e-16 ***
## model_groupSUV (X) -8.493e-01 5.140e-02 -16.525 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1843 on 8478 degrees of freedom
## Multiple R-squared: 0.8577, Adjusted R-squared: 0.8574
## F-statistic: 3930 on 13 and 8478 DF, p-value: < 2.2e-16
vif(model_ols)
## GVIF Df GVIF^(1/(2*Df))
## year 1.253148 1 1.119441
## transmission 1.418541 2 1.091341
## fuelType 3.147493 3 1.210582
## tax 1.690382 1 1.300147
## mpg 4.427156 1 2.104081
## engineSize 2.085640 1 1.444174
## model_group 1.660790 4 1.065465
sau khi loại 1 trong 2 biến, nhóm nhận thấy hệ số xác định giảm đáng kể, từ 0.88 còn 0.85 và 0.80 nên nhóm quyết định giữ lại mô hình đầy đủ.
# Dùng BIC để chọn mô hình.
mod_ols <- lm(log_price ~ ., data = train_df)
modBIC <- MASS::stepAIC(mod_ols, k = log(nrow(train_df)), trace = 0)
summary(modBIC)
##
## Call:
## lm(formula = log_price ~ year + transmission + mileage + fuelType +
## tax + mpg + engineSize + model_group, data = train_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.02646 -0.09403 -0.00059 0.09578 2.18909
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.168e+02 3.119e+00 -69.495 < 2e-16 ***
## year 1.129e-01 1.544e-03 73.121 < 2e-16 ***
## transmissionManual -1.360e-01 5.353e-03 -25.404 < 2e-16 ***
## transmissionSemi-Auto -8.615e-05 4.436e-03 -0.019 0.985
## mileage -5.828e-06 1.373e-07 -42.446 < 2e-16 ***
## fuelTypeHybrid 3.011e-01 1.327e-02 22.681 < 2e-16 ***
## fuelTypeOther 2.228e-01 3.491e-02 6.380 1.86e-10 ***
## fuelTypePetrol -1.397e-01 6.163e-03 -22.670 < 2e-16 ***
## tax -5.169e-04 3.860e-05 -13.390 < 2e-16 ***
## mpg -8.629e-03 3.066e-04 -28.143 < 2e-16 ***
## engineSize 2.365e-01 4.930e-03 47.974 < 2e-16 ***
## model_groupPerformance (M) -6.073e-01 4.888e-02 -12.423 < 2e-16 ***
## model_groupRoadster (Z) -8.854e-01 4.968e-02 -17.821 < 2e-16 ***
## model_groupSeries -9.169e-01 4.648e-02 -19.725 < 2e-16 ***
## model_groupSUV (X) -7.589e-01 4.673e-02 -16.241 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1674 on 8477 degrees of freedom
## Multiple R-squared: 0.8826, Adjusted R-squared: 0.8824
## F-statistic: 4553 on 14 and 8477 DF, p-value: < 2.2e-16
Sử dụng phương pháp stepwise chuẩn BIC cũng cho ra kết quả là mô hình đầy đủ.
# Chọn các biến định lượng và loại bỏ biến phụ thuộc
num_vars <- train_df %>%
select(where(is.numeric)) %>%
select(-log_price)
# Chuẩn hoá dữ liệu
df_PCA <- scale(num_vars, center = TRUE, scale = TRUE)
boxplot(df_PCA)
# Phân tích thành phần chính
res <- princomp(df_PCA, cor = FALSE)
summary(res, loadings = T)
## Importance of components:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## Standard deviation 1.5059035 1.2737670 0.7541976 0.60110674 0.42313132
## Proportion of Variance 0.4536025 0.3245347 0.1137762 0.07227437 0.03581224
## Cumulative Proportion 0.4536025 0.7781372 0.8919134 0.96418776 1.00000000
##
## Loadings:
## Comp.1 Comp.2 Comp.3 Comp.4 Comp.5
## year 0.401 0.573 0.157 0.693
## mileage -0.441 -0.535 0.716
## tax 0.474 -0.336 -0.576 0.571
## mpg -0.534 0.265 0.177 0.782
## engineSize 0.367 -0.450 0.782 0.224
eig_vals <- res$sdev^2
df_scree <- data.frame(
PC = seq_along(eig_vals),
Eigenvalue = eig_vals
)
ggplot(df_scree, aes(x = PC, y = Eigenvalue)) +
geom_point() +
geom_line() +
theme_minimal() +
labs(
title = "Scree Plot (Elbow Method)",
x = "Principal Component",
y = "Eigenvalue"
)
Kết quả PCA cho thấy thành phần chính thứ nhất (PC1) giải thích 45,38% phương sai dữ liệu và PC2 giải thích thêm 32,38%, nâng tổng phương sai tích luỹ lên 77,81%; khi bổ sung PC3,PC4 tổng phương sai được giải thích đạt khoảng 96.4%. Thành phần chính thứ 5 đóng góp rất ít vào việc giải thích phương sai dữ liệu nên nhóm chọn giữ lại 4 thành phần chính đầu tiên.
# Hồi quy trên các thành phần chính
train_pca <- as.data.frame(res$scores)
train_pca$log_price <- train_df$log_price
train_pca$model_group <- train_df$model_group
train_pca$fuelType <- train_df$fuelType
train_pca$transmission <- train_df$transmission
pcr_model <- lm(log_price ~ Comp.1 + Comp.2 + Comp.3 + Comp.4
+ model_group + fuelType + transmission,
data = train_pca)
summary(pcr_model)
##
## Call:
## lm(formula = log_price ~ Comp.1 + Comp.2 + Comp.3 + Comp.4 +
## model_group + fuelType + transmission, data = train_pca)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.02817 -0.09642 -0.00056 0.09834 2.15045
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 10.830906 0.047061 230.144 < 2e-16 ***
## Comp.1 0.244128 0.001770 137.889 < 2e-16 ***
## Comp.2 0.134872 0.001545 87.287 < 2e-16 ***
## Comp.3 0.138979 0.002916 47.653 < 2e-16 ***
## Comp.4 -0.046525 0.004017 -11.583 < 2e-16 ***
## model_groupPerformance (M) -0.580626 0.049422 -11.748 < 2e-16 ***
## model_groupRoadster (Z) -0.863281 0.050241 -17.183 < 2e-16 ***
## model_groupSeries -0.889286 0.046989 -18.925 < 2e-16 ***
## model_groupSUV (X) -0.729263 0.047228 -15.441 < 2e-16 ***
## fuelTypeHybrid 0.303459 0.013428 22.599 < 2e-16 ***
## fuelTypeOther 0.240870 0.035301 6.823 9.51e-12 ***
## fuelTypePetrol -0.142055 0.006233 -22.791 < 2e-16 ***
## transmissionManual -0.142316 0.005397 -26.371 < 2e-16 ***
## transmissionSemi-Auto -0.001338 0.004487 -0.298 0.766
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1694 on 8478 degrees of freedom
## Multiple R-squared: 0.8798, Adjusted R-squared: 0.8796
## F-statistic: 4774 on 13 and 8478 DF, p-value: < 2.2e-16
# Ma trận thiết kế (dummy hóa factor)
x_train <- model.matrix(
log_price ~ .,
data = train_df
)[, -1] # bỏ intercept
y_train <- train_df$log_price
# Hồi quy Ridge
set.seed(1502)
cv_ridge <- cv.glmnet(
x_train,
y_train,
alpha = 0 # Ridge
)
plot(cv_ridge)
# Lambda tối ưu
cv_ridge$lambda.min
## [1] 0.03795819
cv_ridge$lambda.1se
## [1] 0.07280041
# Fit model với lambda tối ưu
model_ridge <- glmnet(
x_train,
y_train,
alpha = 0,
lambda = cv_ridge$lambda.min
)
coef(model_ridge)
## 15 x 1 sparse Matrix of class "dgCMatrix"
## s0
## (Intercept) -1.947244e+02
## year 1.015597e-01
## transmissionManual -1.415035e-01
## transmissionSemi-Auto 1.323016e-02
## mileage -6.075703e-06
## fuelTypeHybrid 2.963869e-01
## fuelTypeOther 2.591024e-01
## fuelTypePetrol -1.070170e-01
## tax -3.305090e-04
## mpg -6.831552e-03
## engineSize 2.215935e-01
## model_groupPerformance (M) 1.820550e-01
## model_groupRoadster (Z) -9.667674e-02
## model_groupSeries -1.320980e-01
## model_groupSUV (X) 3.978248e-02
# Hồi quy Lasso
set.seed(123)
cv_lasso <- cv.glmnet(
x_train,
y_train,
alpha = 1 # Lasso
)
plot(cv_lasso)
-log(cv_lasso$lambda.min)
## [1] 9.434755
-log(cv_lasso$lambda.1se)
## [1] 5.620372
model_lasso <- glmnet(
x_train,
y_train,
alpha = 1,
lambda = cv_lasso$lambda.1se
)
coef(model_lasso)
## 15 x 1 sparse Matrix of class "dgCMatrix"
## s0
## (Intercept) -2.171763e+02
## year 1.126790e-01
## transmissionManual -1.354343e-01
## transmissionSemi-Auto .
## mileage -5.749504e-06
## fuelTypeHybrid 2.869734e-01
## fuelTypeOther 2.014039e-01
## fuelTypePetrol -1.073908e-01
## tax -3.197133e-04
## mpg -6.577560e-03
## engineSize 2.409311e-01
## model_groupPerformance (M) 1.167760e-01
## model_groupRoadster (Z) -1.008612e-01
## model_groupSeries -1.692307e-01
## model_groupSUV (X) .
Lasso loại được 2 biến khỏi mô hình là biến model_SUV và biến động cơ bán tự động.
set.seed(1502)
cv_enet <- cv.glmnet(
x_train,
y_train,
alpha = 0.4 # Elastic-Net
)
plot(cv_enet)
model_enet <- glmnet(
x_train,
y_train,
alpha = 1,
lambda = cv_enet$lambda.1se
)
coef(model_enet)
## 15 x 1 sparse Matrix of class "dgCMatrix"
## s0
## (Intercept) -2.195170e+02
## year 1.137307e-01
## transmissionManual -1.328526e-01
## transmissionSemi-Auto .
## mileage -5.500037e-06
## fuelTypeHybrid 2.121249e-01
## fuelTypeOther 4.156418e-02
## fuelTypePetrol -6.354587e-02
## tax -4.110579e-05
## mpg -3.853825e-03
## engineSize 2.509637e-01
## model_groupPerformance (M) 6.759572e-02
## model_groupRoadster (Z) -5.388218e-02
## model_groupSeries -1.740446e-01
## model_groupSUV (X) .
# So sánh các model
eval_metrics <- function(y_true, y_pred) {
mse <- mean((y_true - y_pred)^2)
rmse <- sqrt(mse)
r2 <- 1 - sum((y_true - y_pred)^2) /
sum((y_true - mean(y_true))^2)
c(R2 = r2, RMSE = rmse, MSE = mse)
}
# ols
pred_ols <- predict(modBIC, newdata = test_df)
ols_metrics <- eval_metrics(test_df$log_price, pred_ols)
ols_metrics
## R2 RMSE MSE
## 0.88861446 0.15651122 0.02449576
x_test <- model.matrix(
log_price ~ .,
data = test_df
)[, -1]
y_test <- test_df$log_price
# Ridge
pred_ridge <- predict(
cv_ridge,
s = "lambda.min",
newx = x_test
)
ridge_metrics <- eval_metrics(test_df$log_price, pred_ridge)
ridge_metrics
## R2 RMSE MSE
## 0.87982747 0.16256748 0.02642818
# Lasso
pred_lasso <- predict(
cv_lasso,
s = "lambda.1se",
newx = x_test
)
lasso_metrics <- eval_metrics(test_df$log_price, pred_lasso)
lasso_metrics
## R2 RMSE MSE
## 0.8811265 0.1616864 0.0261425
# Elastic-Net
pred_enet <- predict(
cv_enet,
s = "lambda.1se",
newx = x_test
)
enet_metrics <- eval_metrics(test_df$log_price, pred_enet)
enet_metrics
## R2 RMSE MSE
## 0.88106886 0.16172563 0.02615518
# PCR
test_scaled <- scale(
test_df[, colnames(num_vars)], # đúng thứ tự biến numeric
center = attr(df_PCA, "scaled:center"),
scale = attr(df_PCA, "scaled:scale")
)
test_scores <- predict(res, newdata = test_scaled)
test_pca <- as.data.frame(test_scores)
test_pca$model_group <- test_df$model_group
test_pca$fuelType <- test_df$fuelType
test_pca$transmission <- test_df$transmission
pred_pca <- predict(pcr_model, newdata = test_pca)
pca_metrics <- eval_metrics(test_df$log_price, pred_pca)
pca_metrics
## R2 RMSE MSE
## 0.88590714 0.15840186 0.02509115
metrics_table <- rbind(
OLS = round(ols_metrics,4),
Ridge = round(ridge_metrics,4),
Lasso = round(lasso_metrics,4),
Elastic_Net = round(enet_metrics,4),
PCA = round(pca_metrics,4)
)
metrics_table
## R2 RMSE MSE
## OLS 0.8886 0.1565 0.0245
## Ridge 0.8798 0.1626 0.0264
## Lasso 0.8811 0.1617 0.0261
## Elastic_Net 0.8811 0.1617 0.0262
## PCA 0.8859 0.1584 0.0251
Dựa vào kết quả test ta có thể thấy, model hồi quy ols đang thể hiện tốt nhất. Tuy Lasso có loại được 2 biến so với các mô hình còn lại, nhưng nhóm vẫn chọn mô hình OLS với số biến nhìn chung không đáng kể.
# Kiểm tra các điểm ảnh hưởng mạnh
plot(modBIC,4)
Có thể thấy có các điểm ảnh hưởng mạnh như quan trắc 9116, 9922, 10161
# Loại bỏ các điểm ảnh hưởng mạnh
cooks_d <- cooks.distance(modBIC)
n <- nrow(train_df)
threshold <- 4 / n
influential_points <- which(cooks_d > threshold)
train_df_clean <- train_df[-influential_points, ]
# Chạy lại model ols với dữ liệu đã loại bỏ các điểm ảnh hưởng mạnh
model_ols_clean <- lm(log_price ~., data = train_df_clean)
summary(model_ols_clean)
##
## Call:
## lm(formula = log_price ~ ., data = train_df_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.43415 -0.08435 -0.00051 0.08502 0.54796
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.054e+02 2.530e+00 -81.169 < 2e-16 ***
## year 1.075e-01 1.251e-03 85.876 < 2e-16 ***
## transmissionManual -1.220e-01 4.278e-03 -28.530 < 2e-16 ***
## transmissionSemi-Auto 7.872e-03 3.530e-03 2.230 0.0258 *
## mileage -5.141e-06 1.106e-07 -46.467 < 2e-16 ***
## fuelTypeHybrid 3.974e-01 1.361e-02 29.203 < 2e-16 ***
## fuelTypeOther 3.126e-01 4.991e-02 6.263 3.96e-10 ***
## fuelTypePetrol -1.959e-01 5.300e-03 -36.958 < 2e-16 ***
## tax -3.132e-04 3.387e-05 -9.249 < 2e-16 ***
## mpg -1.263e-02 2.784e-04 -45.380 < 2e-16 ***
## engineSize 1.848e-01 4.230e-03 43.685 < 2e-16 ***
## model_groupPerformance (M) -6.844e-01 9.418e-02 -7.267 4.03e-13 ***
## model_groupRoadster (Z) -9.300e-01 9.476e-02 -9.814 < 2e-16 ***
## model_groupSeries -9.711e-01 9.317e-02 -10.423 < 2e-16 ***
## model_groupSUV (X) -8.530e-01 9.324e-02 -9.148 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1306 on 8099 degrees of freedom
## Multiple R-squared: 0.9148, Adjusted R-squared: 0.9146
## F-statistic: 6207 on 14 and 8099 DF, p-value: < 2.2e-16
Sau khi loại bỏ các điểm ảnh hưởng, hệ số xác định đã tăng từ 0.88 lên .091
# Kiểm định phân phối chuẩn của sai số
qqnorm(residuals(model_ols_clean))
qqline(residuals(model_ols_clean), col = "red")
Các quan trắc đa phần đều nằm trên đường lý thuyết
# Do dữ liệu > 5000 dòng nên không dùng Shapiro được, dùng Kolmogorov–Smirnov hiệu chỉnh thay thế
lillie.test(residuals(model_ols_clean))
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: residuals(model_ols_clean)
## D = 0.01308, p-value = 0.003194
Phần dư có phân phối chuẩn với độ tin cậy 0.001
# Kiểm định phương sai đồng nhất
bptest(model_ols_clean)
##
## studentized Breusch-Pagan test
##
## data: model_ols_clean
## BP = 405.09, df = 14, p-value < 2.2e-16
plot(model_ols_clean,1)
# Biến đổi box-cox để xem các kiểm định có được cải thiện không
L <- MASS::boxcox(model_ols_clean)
optimal_lambda_idx <-which.max(L$y)
optimal_lambda <-L$x[optimal_lambda_idx]
optimal_lambda
## [1] -0.1818182
train_df_clean$Y_boxcox<-(train_df_clean$log_price^optimal_lambda-1)/optimal_lambda
new_modBIC<-lm(Y_boxcox ~ . - log_price, data = train_df_clean)
summary(new_modBIC)
##
## Call:
## lm(formula = Y_boxcox ~ . - log_price, data = train_df_clean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.035011 -0.005464 0.000082 0.005646 0.034308
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.249e+01 1.671e-01 -74.712 < 2e-16 ***
## year 7.163e-03 8.265e-05 86.667 < 2e-16 ***
## transmissionManual -8.806e-03 2.826e-04 -31.163 < 2e-16 ***
## transmissionSemi-Auto 4.146e-04 2.332e-04 1.778 0.0754 .
## mileage -3.517e-07 7.309e-09 -48.124 < 2e-16 ***
## fuelTypeHybrid 2.535e-02 8.990e-04 28.201 < 2e-16 ***
## fuelTypeOther 2.014e-02 3.297e-03 6.109 1.05e-09 ***
## fuelTypePetrol -1.234e-02 3.501e-04 -35.262 < 2e-16 ***
## tax -1.267e-05 2.237e-06 -5.664 1.53e-08 ***
## mpg -7.775e-04 1.839e-05 -42.277 < 2e-16 ***
## engineSize 1.215e-02 2.794e-04 43.463 < 2e-16 ***
## model_groupPerformance (M) -4.129e-02 6.221e-03 -6.638 3.40e-11 ***
## model_groupRoadster (Z) -5.623e-02 6.260e-03 -8.984 < 2e-16 ***
## model_groupSeries -5.881e-02 6.154e-03 -9.557 < 2e-16 ***
## model_groupSUV (X) -5.108e-02 6.159e-03 -8.294 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.008628 on 8099 degrees of freedom
## Multiple R-squared: 0.9161, Adjusted R-squared: 0.916
## F-statistic: 6318 on 14 and 8099 DF, p-value: < 2.2e-16
bptest(new_modBIC)
##
## studentized Breusch-Pagan test
##
## data: new_modBIC
## BP = 372.28, df = 14, p-value < 2.2e-16
plot(new_modBIC,1)
Biến đổi box cox vẫn không cải thiện được phương sai đồng nhất
# Kiểm định tính chuẩn sau khi biến đổi box-cox. Phần dư không còn tính chuẩn với độ tin cậy 0.0001.
lillie.test(residuals(new_modBIC))
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: residuals(new_modBIC)
## D = 0.015872, p-value = 8.736e-05
Do không cải thiện được phương sai đồng nhất và phân dư không còn phân phối chuẩn với độ tin cậy 1/1000 nên nhóm chọn mô hình không có biến đổi box-cox
# Kiểm định tính độc lập của phần dư Durbin-Watson
dwtest(model_ols_clean)
##
## Durbin-Watson test
##
## data: model_ols_clean
## DW = 2.0013, p-value = 0.5231
## alternative hypothesis: true autocorrelation is greater than 0
pred_log_price <- predict(model_ols_clean, newdata = test_df)
pred_price <- exp(pred_log_price)
actual_price <- exp(test_df$log_price)
df_plot <- data.frame(
Actual_Price = actual_price,
Predicted_Price = pred_price
)
ggplot(df_plot, aes(x = Actual_Price, y = Predicted_Price)) +
geom_point(alpha = 0.4, color = "steelblue") +
geom_abline(slope = 1, intercept = 0,
linetype = "dashed", color = "red") +
theme_minimal() +
labs(
title = "Actual vs Predicted Price (OLS Clean Model)",
x = "Actual Price",
y = "Predicted Price"
)
Đề xuất sử dụng Roburst Standard Error hiệu chỉnh sai số chuẩn trong trường hợp phương sai sai số không đồng nhất. Việc này không làm thay đổi các hệ số ước lượng OLS, nhưng giúp các thống kê kiểm định (t-statistic, p-value và khoảng tin cậy) trở nên đáng tin cậy hơn.
coeftest(model_ols_clean, vcov = vcovHC(model_ols_clean, type = "HC1"))
##
## t test of coefficients:
##
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.0536e+02 2.4925e+00 -82.3918 < 2e-16 ***
## year 1.0745e-01 1.2333e-03 87.1242 < 2e-16 ***
## transmissionManual -1.2205e-01 4.1982e-03 -29.0715 < 2e-16 ***
## transmissionSemi-Auto 7.8715e-03 3.6048e-03 2.1836 0.02902 *
## mileage -5.1413e-06 1.0364e-07 -49.6091 < 2e-16 ***
## fuelTypeHybrid 3.9745e-01 1.2061e-02 32.9526 < 2e-16 ***
## fuelTypeOther 3.1260e-01 1.6942e-02 18.4509 < 2e-16 ***
## fuelTypePetrol -1.9587e-01 5.9859e-03 -32.7217 < 2e-16 ***
## tax -3.1324e-04 3.0918e-05 -10.1313 < 2e-16 ***
## mpg -1.2634e-02 3.1595e-04 -39.9881 < 2e-16 ***
## engineSize 1.8480e-01 4.7555e-03 38.8605 < 2e-16 ***
## model_groupPerformance (M) -6.8439e-01 1.3792e-02 -49.6217 < 2e-16 ***
## model_groupRoadster (Z) -9.3001e-01 1.3225e-02 -70.3240 < 2e-16 ***
## model_groupSeries -9.7111e-01 9.9466e-03 -97.6323 < 2e-16 ***
## model_groupSUV (X) -8.5305e-01 1.0604e-02 -80.4448 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1