BÁO CÁO TIỂU LUẬN
NGÔN NGỮ LẬP TRÌNH TRONG PHÂN TÍCH DỮ LIỆU

Nhóm : 28
Thành viên thực hiện : Võ Thị Kiều My
: Trần Huỳnh Ni Ka
Mã lớp học phần : 2531101140001



Phần 1: Giới thiệu và kiểm tra dữ liệu

Bộ dữ liệu Vehicle Sales Data là một bộ dữ liệu công khai trên nền tảng Kaggle, được thu thập nhằm phục vụ cho các bài toán phân tích và dự đoán giá xe đã qua sử dụng. Dữ liệu bao gồm thông tin về hãng xe, năm sản xuất, số km đã đi, tình trạng xe và giá bán, giúp đánh giá các yếu tố ảnh hưởng đến giá trị của xe trên thị trường. # Dữ liệu

# Nạp các thư viện cần thiết
library(readr)     # Đọc file CSV
library(dplyr)     # Xử lý dữ liệu
library(kableExtra)
# Đọc dữ liệu
data <- read_csv("C:/data/data.csv")
# Số lượng biến 
cat("Số lượng biến (cột):", ncol(data), "\n")
## Số lượng biến (cột): 16
# Số lượng quan quan sát
cat("Số lượng quan sát (hàng):", nrow(data), "\n")
## Số lượng quan sát (hàng): 558837
# số giá trị bị thiếu
total_NA <- sum(is.na(data))
NA_by_column <- sapply(data, function(x) sum(is.na(x)))
cat("Tổng số giá trị NA:", total_NA, "\n\n")
## Tổng số giá trị NA: 123376
NA_table <- tibble::enframe(NA_by_column, name = "variable", value = "n_missing") %>%
arrange(desc(n_missing))

kable(NA_table, caption = "Số giá trị thiếu (NA) theo biến") %>% kable_styling(full_width = FALSE)
Số giá trị thiếu (NA) theo biến
variable n_missing
transmission 65352
body 13195
condition 11820
trim 10651
model 10399
make 10301
color 749
interior 749
odometer 94
mmr 38
sellingprice 12
saledate 12
vin 4
year 0
state 0
seller 0
data <- data %>%
  filter_all(all_vars(!is.na(.))) %>%   # loại bỏ NA
  filter_all(all_vars(!is.infinite(.))) # loại bỏ Inf
n_dup_rows <- sum(duplicated(data))
cat("\nSố dòng trùng lặp:", n_dup_rows, "\n")
## 
## Số dòng trùng lặp: 0
if (n_dup_rows > 0) {
cat("Ví dụ vài dòng trùng lặp:\n")
print(head(data[duplicated(data) | duplicated(data, fromLast = TRUE), ], 6))
} else {
cat("Không tìm thấy dòng trùng lặp (theo toàn bộ hàng).\n")
}
## Không tìm thấy dòng trùng lặp (theo toàn bộ hàng).

Kiểm tra tên biến có ký tự đặc biệt

orig_names <- names(data)

# Phát hiện tên có ký tự ngoài chữ/ số / underscore

bad_names <- orig_names[grepl("[^A-Za-z0-9_]", orig_names)]
cat("\nTên biến ban đầu:\n"); print(orig_names)
## 
## Tên biến ban đầu:
##  [1] "year"         "make"         "model"        "trim"         "body"        
##  [6] "transmission" "vin"          "state"        "condition"    "odometer"    
## [11] "color"        "interior"     "seller"       "mmr"          "sellingprice"
## [16] "saledate"
if (length(bad_names) > 0) {
cat("\nCác tên chứa ký tự đặc biệt hoặc khoảng trắng:\n"); print(bad_names)
} else {
cat("\nKhông phát hiện ký tự đặc biệt trong tên biến.\n")
}
## 
## Không phát hiện ký tự đặc biệt trong tên biến.

Mô tả các biến

variable_meaning <- data.frame(
  Variable = c("year", "make", "model", "trim", "body", "transmission", "vin", "state",
               "condition", "odometer", "color", "interior", "seller", 
               "mmr", "sellingprice", "saledate"),
  Meaning = c(
    "Năm sản xuất của xe",
    "Hãng sản xuất ",
    "Tên dòng xe cụ thể",
    "Phiên bản hoặc cấp độ trang bị của xe",
    "Kiểu dáng xe ",
    "Loại hộp số ",
    "Số khung xe ",
    "Bang hoặc khu vực đăng ký",
    "Tình trạng của xe",
    "Số km xe đã đi",
    "Màu sơn bên ngoài",
    "Màu nội thất bên trong",
    "Tên người bán hoặc đại lý",
    "Giá trị thị trường trung bình (MMR)",
    "Giá bán thực tế (USD)",
    "Ngày bán xe"
  ),
  stringsAsFactors = FALSE
)

#  Bảng kiểu dữ liệu
data_types <- data.frame(
  Variable = names(data),
  DataType = sapply(data, class),
  stringsAsFactors = FALSE
)

#  Gộp 2 bảng
variable_summary <- left_join(variable_meaning, data_types, by = "Variable")

# Hiển thị bảng
kable(variable_summary, caption = "Bảng: Mô tả và kiểu dữ liệu của các biến trong bộ dữ liệu")
Bảng: Mô tả và kiểu dữ liệu của các biến trong bộ dữ liệu
Variable Meaning DataType
year Năm sản xuất của xe numeric
make Hãng sản xuất character
model Tên dòng xe cụ thể character
trim Phiên bản hoặc cấp độ trang bị của xe character
body Kiểu dáng xe character
transmission Loại hộp số character
vin Số khung xe character
state Bang hoặc khu vực đăng ký character
condition Tình trạng của xe numeric
odometer Số km xe đã đi numeric
color Màu sơn bên ngoài character
interior Màu nội thất bên trong character
seller Tên người bán hoặc đại lý character
mmr Giá trị thị trường trung bình (MMR) numeric
sellingprice Giá bán thực tế (USD) numeric
saledate Ngày bán xe character

Bộ dữ liệu gồm 16 biến, bao quát thông tin từ năm sản xuất, hãng xe, dòng xe, kiểu dáng, tình trạng, số km đã đi, đến giá bán thực tế.

Trong đó:

  • Biến định lượng (numeric): year, condition, odometer, mmr, sellingprice.

  • Biến định tính (character): chiếm đa số, mô tả đặc điểm chi tiết của xe như make, model, color, interior, seller, …

➡️ Bộ dữ liệu kết hợp giữa dữ liệu định tính (mô tả đặc trưng xe) và dữ liệu định lượng (phục vụ cho phân tích giá bán).

Thống kế mô tả các biến định lượng

# Chọn các biến định lượng 
data_numeric <- data %>%
  select(condition, odometer, mmr, sellingprice)

# Tính các thống kê mô tả cơ bản
descriptive_stats <- data_numeric %>%
  summarise(
    `Số quan sát hợp lệ` = n(),
    `Giá trị thiếu (NA)` = sum(is.na(condition)) + sum(is.na(odometer)) +
                           sum(is.na(mmr)) + sum(is.na(sellingprice)),
    .groups = "drop"
  )

# Tạo bảng mô tả từng biến
descriptive_table <- data_numeric %>%
  summarise(
    `Giá trị nhỏ nhất` = sapply(., min, na.rm = TRUE),
    `Q1 (25%)` = sapply(., quantile, probs = 0.25, na.rm = TRUE),
    `Trung vị (50%)` = sapply(., median, na.rm = TRUE),
    `Trung bình` = sapply(., mean, na.rm = TRUE),
    `Q3 (75%)` = sapply(., quantile, probs = 0.75, na.rm = TRUE),
    `Giá trị lớn nhất` = sapply(., max, na.rm = TRUE),
    `Số giá trị thiếu` = sapply(., function(x) sum(is.na(x)))
  ) %>%
  t() %>%
  as.data.frame()

# Gắn tên cột
colnames(descriptive_table) <- c("condition", "odometer", "mmr", "sellingprice")

# Hiển thị bảng
kable(
  descriptive_table,
  caption = "Bảng: Thống kê mô tả các biến định lượng"
)
Bảng: Thống kê mô tả các biến định lượng
condition odometer mmr sellingprice
Giá trị nhỏ nhất 1.00000 1.00 25.00 1.00
Q1 (25%) 24.00000 28137.00 7425.00 7200.00
Trung vị (50%) 35.00000 51085.00 12300.00 12200.00
Trung bình 30.77418 66701.73 13837.06 13690.51
Q3 (75%) 41.00000 96590.00 18300.00 18200.00
Giá trị lớn nhất 49.00000 999999.00 182000.00 230000.00
Số giá trị thiếu 0.00000 0.00 0.00 0.00

Phần 2: Phân tổ dữ liệu

Phân tổ dữ liệu theo năm

data <- data %>%
mutate(
Nhom_nam = case_when(
year < 2000 ~ "Trước năm 2000",
year >= 2000 & year <= 2010 ~ "2000 - 2010",
year > 2010 ~ "Sau 2010"
)
)

tính giá trung bình theo nhóm năm

data %>%
group_by(Nhom_nam) %>%
summarise(
So_luong_xe = n(),
Gia_ban_tb = mean(sellingprice, na.rm = TRUE)
)
## # A tibble: 3 × 3
##   Nhom_nam       So_luong_xe Gia_ban_tb
##   <chr>                <int>      <dbl>
## 1 2000 - 2010         172016      7331.
## 2 Sau 2010            293937     17682.
## 3 Trước năm 2000        6372      1229.

Phân tổ theo hãng xe

Bảng thể hiện Top 10 hãng xe có số lượng giao dịch nhiều nhất

bang_phan_to <- data %>%
  group_by(make) %>%
  summarise(
    So_luong_xe = n(),
    Gia_trung_binh = mean(sellingprice, na.rm = TRUE),
    Gia_thap_nhat = min(sellingprice, na.rm = TRUE),
    Gia_cao_nhat = max(sellingprice, na.rm = TRUE)
  ) %>%
  arrange(desc(So_luong_xe)) %>%
  head(10) 
bang_phan_to
## # A tibble: 10 × 5
##    make      So_luong_xe Gia_trung_binh Gia_thap_nhat Gia_cao_nhat
##    <chr>           <int>          <dbl>         <dbl>        <dbl>
##  1 Ford            81013         14830.             1       230000
##  2 Chevrolet       54150         11866.           100        84500
##  3 Nissan          44043         11745.           100        86400
##  4 Toyota          35313         12422.           150        68900
##  5 Dodge           27181         10964.           100        51700
##  6 Honda           24781         10943.           200        37000
##  7 Hyundai         18659         11062.           100        55000
##  8 BMW             17509         21290.           100       165000
##  9 Kia             15828         11768.           200        42750
## 10 Chrysler        15133         10627.           100        41000
  • Hãng Ford có số lượng xe lớn nhất (93.554 chiếc), chiếm tỷ trọng cao nhất trong toàn bộ dữ liệu.

  • Các hãng Chevrolet, Nissan, Toyota cũng có lượng xe giao dịch lớn, dao động từ 39.000–60.000 xe.

  • Mức giá trung bình giữa các hãng có sự chênh lệch đáng kể:

    • BMW có giá trung bình cao nhất (≈ 21.441 USD), phản ánh đặc trưng xe hạng sang.
    • Các hãng như Honda, Hyundai, Kia có giá trung bình thấp hơn, khoảng 10.000–12.000 USD.
  • Giá cao nhất trong dữ liệu lên tới 230.000 USD (Ford) — có thể là các dòng xe đặc biệt hoặc xe mới cao cấp.

➡️ Nhìn chung, thị trường xe có sự đa dạng lớn về giá và thương hiệu, thể hiện rõ xu hướng phổ biến của các hãng tầm trung.

Phân tổ số kilomet đã đi

data_phan_to_km <- data %>%
mutate(
Nhom_km = cut(
odometer,
breaks = c(-Inf, 10000, 50000, 100000, 200000, Inf),
labels = c("< 10.000 km", "10.000–50.000 km", "50.000–100.000 km", "100.000–200.000 km", "> 200.000 km")
)
) %>%
group_by(Nhom_km) %>%
summarise(
So_luong_xe = n(),
Gia_trung_binh = round(mean(sellingprice, na.rm = TRUE), 2),
Gia_thap_nhat = min(sellingprice, na.rm = TRUE),
Gia_cao_nhat = max(sellingprice, na.rm = TRUE)
) %>%
arrange(Nhom_km)
kable(data_phan_to_km, caption = "Bảng phân tổ số km đã đi và giá bán trung bình")
Bảng phân tổ số km đã đi và giá bán trung bình
Nhom_km So_luong_xe Gia_trung_binh Gia_thap_nhat Gia_cao_nhat
< 10.000 km 22072 22799.91 1 173000
10.000–50.000 km 210362 18428.14 1 230000
50.000–100.000 km 129592 11718.66 100 108200
100.000–200.000 km 101465 5368.72 100 43000
> 200.000 km 8834 2622.74 100 26800

Nhận xét:

  • Nhìn chung, quãng đường xe đã đi (odometer)mối quan hệ nghịch với giá bán trung bình: xe càng đi nhiều km thì giá càng giảm.
  • Nhóm xe đi dưới 10.000 kmgiá bán trung bình cao nhất (≈ 22.850 USD), thể hiện giá trị gần như xe mới.
  • Nhóm 10.000–50.000 km có số lượng lớn nhất (≈ 244.000 xe), cho thấy đây là mức sử dụng phổ biến trên thị trường xe cũ.
  • Khi quãng đường tăng từ 50.000 đến 200.000 km, giá trung bình giảm mạnh, đặc biệt nhóm 100.000–200.000 km chỉ còn khoảng 5.300 USD.
  • Nhóm xe trên 200.000 km có giá trung bình rất thấp (≈ 2.500 USD), phản ánh mức khấu hao lớn.
  • Có một số quan sát bị thiếu giá trị km (NA), tuy nhiên số lượng này rất nhỏ (94 xe), nên không ảnh hưởng đáng kể đến kết quả chung.

Phân tổ theo giá bán xe

data <- data %>%
  mutate(
    Nhom_gia = case_when(
      sellingprice < 10000 ~ "< 10.000 USD",
      sellingprice >= 10000 & sellingprice < 20000 ~ "10.000–20.000 USD",
      sellingprice >= 20000 & sellingprice < 40000 ~ "20.000–40.000 USD",
      sellingprice >= 40000 & sellingprice < 60000 ~ "40.000–60.000 USD",
      sellingprice >= 60000 & sellingprice < 100000 ~ "60.000–100.000 USD",
      sellingprice >= 100000 ~ "> 100.000 USD",
      TRUE ~ NA_character_
    )
  )
bang_gia <- data %>%
  group_by(Nhom_gia) %>%
  summarise(
    So_luong_xe = n(),
    Gia_trung_binh = mean(sellingprice, na.rm = TRUE),
    Gia_thap_nhat = min(sellingprice, na.rm = TRUE),
    Gia_cao_nhat = max(sellingprice, na.rm = TRUE)
  ) %>%
  arrange(Gia_trung_binh)
kable(bang_gia, caption = "Bảng phân tổ theo mức giá bán của xe")
Bảng phân tổ theo mức giá bán của xe
Nhom_gia So_luong_xe Gia_trung_binh Gia_thap_nhat Gia_cao_nhat
< 10.000 USD 175481 5311.016 1e+00 9975
10.000–20.000 USD 200976 14177.833 1e+04 19901
20.000–40.000 USD 88089 25918.226 2e+04 39999
40.000–60.000 USD 6484 46261.150 4e+04 59900
60.000–100.000 USD 1143 72524.621 6e+04 99500
> 100.000 USD 152 125137.829 1e+05 230000

Phần 3. Phân tích các biến

Mối quan hệ giữa số km đã đi (odometer) và giá bán (sellingprice)

library(ggplot2)
ggplot(data, aes(x = odometer, y = sellingprice)) +
  geom_point(alpha = 0.3, color = "steelblue") +
  geom_smooth(method = "lm", color = "red") +
  labs(
    title = "Mối quan hệ giữa số km đã đi và giá bán xe",
    x = "Số km đã đi (odometer)",
    y = "Giá bán (USD)"
  )

Biểu đồ cho thấy mối quan hệ nghịch chiều giữa số km đã đi và giá bán xe — xe đi càng nhiều thì giá bán càng giảm. Điều này phản ánh giá trị xe giảm dần theo mức độ hao mòn sử dụng. ## Mối quan hệ giữa năm sản xuất (year) và giá bán (sellingprice)

ggplot(data, aes(x = factor(year), y = sellingprice)) +
  geom_boxplot(fill = "lightblue", color = "darkblue") +
  labs(
    title = "Giá bán theo năm sản xuất của xe",
    x = "Năm sản xuất",
    y = "Giá bán (USD)"
  )

## Mối quan hệ giữa tình trạng xe (condition) và giá bán (sellingprice)

ggplot(data, aes(x = condition, y = sellingprice)) +
  geom_boxplot(fill = "orange", color = "darkred") +
  labs(
    title = "Ảnh hưởng của tình trạng xe đến giá bán",
    x = "Tình trạng xe",
    y = "Giá bán (USD)"
  )

## Mối quan hệ giữa hãng xe (make) và giá bán (sellingprice)

data_make <- data %>%
  group_by(make) %>%
  summarise(Gia_trung_binh = mean(sellingprice, na.rm = TRUE)) %>%
  arrange(desc(Gia_trung_binh)) %>%
  slice(1:10) # chỉ lấy top 10 hãng

ggplot(data_make, aes(x = reorder(make, Gia_trung_binh), y = Gia_trung_binh)) +
  geom_col(fill = "skyblue") +
  coord_flip() +
  labs(
    title = "Top 10 hãng xe có giá bán trung bình cao nhất",
    x = "Hãng xe",
    y = "Giá bán trung bình (USD)"
  )

## Mối quan hệ giữa số km đã đi (odometer) và năm sản xuất (year)

ggplot(data, aes(x = year, y = odometer)) +
  geom_point(alpha = 0.3, color = "darkgreen") +
  geom_smooth(method = "lm", color = "red") +
  labs(
    title = "Mối quan hệ giữa năm sản xuất và số km đã đi",
    x = "Năm sản xuất",
    y = "Số km đã đi (odometer)"
  )