Tôi xin gửi lời cảm ơn chân thành đến ThS. Trần Mạnh Tường – Giảng viên Khoa Khoa học Dữ liệu đã tận tình hướng dẫn và hỗ trợ tôi trong suốt quá trình học và thực hiện bài tiểu luận môn Ngôn ngữ lập trình trong phân tích dữ liệu.
Nhờ sự chỉ dẫn và những chia sẻ hữu ích của Thầy, tôi đã hiểu rõ hơn về kiến thức môn học và có thể hoàn thành bài tiểu luận này.
Tôi cũng nhận thấy rằng bài làm của mình vẫn còn nhiều thiếu sót. Tôi rất mong nhận được góp ý từ Thầy để có thể rút kinh nghiệm và hoàn thiện hơn trong những bài học và nghiên cứu sau này.
Cuối cùng, tôi xin chúc Thầy nhiều sức khỏe, niềm vui và thành công trong công việc giảng dạy. Tôi xin chân thành cảm ơn!
Tôi xin cam kết rằng bài tiểu luận này là kết quả của quá trình học tập, nghiên cứu và thực hiện của riêng tôi, không sao chép từ bất kỳ nguồn nào mà không trích dẫn rõ ràng.
Các số liệu, kết quả và nội dung trình bày trong bài đều trung thực và được thực hiện đúng quy định của môn học Ngôn ngữ lập trình trong phân tích dữ liệu.
Nếu có bất kỳ sai phạm hoặc gian lận nào được phát hiện, tôi xin hoàn toàn chịu trách nhiệm trước giảng viên và nhà trường.
Tôi xin cam đoan những điều trên là đúng sự thật.
Bài báo cáo tiểu luận của nhóm chúng tôi bao gồm 2 phần:
Phần 1: Trình bày bộ dữ liệu về các chuyến bay trong 2 tháng đầu năm 2024.
Phần 2: Trình bày bộ dữ liệu của mã chứng khoán NVL.
Tên bộ dữ liệu: Flight Delay Dataset 2024
Nguồn bộ dữ liệu: https://www.kaggle.com/datasets/hrishitpatil/flight-data-2024
Thông tin bộ dữ liệu: Bộ dữ liệu chứa thông tin về hiệu suất chuyến bay vào tháng 1 và tháng 2 năm 2024. Nó cung cấp thông tin toàn diện về thời gian bay theo lịch trình và thực tế, sự chậm trễ và khoảng cách giữa các sân bay.
Mục đích lấy dữ liệu: Dữ liệu được xử lý, làm sạch và phân tích nhằm hiểu rõ đặc điểm của các chuyến bay.
Sau khi thu thập dữ liệu là nạp bộ dữ liệu thô vào R để bắt đầu quá trình phân tích:
flight_data <- read.csv("C:/Users/TO UYEN/Downloads/flight_data.csv")
Giải thích: (1) dùng để nạp dữ liệu từ file flight_data.csv và đặt tên cho bộ dữ liệu là flight_data.
Nhận xét: Đây là bước đầu tiên khi phân tích dữ liệu thống kê, chuẩn bị cho các bước làm sạch, mô tả và trực quan hóa.
Sau khi đưa dữ liệu thô vào R, bước tiếp theo là tiến hành kiểm tra dữ liệu đã được nạp thành công hay chưa:
is.data.frame(flight_data)
## [1] TRUE
Giải thích: (1) dùng để kiểm tra dữ liệu có được nạp đúng dạng bảng hay không: TRUE nếu là data frame, FALSE nếu không phải.
Nhận xét: Kết quả là TRUE vì thế flight_data là một Data Frame, phù hợp cho các phân tích và xử lý sau này.
dim(flight_data)
## [1] 1048575 26
Giải thích: (1) dùng để kiểm tra kích thước của bộ dữ liệu. Giá trị đầu tiên là số hàng (số quan sát), giá trị thứ hai là số cột (số biến).
Nhận xét: Bộ dữ liệu có 1.048.575 quan sát
và 26 biến.
names(flight_data)
## [1] "month" "day_of_month" "day_of_week"
## [4] "fl_date" "op_unique_carrier" "op_carrier_fl_num"
## [7] "origin" "origin_city_name" "origin_state_nm"
## [10] "dest" "dest_city_name" "dest_state_nm"
## [13] "crs_dep_time" "dep_time" "dep_delay"
## [16] "taxi_out" "wheels_off" "wheels_on"
## [19] "taxi_in" "crs_arr_time" "arr_time"
## [22] "arr_delay" "crs_elapsed_time" "actual_elapsed_time"
## [25] "air_time" "distance"
Giải thích: (1) dùng để hiển thị tên các biến trong bộ dữ liệu.
Nhận xét: Kết quả cung cấp danh sách tên biến, làm cơ sở cho quá trình mô tả, so sánh và mô hình hóa ở các bước phân tích tiếp theo.
sapply(flight_data, typeof)
## month day_of_month day_of_week fl_date
## "integer" "integer" "integer" "character"
## op_unique_carrier op_carrier_fl_num origin origin_city_name
## "character" "integer" "character" "character"
## origin_state_nm dest dest_city_name dest_state_nm
## "character" "character" "character" "character"
## crs_dep_time dep_time dep_delay taxi_out
## "integer" "integer" "integer" "integer"
## wheels_off wheels_on taxi_in crs_arr_time
## "integer" "integer" "integer" "integer"
## arr_time arr_delay crs_elapsed_time actual_elapsed_time
## "integer" "integer" "integer" "integer"
## air_time distance
## "integer" "integer"
Giải thích: (1) dùng để liệt kê kiểu dữ liệu của từng cột trong bảng flight_data.
Nhận xét: Các biến định lượng (integer) như: month, day_of_month, day_of_week, op_carrier_fl_num, crs_dep_time, dep_time,… thích hợp để thống kê định lượng. Các biến định tính (character) như: fl_date, op_unique_carrier, origin, origin_city_name, origin_state_nm, dest, dest_city_name,… dùng để mô tả, phân loại.
table(sapply(flight_data, typeof))
##
## character integer
## 8 18
Giải thích: (1) dùng để đếm số lượng cột theo từng kiểu dữ liệu trong bảng flight_data.
Nhận xét: Bộ dữ liệu có 8 biến thuộc kiểu
character và 18 biến thuộc kiểu integer.
sum(duplicated(flight_data))
## [1] 0
Giải thích: (1) dùng để đếm số dòng bị trùng lặp trong bảng flight_data.
Nhận xét: Không có quan sát bị trùng lặp
trong bộ dữ liệu vì tổng số dòng dữ liệu bị trùng lặp bằng 0.
library(knitr)
kable(t(head(flight_data, 5)))
| 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|
| month | 1 | 1 | 1 | 1 | 1 |
| day_of_month | 1 | 1 | 1 | 1 | 1 |
| day_of_week | 1 | 1 | 1 | 1 | 1 |
| fl_date | 01/01/2024 | 01/01/2024 | 01/01/2024 | 01/01/2024 | 01/01/2024 |
| op_unique_carrier | 9E | 9E | 9E | 9E | 9E |
| op_carrier_fl_num | 4814 | 4815 | 4817 | 4817 | 4818 |
| origin | JFK | MSP | JFK | RIC | DTW |
| origin_city_name | New York, NY | Minneapolis, MN | New York, NY | Richmond, VA | Detroit, MI |
| origin_state_nm | New York | Minnesota | New York | Virginia | Michigan |
| dest | DTW | CLE | RIC | JFK | MKE |
| dest_city_name | Detroit, MI | Cleveland, OH | Richmond, VA | New York, NY | Milwaukee, WI |
| dest_state_nm | Michigan | Ohio | Virginia | New York | Wisconsin |
| crs_dep_time | 1252 | 1015 | 1415 | 1650 | 1015 |
| dep_time | 1247 | 1001 | 1411 | 1643 | 1010 |
| dep_delay | -5 | -14 | -4 | -7 | -5 |
| taxi_out | 31 | 20 | 21 | 13 | 21 |
| wheels_off | 1318 | 1021 | 1432 | 1656 | 1031 |
| wheels_on | 1442 | 1249 | 1533 | 1747 | 1016 |
| taxi_in | 7 | 6 | 8 | 12 | 4 |
| crs_arr_time | 1508 | 1325 | 1601 | 1841 | 1034 |
| arr_time | 1449 | 1255 | 1541 | 1759 | 1020 |
| arr_delay | -19 | -30 | -20 | -42 | -14 |
| crs_elapsed_time | 136 | 130 | 106 | 111 | 79 |
| actual_elapsed_time | 122 | 114 | 90 | 76 | 70 |
| air_time | 84 | 88 | 61 | 51 | 45 |
| distance | 509 | 622 | 288 | 288 | 237 |
Giải thích:
(1): nạp gói knitr để hiển thị bảng dữ liệu rõ ràng trong môi trường RMarkdown.
(2): hiển thị 5 dòng đầu tiên của bảng dữ liệu dưới dạng bảng xoay ngang.
Nhận xét: Việc quan sát 5 dòng đầu giúp hiểu thông tin dữ liệu trước khi phân tích thống kê.
kable(t(tail(flight_data, 5)))
| 1048571 | 1048572 | 1048573 | 1048574 | 1048575 | |
|---|---|---|---|---|---|
| month | 2 | 2 | 2 | 2 | 2 |
| day_of_month | 29 | 29 | 29 | 29 | 29 |
| day_of_week | 4 | 4 | 4 | 4 | 4 |
| fl_date | 29/02/2024 | 29/02/2024 | 29/02/2024 | 29/02/2024 | 29/02/2024 |
| op_unique_carrier | AA | AA | AA | AA | AA |
| op_carrier_fl_num | 1613 | 1614 | 1615 | 1616 | 1616 |
| origin | SJU | PHX | JAX | CLT | MCI |
| origin_city_name | San Juan, PR | Phoenix, AZ | Jacksonville, FL | Charlotte, NC | Kansas City, MO |
| origin_state_nm | Puerto Rico | Arizona | Florida | North Carolina | Missouri |
| dest | MIA | MIA | CLT | MCI | CLT |
| dest_city_name | Miami, FL | Miami, FL | Charlotte, NC | Kansas City, MO | Charlotte, NC |
| dest_state_nm | Florida | Florida | North Carolina | Missouri | North Carolina |
| crs_dep_time | 1455 | 2255 | 2018 | 900 | 1123 |
| dep_time | 1447 | 59 | 2014 | 1104 | 1307 |
| dep_delay | -8 | 124 | -4 | 124 | 104 |
| taxi_out | 24 | 12 | 20 | 12 | 13 |
| wheels_off | 1511 | 111 | 2034 | 1116 | 1320 |
| wheels_on | 1640 | 647 | 2128 | 1210 | 1559 |
| taxi_in | 7 | 3 | 10 | 7 | 22 |
| crs_arr_time | 1646 | 502 | 2143 | 1033 | 1428 |
| arr_time | 1647 | 650 | 2138 | 1217 | 1621 |
| arr_delay | 1 | 108 | -5 | 104 | 113 |
| crs_elapsed_time | 171 | 247 | 85 | 153 | 125 |
| actual_elapsed_time | 180 | 231 | 84 | 133 | 134 |
| air_time | 149 | 216 | 54 | 114 | 99 |
| distance | 1045 | 1972 | 328 | 808 | 808 |
Giải thích: (1) dùng để hiển thị 5 dòng cuối cùng của bảng dữ liệu dưới dạng bảng xoay ngang.
Nhận xét: Việc quan sát 5 dòng cuối giúp kiểm tra tính đầy đủ, liên tục và không bị mất mốc thời gian cuối.
data_dict <- data.frame(
"Tên biến" = c(
"month", "day_of_month", "day_of_week", "fl_date", "op_unique_carrier",
"op_carrier_fl_num", "origin", "origin_city_name", "origin_state_nm",
"dest", "dest_city_name", "dest_state_nm", "crs_dep_time", "dep_time",
"dep_delay", "taxi_out", "wheels_off", "wheels_on", "taxi_in",
"crs_arr_time", "arr_time", "arr_delay", "crs_elapsed_time",
"actual_elapsed_time", "air_time", "distance"),
"Ý nghĩa" = c(
"Tháng trong năm.",
"Ngày trong tháng.",
"Ngày trong tuần.",
"Ngày bay.",
"Mã hãng hàng không thực hiện chuyến bay.",
"Số hiệu chuyến bay của hãng.",
"Mã sân bay khởi hành.",
"Tên thành phố khởi hành.",
"Tên bang hoặc khu vực sân bay khởi hành.",
"Mã sân bay đến.",
"Tên thành phố đến.",
"Tên bang hoặc khu vực sân bay đến.",
"Giờ dự kiến cất cánh (theo lịch).",
"Giờ thực tế cất cánh.",
"Độ trễ cất cánh (phút), giá trị âm nếu cất cánh sớm hơn dự kiến.",
"Khoảng thời gian máy bay di chuyển từ cổng ra đường băng chuẩn bị cất cánh.",
"Thời điểm bánh xe rời mặt đất.",
"Thời điểm bánh xe chạm đất tại sân bay đến.",
"Khoảng thời gian máy bay lăn từ đường băng về cổng sau khi hạ cánh.",
"Giờ dự kiến hạ cánh (theo lịch).",
"Giờ thực tế hạ cánh.",
"Độ trễ hạ cánh (phút), giá trị âm nếu hạ cánh sớm hơn dự kiến.",
"Thời gian dự kiến bay (phút).",
"Thời gian bay thực tế (phút).",
"Thời gian bay trên không (phút).",
"Khoảng cách giữa sân bay đi và đến (dặm)."))
kable(data_dict, col.names = c("Tên biến", "Ý nghĩa"))
| Tên biến | Ý nghĩa |
|---|---|
| month | Tháng trong năm. |
| day_of_month | Ngày trong tháng. |
| day_of_week | Ngày trong tuần. |
| fl_date | Ngày bay. |
| op_unique_carrier | Mã hãng hàng không thực hiện chuyến bay. |
| op_carrier_fl_num | Số hiệu chuyến bay của hãng. |
| origin | Mã sân bay khởi hành. |
| origin_city_name | Tên thành phố khởi hành. |
| origin_state_nm | Tên bang hoặc khu vực sân bay khởi hành. |
| dest | Mã sân bay đến. |
| dest_city_name | Tên thành phố đến. |
| dest_state_nm | Tên bang hoặc khu vực sân bay đến. |
| crs_dep_time | Giờ dự kiến cất cánh (theo lịch). |
| dep_time | Giờ thực tế cất cánh. |
| dep_delay | Độ trễ cất cánh (phút), giá trị âm nếu cất cánh sớm hơn dự kiến. |
| taxi_out | Khoảng thời gian máy bay di chuyển từ cổng ra đường băng chuẩn bị cất cánh. |
| wheels_off | Thời điểm bánh xe rời mặt đất. |
| wheels_on | Thời điểm bánh xe chạm đất tại sân bay đến. |
| taxi_in | Khoảng thời gian máy bay lăn từ đường băng về cổng sau khi hạ cánh. |
| crs_arr_time | Giờ dự kiến hạ cánh (theo lịch). |
| arr_time | Giờ thực tế hạ cánh. |
| arr_delay | Độ trễ hạ cánh (phút), giá trị âm nếu hạ cánh sớm hơn dự kiến. |
| crs_elapsed_time | Thời gian dự kiến bay (phút). |
| actual_elapsed_time | Thời gian bay thực tế (phút). |
| air_time | Thời gian bay trên không (phút). |
| distance | Khoảng cách giữa sân bay đi và đến (dặm). |
Giải thích:
(1)-(35): tạo bảng dữ liệu gồm 2 cột Tên biến và Ý nghĩa.
(36): in bảng gọn đẹp mô tả toàn bộ 26 biến trong dữ liệu chuyến bay.
Nhận xét: Bảng kết quả giúp người đọc hiểu
rõ vai trò của từng biến.
any(is.na(flight_data))
## [1] TRUE
Giải thích: (1) dùng để kiểm tra bộ dữ liệu có ô nào bị thiếu dữ liệu hay không. Nếu kết quả là TRUE thì ô đó bị thiếu (NA), ngược lại kết quả là FALSE nếu ô đó có giá trị.
Nhận xét: Vì kết quả trả về là TRUE nên bộ
dữ liệu có tồn tại dữ liệu bị thiếu (NA) trong bộ dữ liệu
flight_data.
Bước tiếp theo, thực hiện đếm số lượng giá trị bị thiếu (NA) ở từng biến.
colSums(is.na(flight_data))
## month day_of_month day_of_week fl_date
## 0 0 0 0
## op_unique_carrier op_carrier_fl_num origin origin_city_name
## 0 0 0 0
## origin_state_nm dest dest_city_name dest_state_nm
## 0 0 0 0
## crs_dep_time dep_time dep_delay taxi_out
## 0 22553 22650 23125
## wheels_off wheels_on taxi_in crs_arr_time
## 23125 23677 23677 0
## arr_time arr_delay crs_elapsed_time actual_elapsed_time
## 23675 25751 1 25751
## air_time distance
## 25751 0
Giải thích: (1) dùng để đếm số ô bị thiếu (NA) trong từng cột của bảng flight_data.
Nhận xét: Các giá trị thiếu tập trung ở các biến thời gian và độ trễ, có thể do chuyến bay bị hủy hoặc dữ liệu không được ghi nhận đầy đủ.
Vì các biến bị thiếu không phải là biến trọng yếu và số lượng giá trị thiếu ở các biến là nhỏ, không ảnh hưởng đến tổng thể dữ liệu nên phương pháp xử lý NA phù hợp nhất là loại bỏ các dòng bị thiếu.
flight_data_clean <- na.omit(flight_data)
colSums(is.na(flight_data_clean))
## month day_of_month day_of_week fl_date
## 0 0 0 0
## op_unique_carrier op_carrier_fl_num origin origin_city_name
## 0 0 0 0
## origin_state_nm dest dest_city_name dest_state_nm
## 0 0 0 0
## crs_dep_time dep_time dep_delay taxi_out
## 0 0 0 0
## wheels_off wheels_on taxi_in crs_arr_time
## 0 0 0 0
## arr_time arr_delay crs_elapsed_time actual_elapsed_time
## 0 0 0 0
## air_time distance
## 0 0
Giải thích:
(1): tạo ra một bộ dữ liệu mới tên là
flight_data_clean bằng cách loại bỏ tất cả các quan sát bị NA.
(2): kiểm tra lại toàn bộ dữ liệu sau khi làm
sạch.
Nhận xét: Kết quả trả về là 0 chứng tỏ bộ
dữ liệu flight_data_clean không còn giá trị thiếu.
Sau khi xử lý giá trị bị thiếu, kiểm tra lại số lượng quan sát sau khi làm sạch.
nrow(flight_data_clean)
## [1] 1022824
Giải thích: (1) dùng để đếm số quan sát trong bảng dữ liệu flight_data_clean.
Nhận xét: Kết quả cho biết quy mô dữ liệu sau khi làm sạch có 1.022.824 quan sát.
Biến op_unique_carrier thể hiện mã hãng hàng không thực hiện chuyến bay được lưu dưới dạng character nhưng giá trị của nó chỉ phân loại các hãng bay chứ không mang ý nghĩa văn bản. Do đó, khi chuyển sang dạng factor giúp R nhận diện đúng bản chất biến định tính phân loại thay vì biến chuỗi thông thường.
flight_data_clean$op_unique_carrier <- as.factor(flight_data_clean$op_unique_carrier)
class(flight_data_clean$op_unique_carrier)
## [1] "factor"
Giải thích:
(1): chuyển biến op_unique_carrier từ dạng character sang dạng factor.
(2): kiểm tra lại kiểu dữ liệu sau khi chuyển đổi.
Nhận xét: Kết quả “factor” xác nhận chuyển
thành kiểu factor thành công.
Biến op_carrier_fl_num thể hiện mã số chuyến bay của hãng hàng không được lưu dưới dạng integer nhưng các giá trị của nó mang tính định danh cho từng chuyến bay chứ không mang ý nghĩa đo lường hay thứ tự. Do đó, việc chuyển sang dạng character giúp lưu trữ chính xác hơn bản chất nhận dạng của biến mà không làm phát sinh các xử lý nhầm lẫn như biến số.
flight_data_clean$op_carrier_fl_num <- as.character(flight_data_clean$op_carrier_fl_num)
class(flight_data_clean$op_carrier_fl_num)
## [1] "character"
Giải thích:
(1): chuyển biến op_carrier_fl_num sang kiểu ký tự (character).
(2):: kiểm tra lại kiểu dữ liệu sau khi chuyển đổi.
Nhận xét: Kết quả “character” xác nhận việc
chuyển đổi đã thành công.
flight_data_clean$weekend_flight <- ifelse(flight_data_clean$day_of_week %in% c(6, 7), 1, 0)
table(flight_data_clean$weekend_flight)
##
## 0 1
## 753717 269107
Giải thích:
(1): tạo biến mới weekend_flight. Nếu day_of_week là 6 hoặc 7, giá trị gán bằng 1 (chuyến bay cuối tuần); ngược lại gán 0 (chuyến bay ngày thường).
(2): đếm tần suất xuất hiện của hai giá trị 0 và 1.
Nhận xét: Bộ dữ liệu có 269.107 chuyến bay diễn ra vào cuối tuần và 753.717 chuyến bay vào các ngày thường.
flight_data_clean$day_period <- ifelse(
flight_data_clean$dep_time >= 300 &
flight_data_clean$dep_time < 720, "Morning",
ifelse(
flight_data_clean$dep_time >= 720 &
flight_data_clean$dep_time < 1080, "Afternoon",
ifelse(
flight_data_clean$dep_time >= 1080 &
flight_data_clean$dep_time < 1320, "Evening",
"Night")))
flight_data_clean$day_period <- as.factor(flight_data_clean$day_period)
summary(flight_data_clean$day_period)
## Afternoon Evening Morning Night
## 223079 142217 136900 520628
Giải thích:
(1)-(10): tạo biến mới day_period: dep_time từ 300–719 phút gán “Morning”, từ 720–1079 phút gán “Afternoon”, từ 1080–1319 phút gán “Evening”, các giá trị còn lại gán “Night”.
(11): chuyển biến day_period sang dạng factor để R hiểu đây là biến phân loại.
(12): thống kê số lượng chuyến bay trong từng nhóm thời điểm.
Nhận xét: Việc phân chia chuyến bay theo bốn khoảng thời gian cho thấy sự tập trung của lưu lượng bay vào ban đêm.
Trước khi tính tốc độ trung bình (speed_mph), cần kiểm tra trong tập dữ liệu có giá trị air_time ≤ 0 hay không. Việc này giúp tránh sai số và lỗi chia cho 0 trong bước tính tốc độ.
any(flight_data_clean$air_time <= 0)
## [1] FALSE
Giải thích: (1) dùng để kiểm tra có giá trị air_time ≤ 0 hay không. Kết quả trả về TRUE nếu có ít nhất một giá trị ≤ 0, ngược lại là FALSE.
Nhận xét: Kết quả trả về FALSE cho thấy không có chuyến bay nào có thời gian bay ≤ 0. Bộ dữ liệu đủ điều kiện để tính tốc độ trung bình (speed_mph).
flight_data_clean$speed_mph <-
flight_data_clean$distance / (flight_data_clean$air_time / 60)
summary(flight_data_clean$speed_mph)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 21.16 360.00 407.75 405.57 453.75 4473.33
Giải thích:
(1)-(2): Tạo biến mới speed_mph bằng công thức tốc độ = quãng đường / thời gian.
(3): thống kê mô tả cơ bản của biến tốc độ giúp đánh giá mức độ dao động giữa các chuyến bay.
Nhận xét: Giá trị nhỏ nhất chỉ 21.16 mph và giá trị lớn nhất tới 4473.33 mph là không thực tế. Nguyên nhân có thể do lỗi nhập liệu, thời gian bay ghi sai hoặc sự cố trong quá trình đo đạc. Do đó, các giá trị tốc độ quá thấp hoặc quá cao (ngoại lai) cần được loại bỏ hoặc hiệu chỉnh ở bước xử lý kế tiếp nhằm đảm bảo tính chính xác cho các phân tích sau này.
library(dplyr)
Q1 <- quantile(flight_data_clean$speed_mph, 0.25, na.rm = TRUE)
Q3 <- quantile(flight_data_clean$speed_mph, 0.75, na.rm = TRUE)
IQR_value <- Q3 - Q1
lower_bound <- Q1 - 1.5 * IQR_value
upper_bound <- Q3 + 1.5 * IQR_value
flight_data_no_outlier <- flight_data_clean %>%
filter(speed_mph >= lower_bound & speed_mph <= upper_bound)
summary(flight_data_no_outlier$speed_mph)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 219.4 361.6 408.7 407.8 454.2 594.4
Giải thích:
(1): nạp gói dplyr để thực hiện thao tác lọc dữ liệu.
(2)-(3): tính các phân vị thứ nhất (Q1) và thứ ba
(Q3) của biến speed_mph.
(4): tính khoảng tứ phân vị (IQR) bằng hiệu Q3 - Q1.
(5)-(6): xác định ngưỡng dưới và ngưỡng trên dựa theo quy tắc 1.5 × IQR để nhận diện ngoại lai.
(7): tạo bộ dữ liệu mới tên flight_data_no_outlier.
(8): lọc các quan sát có speed_mph nằm trong khoảng lower_bound đến upper_bound.
(9): thống kê lại tốc độ sau khi loại bỏ ngoại lai.
Nhận xét: Sau khi lọc, khoảng giá trị từ
219,4 đến 594,4 dặm/giờ trở nên hợp lý, với tốc độ trung bình khoảng 408
dặm/giờ, phù hợp với đặc điểm kỹ thuật của máy bay phản lực dân dụng, có
độ tin cậy cao hơn, sẵn sàng cho các phân tích mô tả và mô hình hóa tiếp
theo.
flight_data_no_outlier <- flight_data_no_outlier %>%
mutate(schedule_diff = actual_elapsed_time - crs_elapsed_time)
names(flight_data_no_outlier)
## [1] "month" "day_of_month" "day_of_week"
## [4] "fl_date" "op_unique_carrier" "op_carrier_fl_num"
## [7] "origin" "origin_city_name" "origin_state_nm"
## [10] "dest" "dest_city_name" "dest_state_nm"
## [13] "crs_dep_time" "dep_time" "dep_delay"
## [16] "taxi_out" "wheels_off" "wheels_on"
## [19] "taxi_in" "crs_arr_time" "arr_time"
## [22] "arr_delay" "crs_elapsed_time" "actual_elapsed_time"
## [25] "air_time" "distance" "weekend_flight"
## [28] "day_period" "speed_mph" "schedule_diff"
Giải thích:
(1)-(2): tạo biến mới schedule_diff bằng công thức: thời gian bay thực tế - thời gian bay theo lịch trình.
(3): hiển thị tên các biến trong bộ dữ liệu nhằm xác nhận rằng biến schedule_diff đã được tạo thành công.
Nhận xét: Bộ dữ liệu flight_data_no_outlier đã có thêm biến schedule_diff. Biến này giúp đánh giá mức độ chênh lệch giữa thời gian thực tế và lịch trình.
Việc chuyển tất cả các biến thời gian (departure, arrival, wheels_off, wheels_on) sang đơn vị “phút trong ngày” giúp dữ liệu giảm phức tạp khi xử lý và thuận tiện cho việc tính toán, so sánh và trực quan hóa.
convert_to_minutes <- function(x) {
hour <- floor(x / 100)
minute <- x %% 100
total_minutes <- hour * 60 + minute
return(total_minutes)}
flight_data_no_outlier <- flight_data_no_outlier %>%
mutate(
crs_dep_time_min = convert_to_minutes(crs_dep_time),
dep_time_min = convert_to_minutes(dep_time),
wheels_off_min = convert_to_minutes(wheels_off),
wheels_on_min = convert_to_minutes(wheels_on),
crs_arr_time_min = convert_to_minutes(crs_arr_time),
arr_time_min = convert_to_minutes(arr_time))
View(flight_data_no_outlier)
Giải thích:
(1): chuyển đổi thời gian dạng giờ–phút sang tổng số phút trong ngày.
(2)-(5) tách phần giờ và phần phút từ giá trị nhập vào và quy đổi tổng thời gian sang phút.
(6): gọi bộ dữ liệu flight_data_no_outlier và dùng toán tử %>% để truyền dữ liệu vào bước xử lý kế tiếp.
(7)-(13): tạo thêm các biến mới: crs_dep_time_min (giờ khởi hành dự kiến), dep_time_min (giờ khởi hành thực tế), wheels_off_min (thời điểm cất cánh thực tế), wheels_on_min (thời điểm hạ cánh thực tế), crs_arr_time_min ( giờ đến dự kiến), arr_time_min (giờ đến thực tế) theo đơn vị phút.
(14): mở bảng dữ liệu đã bổ sung các cột thời gian mới.
Nhận xét: Chuẩn hóa dữ liệu thời gian của chuyến bay về cùng đơn vị phút nhằm phục vụ cho các phép đo, so sánh và phân tích thống kê chính xác.
Phân tích đặc điểm cơ bản của 3 biến định lượng: dep_delay, arr_delay và distance.
quant_vars <- flight_data_no_outlier[, c("dep_delay", "arr_delay", "distance")]
Giải thích: (1) dùng để trích 3 biến định lượng từ bộ dữ liệu flight_data_no_outlier.
Nhận xét: Lọc 3 biến định lượng để thống kê mô tả, tính trung bình, tính độ lệch chuẩn và tính khoảng của từng biến ở các bước tiếp theo.
summary(quant_vars)
## dep_delay arr_delay distance
## Min. : -96.00 Min. :-117.000 Min. : 31
## 1st Qu.: -6.00 1st Qu.: -17.000 1st Qu.: 406
## Median : -2.00 Median : -7.000 Median : 699
## Mean : 11.52 Mean : 5.494 Mean : 839
## 3rd Qu.: 8.00 3rd Qu.: 9.000 3rd Qu.:1072
## Max. :3125.00 Max. :3136.000 Max. :5095
Giải thích: (1) dùng để tạo bảng tóm tắt thống kê mô tả cơ bản như: min, 1st quartile, median, mean, 3rd quartile, max.
Nhận xét: Độ trễ khởi hành từ -96 đến 3125 phút, trung bình 11.5 phút cho thấy đa số đúng giờ hoặc trễ nhẹ, nhưng có vài giá trị trễ rất lớn có thể do ngoại lệ. Độ trễ hạ cánh từ -117 đến 3136 phút, trung bình 5.5 phút, trung vị -7 phút cho thấy nhiều chuyến đến sớm nhưng vẫn có một số chuyến trễ nặng. Khoảng cách bay từ 31 đến 5095 dặm, trung bình 839 dặm phản ánh sự đa dạng về độ dài hành trình.
sapply(quant_vars, sd)
## dep_delay arr_delay distance
## 56.23152 59.03097 584.93699
Giải thích: (1) dùng để tính độ lệch chuẩn cho từng cột trong quant_var.
Nhận xét: Độ trễ khởi hành và khi đến có mức biến động tương đối lớn, phản ánh sự không ổn định trong thời gian bay giữa các chuyến. Biến khoảng cách có độ lệch chuẩn cao do sự chênh lệch cao giữa các chuyến bay ngắn và dài trong bộ dữ liệu.
sapply(quant_vars, function(x) max(x) - min(x))
## dep_delay arr_delay distance
## 3221 3253 5064
Giải thích: (1) dùng để tính khoảng biến thiên cho từng cột trong quant_vars.
Nhận xét: Biến dep_delay và arr_delay có mức dao động rất lớn phản ánh sự chênh lệch rõ rệt giữa các chuyến bay đến sớm và trễ nặng. Biến distance có khoảng biến thiên rộng chứng tỏ bộ dữ liệu có các chuyến bay ngắn và đường bay dài.
qual_vars <- flight_data_no_outlier[, c("op_unique_carrier", "origin", "dest")]
Giải thích: (1) dùng để trích 3 biến định tính từ bộ dữ liệu flight_data_no_outlier.
Nhận xét: Lọc 3 biến định tính này nhằm phân tích tần suất xuất hiện, tính tần suất tương đối và sắp xếp các nhóm theo tần suất giảm dần.
Giải thích chung:
table(): đếm số lần xuất hiện của từng giá trị trong một biến phân loại.
as.data.frame(): kết quả được chuyển sang dạng khung dữ liệu data frame.
kable(): hiển thị bảng dưới dạng đẹp mắt trong báo cáo RMarkdown, có chú thích và căn lề cột.
table_carrier <- as.data.frame(table(flight_data_no_outlier$op_unique_carrier))
colnames(table_carrier) <- c("Mã hãng hàng không", "Số chuyến bay")
kable(table_carrier,
caption = "**Tần suất hãng hàng không thực hiện chuyến bay**",
align = "lc", row.names = FALSE)
| Mã hãng hàng không | Số chuyến bay |
|---|---|
| 9E | 31053 |
| AA | 147210 |
| AS | 30255 |
| B6 | 37060 |
| DL | 141543 |
| F9 | 27544 |
| G4 | 16369 |
| HA | 11770 |
| MQ | 38334 |
| NK | 39048 |
| OH | 28685 |
| OO | 100015 |
| UA | 107441 |
| WN | 211567 |
| YX | 41396 |
Nhận xét: Hãng WN có số chuyến nhiều nhất, tiếp theo là AA, DL, UA cho thấy quy mô khai thác lớn, trong khi HA, G4, F9 có ít chuyến hơn, phản ánh sự chênh lệch rõ giữa các hãng.
table_origin <- as.data.frame(table(flight_data_no_outlier$origin))
colnames(table_origin) <- c("Mã sân bay xuất phát", "Số chuyến bay")
table_origin <- table_origin[order(-table_origin$'Số chuyến bay'), ]
kable(head(table_origin, 10),
caption = "**Tần suất 10 sân bay xuất phát có số chuyến bay cao nhất**", row.names = FALSE, align = "lc")
| Mã sân bay xuất phát | Số chuyến bay |
|---|---|
| ATL | 49667 |
| DFW | 44431 |
| DEN | 42461 |
| ORD | 37057 |
| CLT | 30470 |
| PHX | 29025 |
| LAS | 27791 |
| LAX | 27741 |
| MCO | 26862 |
| LGA | 23926 |
Nhận xét: Các sân bay trên là trung tâm hàng không lớn với tần suất khai thác cao, thể hiện vai trò trung chuyển trọng điểm trong mạng lưới bay nội địa.
table_dest <- as.data.frame(table(flight_data_no_outlier$dest))
colnames(table_dest) <- c("Mã sân bay đến", "Số chuyến bay")
table_dest <- table_dest[order(-table_dest$`Số chuyến bay`), ]
kable(head(table_dest, 10),
caption = "**Tần suất 10 sân bay đến có số chuyến bay cao nhất**",
row.names = FALSE, align = "lc")
| Mã sân bay đến | Số chuyến bay |
|---|---|
| ATL | 49266 |
| DFW | 44167 |
| DEN | 42086 |
| ORD | 36555 |
| CLT | 29496 |
| PHX | 29070 |
| LAX | 27961 |
| LAS | 27922 |
| MCO | 26827 |
| LGA | 23565 |
Nhận xét: Sân bay ATL đứng đầu với 49.266 chuyến, tiếp theo là DFW và DEN với hơn 40,000 chuyến. Các sân bay ORD, CLT, PHX, LAX, LAS, MCO, LGA cũng có lượng chuyến lớn, phản ánh mức khai thác mạnh ở cả hai chiều.
Giải thích chung:
table(): tạo bảng tần suất đếm số chuyến bay của từng hãng hàng không.
prop.table(): chuyển tần suất tuyệt đối sang tần suất tương đối.
round(…,2): làm tròn kết quả đến 2 chữ số thập phân.
as.data.frame(): chuyển kết quả thành một data frame để tiện xử lý và hiển thị.
colnames(): đặt tên cột cho rõ nghĩa.
kable(): hiển thị bảng dưới dạng bảng đẹp và có chú thích trong R Markdown.
table_carrier_rel <- as.data.frame(round(prop.table(
table(flight_data_no_outlier$op_unique_carrier)) * 100, 2))
colnames(table_carrier_rel) <- c("Mã hãng hàng không", "Tần suất tương đối (%)")
kable(table_carrier_rel,
caption = "**Tần suất tương đối (%) của hãng hàng không thực hiện chuyến bay**",
row.names = FALSE, align = "lc")
| Mã hãng hàng không | Tần suất tương đối (%) |
|---|---|
| 9E | 3.08 |
| AA | 14.59 |
| AS | 3.00 |
| B6 | 3.67 |
| DL | 14.02 |
| F9 | 2.73 |
| G4 | 1.62 |
| HA | 1.17 |
| MQ | 3.80 |
| NK | 3.87 |
| OH | 2.84 |
| OO | 9.91 |
| UA | 10.65 |
| WN | 20.96 |
| YX | 4.10 |
Nhận xét: Hãng WN chiếm tỷ trọng cao nhất (20,96%), tiếp theo là AA, DL, và UA với hơn 10% mỗi hãng cho thấy ưu thế rõ của các hãng lớn, trong khi hãng nhỏ hoạt động hạn chế.
table_origin_rel <- as.data.frame(round(prop.table(
table(flight_data_no_outlier$origin)) * 100, 2))
colnames(table_origin_rel) <- c("Mã sân bay xuất phát", "Tần suất tương đối (%)")
top10_origin <- table_origin_rel %>%
arrange(desc(`Tần suất tương đối (%)`)) %>%
head(10)
kable(top10_origin,
caption = "**Top 10 sân bay xuất phát theo tần suất tương đối**",
row.names = FALSE, align = "lc")
| Mã sân bay xuất phát | Tần suất tương đối (%) |
|---|---|
| ATL | 4.92 |
| DFW | 4.40 |
| DEN | 4.21 |
| ORD | 3.67 |
| CLT | 3.02 |
| PHX | 2.88 |
| LAS | 2.75 |
| LAX | 2.75 |
| MCO | 2.66 |
| LGA | 2.37 |
Nhận xét: Sân bay ATL có tần suất xuất phát cao nhất (4,92%), tiếp theo là DFW, DEN, ORD và CLT (3-4%). Các sân bay PHX, LAS, LAX, MCO, LGA (2–3%) cho thấy hoạt động bay tập trung ở các trung tâm lớn.
table_dest_rel <- as.data.frame(round(prop.table(
table(flight_data_no_outlier$dest)) * 100, 2))
colnames(table_dest_rel) <- c("Mã sân bay đến", "Tần suất tương đối (%)")
top10_dest <- table_dest_rel %>%
arrange(desc(`Tần suất tương đối (%)`)) %>%
head(10)
kable(top10_dest,
caption = "**Top 10 sân bay đến theo tần suất tương đối**",
row.names = FALSE, align = "lc")
| Mã sân bay đến | Tần suất tương đối (%) |
|---|---|
| ATL | 4.88 |
| DFW | 4.38 |
| DEN | 4.17 |
| ORD | 3.62 |
| CLT | 2.92 |
| PHX | 2.88 |
| LAS | 2.77 |
| LAX | 2.77 |
| MCO | 2.66 |
| LGA | 2.33 |
Nhận xét: Sân bay ATL có tần suất đến cao nhất (4.88%), tiếp theo là DFW và DEN. Các sân bay ORD, CLT, PHX, LAS, LAX, MCO, LGA chiếm tỷ lệ từ 2–3% cho thấy vai trò nút giao của các trung tâm hàng không lớn.
delay_by_day <- flight_data_no_outlier %>%
group_by(day_of_week) %>%
summarise(
avg_dep_delay = round(mean(dep_delay), 2),
median_dep_delay = round(median(dep_delay), 2),
total_flights = n()
) %>%
arrange(day_of_week)
colnames(delay_by_day) <- c("Thứ trong tuần",
"Độ trễ khởi hành trung bình (phút)",
"Độ trễ khởi hành trung vị (phút)",
"Số chuyến bay")
kable(delay_by_day,
caption = "**Thống kê độ trễ khởi hành theo thứ trong tuần**",
row.names = FALSE, align = "lccc")
| Thứ trong tuần | Độ trễ khởi hành trung bình (phút) | Độ trễ khởi hành trung vị (phút) | Số chuyến bay |
|---|---|---|---|
| 1 | 13.81 | -2 | 158769 |
| 2 | 14.06 | -3 | 144978 |
| 3 | 7.87 | -3 | 150363 |
| 4 | 7.84 | -3 | 145937 |
| 5 | 11.75 | -2 | 143644 |
| 6 | 11.96 | -2 | 123143 |
| 7 | 13.39 | -2 | 142456 |
Giải thích:
(1): tạo biến mới tên delay_by_day từ bộ dữ liệu flight_data_no_outlier.
(2): nhóm dữ liệu theo ngày trong tuần để tính toán riêng cho từng nhóm.
(3)-(7): tổng hợp các chỉ tiêu thống kê trong từng nhóm: độ trễ khởi hành trung bình, độ trễ khởi hành trung vị, tổng số chuyến bay.
(8)-(12): sắp xếp dữ liệu theo thứ tự ngày trong tuần từ 1 đến 7 và đặt lại tên cột bằng tiếng Việt.
(13)-(15): hiển thị bảng dưới dạng bảng đẹp và có chú thích trong R Markdown.
Nhận xét: Độ trễ khởi hành trung bình từ 7,84 đến 14,06 phút, trung vị khoảng –2 đến –3 phút cho thấy đa số chuyến bay khởi hành đúng giờ hoặc sớm nhẹ. Các ngày thứ hai, thứ ba và chủ nhật có độ trễ cao, thứ tư và thứ năm diễn ra ổn định hơn.
speed_by_day <- flight_data_no_outlier %>%
mutate(Thứ = recode(day_of_week,
`1` = "Thứ Hai", `2` = "Thứ Ba",
`3` = "Thứ Tư", `4` = "Thứ Năm",
`5` = "Thứ Sáu", `6` = "Thứ Bảy", `7` = "Chủ Nhật")) %>%
group_by(Thứ) %>%
summarise(`Tốc độ trung bình (mph)` = round(mean(speed_mph), 2)) %>%
mutate(Thứ = factor(Thứ,
levels = c("Thứ Hai", "Thứ Ba",
"Thứ Tư", "Thứ Năm",
"Thứ Sáu", "Thứ Bảy",
"Chủ Nhật"))) %>%
arrange(Thứ)
kable(
speed_by_day, align = "lc",
caption = "**Tốc độ trung bình theo ngày trong tuần**")
| Thứ | Tốc độ trung bình (mph) |
|---|---|
| Thứ Hai | 408.20 |
| Thứ Ba | 407.28 |
| Thứ Tư | 405.99 |
| Thứ Năm | 407.63 |
| Thứ Sáu | 407.45 |
| Thứ Bảy | 409.53 |
| Chủ Nhật | 408.63 |
Giải thích:
(1)-(5): sử dụng bộ dữ liệu flight_data_no_outlier làm đầu vào và chuyển giá trị số của biến day_of_week thành tên ngày tương ứng.
(6)-(7): nhóm dữ liệu theo từng ngày trong tuần và tính tốc độ bay trung bình của mỗi nhóm và làm tròn đến 2 chữ số thập phân.
(8)-(12): chuyển biến Thứ sang kiểu factor và sắp xếp theo thứ tự logic từ Thứ Hai đến Chủ Nhật.
(13)-(16): đảm bảo bảng kết quả hiển thị theo đúng thứ tự trong tuần và có tiêu đề.
Nhận xét: Tốc độ bay trung bình dao động từ 405,99 đến 409,53 mph cho thấy hiệu suất vận hành ổn định giữa các ngày trong tuần. Tốc độ cao nhất vào Thứ Bảy (409,53 mph) và thấp nhất vào Thứ Tư (405,99 mph) nhưng chênh lệch không đáng kể. Qua đó phản ánh điều kiện khai thác đồng đều và ít biến động theo ngày.
speed_summary <- flight_data_no_outlier %>%
group_by(op_unique_carrier) %>%
summarise(
`Tốc độ trung bình (mph)` = round(mean(speed_mph), 2),
`Số chuyến bay` = n()
) %>%
rename(`Hãng hàng không` = op_unique_carrier) %>%
arrange(desc(`Tốc độ trung bình (mph)`))
kable(
speed_summary, align = "lcc",
caption = "**Tốc độ trung bình của các hãng hàng không**")
| Hãng hàng không | Tốc độ trung bình (mph) | Số chuyến bay |
|---|---|---|
| AS | 438.89 | 30255 |
| G4 | 435.66 | 16369 |
| UA | 433.27 | 107441 |
| F9 | 428.54 | 27544 |
| B6 | 428.18 | 37060 |
| NK | 426.18 | 39048 |
| AA | 422.48 | 147210 |
| DL | 421.25 | 141543 |
| WN | 411.19 | 211567 |
| MQ | 376.30 | 38334 |
| 9E | 365.72 | 31053 |
| OO | 361.98 | 100015 |
| OH | 361.06 | 28685 |
| YX | 360.55 | 41396 |
| HA | 357.40 | 11770 |
Giải thích:
(1)-(2): sử dụng bộ dữ liệu flight_data_no_outlier làm đầu vào và nhóm dữ liệu theo từng hãng hàng không.
(3)-(6): tổng hợp tốc độ trung bình của mỗi hãng được làm tròn đến 2 chữ số thập phân và tổng số chuyến bay của từng hãng.
(7)-(8): đổi tên cột sang “Hãng hàng không” và sắp xếp giảm dần theo tốc độ trung bình.
(9)-(11): hiển thị bảng kết quả gọn gàng và có chú thích.
Nhận xét: Tốc độ trung bình giữa các hãng hàng không dao động từ 357,40 đến 438,89 mph. Các hãng AS, G4, UA, F9 có tốc độ trung bình cao (>425 mph) phản ánh việc khai thác các đường bay dài và ổn định hơn trong khi HA, YX, OO, 9E thấp hơn (<370 mph) vì chủ yếu bay ngắn, nội địa.
carrier_delay <- flight_data_no_outlier %>%
group_by(op_unique_carrier) %>%
summarise(
avg_depdelay = round(mean(dep_delay), 2),
avg_arrdelay = round(mean(arr_delay), 2)
) %>%
arrange(desc(avg_depdelay))
colnames(carrier_delay) <- c("Hãng bay",
"Độ trễ khởi hành trung bình (phút)",
"Độ trễ đến trung bình (phút)")
kable(carrier_delay,
caption = "**Trung bình độ trễ khởi hành và đến theo hãng bay**",
row.names = FALSE, align = "lcc")
| Hãng bay | Độ trễ khởi hành trung bình (phút) | Độ trễ đến trung bình (phút) |
|---|---|---|
| AA | 16.66 | 12.19 |
| B6 | 16.60 | 10.17 |
| OO | 14.51 | 9.31 |
| F9 | 14.24 | 9.21 |
| NK | 13.38 | 7.43 |
| G4 | 12.61 | 7.54 |
| UA | 11.63 | 4.59 |
| OH | 11.29 | 6.43 |
| 9E | 10.12 | 2.06 |
| WN | 10.05 | 3.70 |
| AS | 9.42 | 4.22 |
| HA | 9.13 | 9.12 |
| MQ | 9.05 | 5.51 |
| DL | 8.01 | 0.22 |
| YX | 2.34 | -5.47 |
Giải thích:
(1)-(2): gọi bộ dữ liệu flight_data_no_outlier làm đầu vào và nhóm dữ liệu theo từng hãng hàng không.
(3)-(6): tính độ trễ khởi hành trung bình và độ trễ đến trung bình, làm tròn đến 2 chữ số thập phân.
(7): sắp xếp giảm dần theo độ trễ khởi hành trung bình.
(8)-(10): đặt lại tên cột bằng tiếng Việt để hiển thị rõ ý nghĩa trong bảng.
(11)-(13): hiển thị bảng kết quả gọn gàng và có chú thích.
Nhận xét: Hãng AA có độ trễ trung bình lớn nhất ở hai giai đoạn cất cánh và hạ cánh cho thấy tình trạng chậm chuyến xảy ra thường xuyên. Ngược lại, hãng YX có độ trễ trung bình thấp nhất cho thấy khả năng duy trì lịch trình cất cánh đúng giờ tốt nhất.
delay_by_period <- flight_data_no_outlier %>%
group_by(day_period) %>%
summarise(
`Trễ khởi hành trung bình (phút)` = round(mean(dep_delay), 2),
`Trễ đến trung bình (phút)` = round(mean(arr_delay), 2)
) %>%
arrange(day_period) %>%
rename(`Thời điểm trong ngày` = day_period)
kable(delay_by_period, align = "lcc",
caption = "**Độ trễ trung bình theo thời điểm trong ngày**")
| Thời điểm trong ngày | Trễ khởi hành trung bình (phút) | Trễ đến trung bình (phút) |
|---|---|---|
| Afternoon | 6.60 | 0.98 |
| Evening | 10.71 | 4.33 |
| Morning | -1.10 | -7.02 |
| Night | 17.18 | 11.04 |
Giải thích:
(1)-(2): gọi bộ dữ liệu flight_data_no_outlier để làm nguồn phân tích và nhóm dữ liệu theo thời điểm trong ngày.
(3)-(6): tính độ trễ khởi hành trung bình và độ trễ khi đến trung bình.
(7)-(8): sắp xếp kết quả theo thứ tự thời điểm trong ngày và đổi tên cột day_period thành “Thời điểm trong ngày”.
(9)-(10): trình bày bảng có tiêu đề và căn chỉnh.
Nhận xét: Buổi sáng có độ trễ âm cho thấy chuyến bay thường đến sớm. Buối chiều có độ trễ nhẹ khi khởi hành nhưng vẫn duy trì thời gian ổn định. Buổi tối và ban đêm có độ trễ cao nhất, đặc biệt là vào ban đêm do ảnh hưởng dây chuyền của các chuyến bay trong ngày.
origin_time_stats <- flight_data_no_outlier %>%
group_by(origin_city_name) %>%
summarise(
total_flights = n(),
min_time = round(min(actual_elapsed_time), 2),
max_time = round(max(actual_elapsed_time), 2),
mean_time = round(mean(actual_elapsed_time), 2),
median_time = round(median(actual_elapsed_time), 2)
) %>%
arrange(desc(total_flights))
colnames(origin_time_stats) <- c("Thành phố khởi hành",
"Tổng số chuyến bay",
"Thời gian bay ngắn nhất (phút)",
"Thời gian bay dài nhất (phút)",
"Thời gian bay trung bình (phút)",
"Thời gian bay trung vị (phút)")
kable(head(origin_time_stats, 10),
caption = "**Thống kê thời gian bay theo thành phố khởi hành**",
row.names = FALSE, align = "lccccc")
| Thành phố khởi hành | Tổng số chuyến bay | Thời gian bay ngắn nhất (phút) | Thời gian bay dài nhất (phút) | Thời gian bay trung bình (phút) | Thời gian bay trung vị (phút) |
|---|---|---|---|---|---|
| Atlanta, GA | 49667 | 32 | 654 | 121.62 | 105 |
| Chicago, IL | 47465 | 30 | 617 | 141.56 | 126 |
| Dallas/Fort Worth, TX | 44431 | 33 | 604 | 136.71 | 133 |
| Denver, CO | 42461 | 28 | 534 | 140.58 | 137 |
| New York, NY | 41879 | 41 | 781 | 175.27 | 158 |
| Charlotte, NC | 30470 | 31 | 409 | 122.91 | 106 |
| Phoenix, AZ | 29974 | 36 | 475 | 146.27 | 132 |
| Washington, DC | 28839 | 37 | 718 | 142.64 | 122 |
| Las Vegas, NV | 27791 | 43 | 469 | 144.03 | 135 |
| Los Angeles, CA | 27741 | 33 | 458 | 185.93 | 172 |
Giải thích:
(1)-(2): gọi bộ dữ liệu flight_data_no_outlier làm đầu vào và nhóm dữ liệu theo tên thành phố khởi hành.
(3)-(9): tổng hợp tổng số chuyến bay, thời gian ngắn nhất và dài nhất, thời gian trung bình và trung vị.
(10)-(16): sắp xếp giảm dần theo số chuyến bay và đặt lại tên cột.
(17)-(19): hiển thị 10 thành phố có số chuyến bay khởi hành cao nhất.
Nhận xét: Atlanta, Chicago, Dallas/Fort Worth có số chuyến bay cao nhất, giữ vai trò trung tâm trung chuyển. Los Angeles và New York có thời gian bay trung bình dài nhất, Charlotte và Atlanta có chuyến bay ngắn hơn phản ánh sự đa dạng về cự ly khai thác giữa các sân bay lớn.
delay_by_distance <- flight_data_no_outlier %>%
mutate(`Nhóm khoảng cách` = case_when(
distance < 500 ~ "Ngắn",
distance >= 500 & distance < 1000 ~ "Trung bình",
distance >= 1000 & distance < 1500 ~ "Dài",
TRUE ~ "Rất dài"
)) %>%
mutate(`Nhóm khoảng cách` = factor(`Nhóm khoảng cách`,
levels = c("Rất dài", "Dài",
"Trung bình", "Ngắn"))) %>%
group_by(`Nhóm khoảng cách`) %>%
summarise(`Trễ khởi hành trung bình (phút)` = round(mean(dep_delay), 2),
`Trễ đến trung bình (phút)` = round(mean(arr_delay), 2)
) %>%
arrange(`Nhóm khoảng cách`)
kable(delay_by_distance, align = "lcc",
caption = "**Độ trễ trung bình theo nhóm khoảng cách bay**")
| Nhóm khoảng cách | Trễ khởi hành trung bình (phút) | Trễ đến trung bình (phút) |
|---|---|---|
| Rất dài | 12.11 | 3.35 |
| Dài | 13.02 | 6.75 |
| Trung bình | 11.74 | 6.09 |
| Ngắn | 10.25 | 4.96 |
Giải thích:
(1): sử dụng bộ dữ liệu flight_data_no_outlier để làm đầu vào.
(2)-(7): phân loại các chuyến bay theo khoảng cách: Dưới 500 dặm gán “Ngắn”, 500 đến 1000 dặm gán “Trung bình”, 1000 đến 1500 dặm gán “Dài”, trên 1500 dặm gán “Rất dài”.
(8)-(11): chuyển cột “Nhóm khoảng cách” thành biến factor.
(12)-(15): tính trễ khởi hành và trễ đến trung bình theo từng loại khoảng cách và sắp xếp theo thứ tự nhóm khoảng cách.
(16)-(17): hiển thị bảng có chú thích và định dạng.
Nhận xét: Bảng cho thấy độ trễ trung bình tăng theo độ dài quãng đường bay. Các chuyến bay ngắn có mức trễ thấp nhất, đường bay dài và rất dài có độ trễ cao hơn.
flight_diff_stats <- flight_data_no_outlier %>%
mutate(time_diff = actual_elapsed_time - crs_elapsed_time) %>%
group_by(op_unique_carrier) %>%
summarise(total_flights = n(),
mean_diff = round(mean(time_diff), 2),
median_diff = round(median(time_diff), 2),
min_diff = round(min(time_diff), 2),
max_diff = round(max(time_diff), 2)
) %>%
arrange(desc(mean_diff))
colnames(flight_diff_stats) <- c("Hãng hàng không",
"Tổng số chuyến bay",
"Chênh lệch trung bình (phút)",
"Chênh lệch trung vị (phút)",
"Chênh lệch nhỏ nhất (phút)",
"Chênh lệch lớn nhất (phút)")
kable(flight_diff_stats,
caption = "Chênh lệch thời gian bay thực tế so với kế hoạch theo hãng hàng không",
row.names = FALSE, align = "lccccc")
| Hãng hàng không | Tổng số chuyến bay | Chênh lệch trung bình (phút) | Chênh lệch trung vị (phút) | Chênh lệch nhỏ nhất (phút) | Chênh lệch lớn nhất (phút) |
|---|---|---|---|---|---|
| HA | 11770 | -0.01 | 0.0 | -54 | 109 |
| MQ | 38334 | -3.55 | -5.5 | -58 | 191 |
| AA | 147210 | -4.47 | -6.0 | -82 | 205 |
| OH | 28685 | -4.86 | -7.0 | -54 | 265 |
| F9 | 27544 | -5.02 | -7.0 | -62 | 173 |
| G4 | 16369 | -5.07 | -7.0 | -62 | 187 |
| OO | 100015 | -5.20 | -7.0 | -133 | 343 |
| AS | 30255 | -5.21 | -6.0 | -71 | 211 |
| NK | 39048 | -5.95 | -8.0 | -64 | 174 |
| WN | 211567 | -6.36 | -7.0 | -68 | 292 |
| B6 | 37060 | -6.43 | -9.0 | -78 | 167 |
| UA | 107441 | -7.04 | -8.0 | -79 | 252 |
| DL | 141543 | -7.80 | -9.0 | -87 | 168 |
| YX | 41396 | -7.83 | -10.0 | -773 | 500 |
| 9E | 31053 | -8.06 | -10.0 | -56 | 134 |
Giải thích:
(1): gọi bộ dữ liệu flight_data_no_outlier làm đầu vào.
(2): tạo biến mới time_diff bằng hiệu giữa actual_elapsed_time và crs_elapsed_time.
(3): nhóm dữ liệu theo hãng hàng không.
(4)-(10): tổng hợp tổng số chuyến bay, chênh lệch trung bình, chênh lệch trung vị, chênh lệch nhỏ nhất, chênh lệch lớn nhất và sắp xếp giảm dần theo chênh lệch trung bình.
(11)-(16): đổi tên cột sang tiếng Việt.
(17)-(19): trình bày bảng kết quả có chú thích, căn lề và định dạng rõ ràng.
Nhận xét: Hầu hết hãng có chênh lệch thời gian âm, tức bay nhanh hơn kế hoạch. Các hãng 9E, YX, DL đạt hiệu suất cao (–7 đến –8 phút) trong khi HA gần như không sai lệch (–0,01 phút) cho thấy dự đoán chính xác.
delay_summary <- flight_data_no_outlier %>%
mutate(weekend_flight = ifelse(weekend_flight == 1,
"Cuối tuần",
"Ngày thường")) %>%
group_by(weekend_flight) %>%
summarise(mean_dep_delay = round(mean(dep_delay), 2),
mean_arr_delay = round(mean(arr_delay), 2),
sd_dep_delay = round(sd(dep_delay), 2),
sd_arr_delay = round(sd(arr_delay), 2),
n = n())
colnames(delay_summary) <- c("Loại ngày",
"Trễ khởi hành trung bình",
"Trễ đến trung bình",
"Độ lệch chuẩn khởi hành",
"Độ lệch chuẩn đến",
"Số chuyến")
kable(delay_summary,
caption = "**Độ trễ trung bình giữa chuyến bay ngày thường và cuối tuần**",
align = "lccccc")
| Loại ngày | Trễ khởi hành trung bình | Trễ đến trung bình | Độ lệch chuẩn khởi hành | Độ lệch chuẩn đến | Số chuyến |
|---|---|---|---|---|---|
| Cuối tuần | 12.73 | 6.95 | 57.98 | 60.57 | 265599 |
| Ngày thường | 11.09 | 4.97 | 55.59 | 58.46 | 743691 |
Giải thích:
(1): gọi dữ liệu flight_data_no_outlier làm đầu vào.
(2)-(4): chuyển giá trị của biến weekend_flight từ 1–0 sang “Cuối tuần” và “Ngày thường”.
(5)-(10): nhóm dữ liệu lại theo loại ngày và tổng hợp độ trễ trung bình khi khởi hành và khi đến, độ lệch chuẩn khi khởi hành và khi đến, tổng số chuyến bay.
(11)-(19): đổi tên cột sang tiếng Việt và hiển thị bảng kết quả có chú thích và căn chỉnh rõ ràng.
Nhận xét: Chuyến bay cuối tuần có độ trễ cao hơn so với ngày thường, độ trễ khởi hành trung bình 12.73 phút và trễ khi đến 6.95 phút. Độ lệch chuẩn lớn hơn cũng phản ánh mức độ biến động cao hơn vào cuối tuần trong khi ngày thường ổn định hơn về thời gian bay.
Trước khi tiến hành trực quan hóa dữ liệu, ta cần cài đặt và kích hoạt một số gói thư viện hỗ trợ đồ họa trong R.
library(ggplot2)
library(showtext)
showtext_auto()
knitr::opts_chunk$set(dev = "cairo_pdf")
theme_set(theme_minimal(base_family = "Times New Roman"))
Giải thích:
(1): nạp gói vẽ đồ thị.
(2)-(3): hiển thị đúng tiếng Việt và font Unicode trong biểu đồ.
(4): thiết lập hệ thống xuất hình ảnh chống lỗi font khi in ra PDF.
(5): chọn phong cách tối giản và font Times New Roman làm mặc định cho toàn bộ biểu đồ.
library(scales)
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
options(bitmapType = "cairo", scipen = 999)
mu <- mean(flight_data_no_outlier$distance, na.rm = TRUE)
md <- median(flight_data_no_outlier$distance, na.rm = TRUE)
dens <- stats::density(flight_data_no_outlier$distance, na.rm = TRUE)
y_max <- max(dens$y, na.rm = TRUE)
x_rng <- range(flight_data_no_outlier$distance, na.rm = TRUE)
x_pad <- diff(x_rng) * 0.015
ggplot(flight_data_no_outlier, aes(x = distance)) +
geom_density(fill = "#FFB74D", alpha = 0.55, linewidth = 0.6, color = "black") +
geom_vline(xintercept = mu, color = "red", linetype = "dashed", linewidth = 0.7) +
geom_vline(xintercept = md, color = "blue", linetype = "dotted", linewidth = 0.7) +
annotate("text",
x = mu + x_pad, y = y_max * 0.88,
label = "Mean", color = "red", size = 3.8, fontface = "bold",
family = "TimesVN") +
annotate("text",
x = md - x_pad, y = y_max * 0.78,
label = "Median", color = "blue", size = 3.8, fontface = "bold",
family = "TimesVN") +
labs(
title = "Mật độ phân bố quãng đường bay",
x = "Khoảng cách (dặm)", y = "Mật độ") +
coord_cartesian(clip = "off") +
theme(
plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
axis.title = element_text(face = "bold", size = 12),
axis.text = element_text(face = "bold", size = 11),
plot.margin = margin(10, 20, 10, 10))
Giải thích:
(1)-(5): nạp các gói hỗ trợ định dạng và hiển thị tiếng Việt, thiết lập font Times New Roman, bật hệ thống Cairo để đảm bảo biểu đồ không lỗi font khi xuất ra PDF và loại bỏ ký hiệu khoa học (e+) trong số liệu.
(6)-(11): tính các thông số mô tả của biến distance, xác định giới hạn trục và vị trí thích hợp để gắn nhãn “Mean” và “Median”.
(12)-(15): khởi tạo biểu đồ ggplot() để vẽ đường mật độ phân bố với màu cam nhạt, viền đen và vẽ đường đỏ nét đứt biểu diễn trung bình, đường xanh nét chấm biểu diễn trung vị.
(16)-(23): ghi chú nhãn “Mean” và “Median” lên đồ thị, điều chỉnh vị trí hiển thị bằng các tham số tọa độ.
(24)-(28): tùy chỉnh thang trục X và Y, định dạng số theo chuẩn kế toán và mở rộng khoảng trống để tránh che nhãn.
Nhận xét: Đường trung bình nằm lệch phải so với trung vị chứng tỏ phân bố lệch phải, cho thấy phần lớn các chuyến bay có khoảng cách ngắn dưới 1.000 dặm, chỉ có một số ít chuyến bay dài trên 2.000 dặm.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
table_dest <- flight_data_no_outlier %>%
group_by(dest, op_unique_carrier) %>%
summarise(`Số chuyến bay` = n(), .groups = "drop")
top_dest <- table_dest %>%
group_by(dest) %>%
summarise(Tổng_chuyến = sum(`Số chuyến bay`)) %>%
arrange(desc(Tổng_chuyến)) %>%
slice_head(n = 4)
dest_summary <- table_dest %>%
filter(dest %in% top_dest$dest) %>%
group_by(dest) %>%
mutate(Tỷ_trọng = `Số chuyến bay` / sum(`Số chuyến bay`) * 100) %>%
ungroup()
ggplot(dest_summary, aes(x = "", y = Tỷ_trọng, fill = op_unique_carrier)) +
geom_col(width = 1, color = "white", linewidth = 0.3) +
coord_polar(theta = "y", start = 0, clip = "off") +
facet_wrap(~ dest, ncol = 2, scales = "free") +
geom_text(aes(
label = ifelse(Tỷ_trọng >= 15, paste0(round(Tỷ_trọng, 1), "%"), "")),
position = position_stack(vjust = 0.5),
size = 3.5, color = "black", family = "TimesVN") +
scale_fill_manual(
name = "Hãng hàng không",
values = c(
"9E" = "#F4A261", "AA" = "#FFB6B9", "AS" = "#81C784",
"B6" = "#AEDFF7", "DL" = "#A8D1D1", "F9" = "#C3AED6",
"G4" = "#FFD275", "HA" = "#E6B0AA", "MQ" = "#B39DDB",
"NK" = "#FFF176", "OH" = "#A5D6A7", "OO" = "#F48FB1",
"UA" = "#90CAF9", "WN" = "#4DD0E1", "YX" = "#CE93D8")) +
labs(
title = "Tỷ trọng chuyến bay theo hãng hàng không tại 4 điểm đến phổ biến nhất",
fill = "Hãng hàng không") +
theme_void(base_family = "TimesVN") +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.7),
plot.subtitle = element_text(size = 11, color = "gray40", hjust = 0.7),
strip.text = element_text(face = "bold", size = 13),
legend.position = "left",
legend.direction = "vertical",
legend.box = "vertical",
legend.title = element_text(face = "bold", size = 10),
legend.text = element_text(size = 9),
panel.spacing = unit(1.8, "lines"),
plot.margin = margin(20, 20, 20, 20))
Giải thích:
(4)-(7): tạo bảng table_dest chứa số chuyến bay của từng hãng tại từng điểm đến bằng cách đếm (n()).
(8)-(11): tính tổng số chuyến bay của từng điểm đến và chọn 4 điểm đến có tần suất cao nhất.
(12)-(15): lấy 4 điểm đến phổ biến nhất để tính tỷ trọng (%) chuyến bay của từng hãng.
(16)-(24): khởi tạo biểu đồ với ggplot(); tạo biểu đồ tròn với 4 biểu đồ con, mỗi biểu đồ đại diện cho 1 điểm đến.
(25)-(32): gán màu cố định cho từng hãng hàng không.
Nhận xét: Biểu đồ cho thấy mức độ tập trung và cạnh tranh giữa các hãng hàng không khác nhau tùy từng sân bay. ATL và DFW đều có một hãng chiếm ưu thế vượt trội còn DEN và ORD có cơ cấu tỷ trọng cân bằng hơn.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
flight_origin3 <- flight_data_no_outlier %>%
filter(origin %in% c("JFK", "LGA", "EWR"))
mean_delay_data <- flight_origin3 %>%
group_by(origin) %>%
summarise(mean_delay = mean(arr_delay, na.rm = TRUE), .groups = "drop")
ggplot(flight_origin3, aes(x = arr_delay, fill = origin)) +
geom_histogram(binwidth = 70, color = "white", alpha = 0.8, boundary = 0) +
geom_vline(
data = mean_delay_data,
aes(xintercept = mean_delay, color = origin),
linewidth = 1,
linetype = "dashed",
show.legend = FALSE) +
facet_wrap(~origin, ncol = 3, scales = "free_y") +
scale_fill_manual(values = c(
"JFK" = "#81C784",
"LGA" = "#64B5F6",
"EWR" = "#FFD54F")) +
labs(
title = "Phân bố độ trễ đến theo từng thành phố xuất phát",
subtitle = "Biểu đồ thể hiện sự phân bố độ trễ và vị trí trung bình",
x = "Độ trễ đến (phút)",
y = "Tần suất (số chuyến bay)",
fill = "Sân bay xuất phát") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 16,
face = "bold", hjust = 0.5,
color = "#0D47A1"),
plot.subtitle = element_text(size = 11, color = "gray40", hjust = 0.5),
strip.text = element_text(size = 12, face = "bold"),
legend.position = "bottom",
legend.title = element_text(face = "bold"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 8, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dotted"),
panel.spacing = unit(1.2, "lines"),
plot.margin = margin(20, 20, 20, 20),
strip.background = element_blank())
Giải thích:
(4)-(5): lọc dữ liệu chỉ giữ lại 3 sân bay xuất phát chính là JFK, LGA và EWR.
(6)-(8): tính độ trễ đến trung bình cho từng sân bay để làm đường tham chiếu trên biểu đồ.
(9)-(16): tạo biểu đồ histogram hiển thị phân bố độ trễ đến cho từng sân bay: vẽ biểu đồ tần suất, tô màu khác nhau và thêm đường thẳng nét đứt biểu diễn giá trị trung bình độ trễ của từng sân bay.
(17)-(21): tạo 3 biểu đồ con, mỗi biểu đồ tương ứng một sân bay và gán màu cố định cho từng sân bay: JFK gán xanh lá, LGA gán xanh dương và EWR gán vàng.
Nhận xét: Cả ba biểu đồ đều có dạng phân bố lệch phải, phần lớn chuyến bay có độ trễ nhỏ hơn 100 phút cho thấy đa số chuyến bay đến đúng hoặc gần đúng giờ nhưng vẫn tồn tại một số ít chuyến trễ nặng kéo dài đến hơn 500–1000 phút.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
options(bitmapType = "cairo")
knitr::opts_chunk$set(dev = "cairo_pdf", fig.align = "center",
fig.width = 7, fig.height = 4.5, out.width = "85%")
theme_set(theme_minimal(base_family = "TimesVN"))
delay_summary <- flight_data_no_outlier %>%
mutate(delay_group = case_when(
dep_delay <= 0 ~ "Sớm hoặc đúng giờ",
dep_delay <= 15 ~ "Trễ nhẹ",
TRUE ~ "Trễ nặng")
) %>%
count(delay_group, name = "Số_chuyến_bay")
ggplot(delay_summary, aes(x = reorder(delay_group, -Số_chuyến_bay),
y = Số_chuyến_bay, fill = delay_group)) +
geom_col(width = 0.65, color = "white") +
geom_text(aes(label = comma(Số_chuyến_bay)),
vjust = -0.4, size = 4, fontface = "bold",
family = "TimesVN", color = "black") +
scale_fill_manual(values = c(
"Sớm hoặc đúng giờ" = "#81C784",
"Trễ nhẹ" = "#FFD54F",
"Trễ nặng" = "#E57373")) +
scale_y_continuous(
labels = comma,
expand = expansion(mult = c(0, 0.12))) +
labs(
title = "Số lượng chuyến bay theo nhóm độ trễ khởi hành",
x = "Nhóm độ trễ khởi hành",
y = "Số lượng chuyến bay") +
theme_minimal(base_family = "TimesVN") +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 15, hjust = 0.5, color = "#0D47A1"),
axis.title = element_text(face = "bold", size = 12),
axis.text.x = element_text(face = "bold", size = 12),
axis.text.y = element_text(face = "bold", size = 11),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dotted"),
plot.margin = margin(20, 20, 20, 20),
plot.background = element_blank())
Giải thích:
(6)-(13): tạo biến phân loại: arr_delay ≤ 0 phút gán “Sớm hoặc đúng giờ”, 1 đến 15 phút gán “Trễ nhẹ”, > 15 phút gán “Trễ nặng” và đếm số chuyến bay trong từng nhóm.
(14)-(19): tạo biểu đồ cột,thêm nhãn giá trị trên cột và sắp xếp nhóm theo tần suất giảm dần.
(20)-(23): gán màu sắc cho từng nhóm độ trễ: “Sớm hoặc đúng giờ” gán xanh lá, “Trễ nhẹ” gán màu vàng, “Trễ nặng” gán màu đỏ.
(24)-(26): tùy chỉnh trục Y hiển thị theo định dạng có dấu phẩy và thêm khoảng đệm trên đầu cột để tránh che nhãn.
Nhận xét: Biểu đồ cho thấy đa số chuyến bay khởi hành sớm hoặc đúng giờ, chiếm tỷ trọng cao nhất so với các nhóm còn lại. Số chuyến trễ nhẹ ít hơn đáng kể trong khi trễ nặng chiếm tỷ lệ rất nhỏ phản ánh hiệu quả vận hành tốt của hệ thống bay.
showtext_auto(); options(bitmapType = "cairo")
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
knitr::opts_chunk$set(
dev = "cairo_pdf",
fig.align = "center",
fig.width = 7, fig.height = 4.5,
out.width = "85%")
theme_set(theme_minimal(base_family = "TimesVN"))
arr_delay_summary <- flight_data_no_outlier %>%
mutate(arr_delay_group = case_when(
arr_delay <= 0 ~ "Sớm hoặc đúng giờ",
arr_delay <= 15 ~ "Trễ nhẹ",
TRUE ~ "Trễ nặng")
) %>%
count(arr_delay_group, name = "Số_chuyến_bay") %>%
mutate(arr_delay_group = factor(
arr_delay_group,
levels = c("Sớm hoặc đúng giờ", "Trễ nhẹ", "Trễ nặng")))
ggplot(arr_delay_summary, aes(x = reorder(arr_delay_group, -Số_chuyến_bay),
y = Số_chuyến_bay, fill = arr_delay_group)) +
geom_col(width = 0.65, color = "white") +
geom_text(aes(label = scales::comma(Số_chuyến_bay)),
vjust = -0.6, fontface = "bold", size = 4) +
scale_fill_manual(values = c(
"Sớm hoặc đúng giờ" = "#81C784",
"Trễ nhẹ" = "#FFD54F",
"Trễ nặng" = "#E57373")) +
scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.08))) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
axis.title = element_text(face = "bold"),
axis.text.x = element_text(face = "bold", size = 12)) +
labs(
title = "Số lượng chuyến bay theo nhóm độ trễ khi đến",
x = "Nhóm độ trễ khi đến",
y = "Số lượng chuyến bay")
Giải thích:
(9)-(18): tạo biến phân loại arr_delay_group: arr_delay ≤ 0 phút gán “Sớm hoặc đúng giờ”, 1 đến 15 phút gán “Trễ nhẹ” và > 15 gán “Trễ nặng” và đếm số chuyến bay trong từng nhóm.
(19)-(23): khởi tạo biểu đồ cột biểu diễn số lượng chuyến bay từng nhóm độ trễ và hiện thị giá trị cụ thể trên mỗi cột.
(24)-(27): gán màu sắc cho từng nhóm độ trễ: “Sớm hoặc đúng giờ” gán xanh lá, “Trễ nhẹ” gán màu vàng, “Trễ nặng” gán màu đỏ.
(28): cấu hình trục tung hiển thị định dạng có dấu phẩy ngăn cách hàng nghìn, tắt chú giải, căn giữa tiêu đề và tô đậm chữ.
(29)-(37): đặt tiêu đề và nhãn trục và tinh chỉnh giao diện.
NHận xét: Biểu đồ cho thấy đa số chuyến bay đến sớm hoặc đúng giờ với hơn 650 nghìn chuyến, nhóm trễ nhẹ và trễ nặng chỉ chiếm tỷ trọng nhỏ hơn lần lượt khoảng 162 nghìn và 195 nghìn chuyến, phản ánh hiệu suất điều phối và kiểm soát thời gian đến của các chuyến bay khá tốt.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
delay_mean <- flight_data_no_outlier %>%
summarise(
`Độ trễ khởi hành trung bình (phút)` = mean(dep_delay),
`Độ trễ khi đến trung bình (phút)` = mean(arr_delay)
) %>%
tidyr::pivot_longer(
cols = everything(),
names_to = "Loại độ trễ",
values_to = "Giá trị trung bình")
delay_mean <- delay_mean %>%
mutate(vitri = as.numeric(factor(`Loại độ trễ`)))
ggplot(delay_mean, aes(x = `Loại độ trễ`,
y = `Giá trị trung bình`,
fill = `Loại độ trễ`)) +
geom_col(width = 0.5, color = "black", alpha = 0.9) +
geom_text(aes(label = round(`Giá trị trung bình`, 1)),
vjust = -1.2, size = 4, fontface = "bold") +
geom_hline(yintercept = 0, color = "gray40",
linetype = "dashed", linewidth = 1) +
annotate("text", x = 1.5,
y = max(delay_mean$`Giá trị trung bình`) + 3,
label = "Trung bình độ trễ khởi hành cao hơn khi đến",
color = "darkgreen", fontface = "italic", size = 3.8) +
scale_fill_manual(values = c("#E8A0BF", "#A8D1D1")) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
expand_limits(y = max(delay_mean$`Giá trị trung bình`) + 5) +
labs(
title = "So sánh độ trễ trung bình giữa khởi hành và khi đến",
subtitle = "Biểu đồ thể hiện độ trễ trung bình của hai giai đoạn chuyến bay",
x = "Loại độ trễ",
y = "Thời gian trễ trung bình (phút)") +
theme(
plot.title = element_text(face = "bold",
size = 15,
hjust = 0.5),
plot.subtitle = element_text(size = 12,
color = "gray40",
hjust = 0.5),
axis.title = element_text(face = "bold"),
axis.text = element_text(face = "bold"),
legend.position = "none")
(4)-(13): tạo bảng delay_mean tính độ trễ khởi hành trung bình và độ trễ khi đến trung bình rồi chuyển hai cột độ trễ thành dạng dọc.
(14): tạo cột “vitri” để gán giá trị số thứ tự cho từng loại độ trễ.
(15)-(26): tạo biểu đồ: vẽ cột biểu diễn giá trị trung bình của từng loại độ trễ, hiển thị giá trị số trung bình ngay trên cột, hêm đường chuẩn ở mức 0 để dễ so sánh mức độ trễ và thêm chú thích trên biểu đồ.
(27)-(29): tùy chỉnh màu sắc cho độ trễ khởi hành và đến trung bình.
Nhận xét: Độ trễ khởi hành trung bình cao gần gấp đôi độ trễ khi đến cho thấy dù nhiều chuyến khởi hành muộn nhưng hãng bay đã bù thời gian trong chuyến, giảm ảnh hưởng đến giờ đến thực tế.
library(tidyr)
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
flight_data_no_outlier <- flight_data_no_outlier %>%
mutate(distance = as.numeric(distance))
delay_by_distance <- flight_data_no_outlier %>%
mutate(`Nhóm khoảng cách` = case_when(
distance < 500 ~ "Ngắn", distance < 1000 ~ "Trung bình",
distance < 1500 ~ "Dài", TRUE ~ "Rất dài"
)) %>%
group_by(`Nhóm khoảng cách`) %>%
summarise(
`Khởi hành` = mean(dep_delay),
`Khi đến` = mean(arr_delay)
) %>%
pivot_longer(cols = c(`Khởi hành`, `Khi đến`),
names_to = "Loại", values_to = "Trễ TB")
ggplot(delay_by_distance, aes(x = `Loại`, y = `Trễ TB`,
group = `Nhóm khoảng cách`,
color = `Nhóm khoảng cách`)) +
geom_line(linewidth = 1.2) +
geom_point(size = 3) +
geom_text(aes(
label = round(`Trễ TB`, 1),
hjust = case_when(
`Nhóm khoảng cách` == "Ngắn" &
`Loại` == "Khi đến" ~ 2.1,
`Loại` == "Khi đến" ~ 1.6,
TRUE ~ -0.4),
vjust = case_when(
`Nhóm khoảng cách` == "Trung bình" &
`Loại` == "Khởi hành" ~ 1.4,
TRUE ~ 0.4)),
fontface = "bold", size = 3.5) +
scale_color_brewer(palette = "Set2") +
labs(
title = "Độ trễ khởi hành và đến trung bình theo nhóm khoảng cách bay",
subtitle = "Biểu đồ slope thể hiện sự thay đổi giữa hai giai đoạn chuyến bay",
x = "Loại độ trễ",
y = "Thời gian trễ trung bình (phút)",
color = "Nhóm khoảng cách bay") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
axis.title = element_text(face = "bold"),
legend.title = element_text(size = 11, face = "bold"),
legend.text = element_text(size = 10, lineheight = 1.1),
legend.position = "bottom")
Giải thích:
(5)-(6): chuyển biến distance sang kiểu numeric.
(7)-(11): phân loại quãng đường bay thành 4 nhóm: Ngắn, Trung bình, Dài và Rất dài.
(12)-(18): tính độ trễ khởi hành và độ trễ đến trung bình cho từng nhóm và chuyển hai cột “Khởi hành”, “Khi đến” thành dạng dọc.
(19)-(36): xây dựng biểu đồ: nối và đánh dấu mức trễ trung bình của hai giai đoạn cho từng nhóm quãng đường, hiển thị giá trị cụ thể, căn chỉnh vị trí hợp lý để tránh chồng nhãn và sử dụng bảng màu “Set2” giúp phân biệt rõ các nhóm khoảng cách.
Nhận xét: Độ trễ khởi hành luôn cao hơn khi đến, đặc biệt ở chặng “Dài” và “Rất dài” cho thấy khả năng bù trễ hiệu quả hơn trên các hành trình dài, trong khi các chặng “Ngắn” và “Trung bình” ổn định hơn nhờ kiểm soát tốt thời gian.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_classic(base_family = "TimesVN"))
ggplot(flight_data_no_outlier, aes(x = schedule_diff)) +
geom_density(fill = "#90CAF9", alpha = 0.6, color = "#1565C0", linewidth = 1) +
geom_vline(xintercept = 0, color = "red", linetype = "dashed", linewidth = 0.8) +
labs(
title = "Phân bố chênh lệch thời gian bay thực tế và dự kiến",
subtitle = "Giá trị dương thể hiện bay lâu hơn dự kiến, giá trị âm là bay nhanh hơn",
x = "Chênh lệch thời gian (phút)",
y = "Mật độ xác suất") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 11, color = "gray40", hjust = 0.5),
axis.title = element_text(face = "bold"),
axis.text = element_text(face = "bold"))
Giải thích:
(4)-(6): khởi tạo ggplot() với biến schedule_diff là hiệu giữa thời gian bay thực tế và thời gian dự kiến. Vẽ đường mật độ thể hiện phân bố tần suất xác suất của chênh lệch thời gian bay với tô màu xanh dương nhạt, viền xanh đậm và đường tham chiếu tại 0 phút.
(7)-(11): đặt tiêu đề, phụ đề và nhãn trục.
Nhận xét: Đường cong tập trung quanh 0, hẹp và đối xứng cho thấy thời gian bay thực tế gần trùng với kế hoạch và chênh lệch lớn hiếm xảy ra.
library(tidyverse)
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
time_compare <- flight_data_no_outlier %>%
group_by(op_unique_carrier) %>%
summarise(
`Thời gian bay dự kiến (phút)` = mean(crs_elapsed_time, na.rm = TRUE),
`Thời gian bay thực tế (phút)` = mean(actual_elapsed_time, na.rm = TRUE),
.groups = "drop"
) %>%
drop_na() %>%
slice_max(rowMeans(across(-op_unique_carrier), na.rm = TRUE), n = 10) %>%
pivot_longer(-op_unique_carrier, names_to = "Loại thời gian", values_to = "Giá trị trung bình") %>%
mutate(op_unique_carrier = fct_reorder(op_unique_carrier, `Giá trị trung bình`, .fun = mean))
ggplot(time_compare, aes(x = op_unique_carrier, y = `Giá trị trung bình`, fill = `Loại thời gian`)) +
geom_col(position = position_dodge(0.8), width = 0.7, color = "grey50", linewidth = 0.4) +
geom_text(aes(label = round(`Giá trị trung bình`, 1)),
position = position_dodge(0.8), hjust = -0.2, size = 2.5, family = "TimesVN") +
scale_fill_manual(values = c("#90CAF9", "#FFB6B9")) +
coord_flip() +
labs(
title = "Top 10 hãng hàng không có thời gian bay trung bình cao nhất",
subtitle = "So sánh giữa thời gian dự kiến và thực tế (đơn vị: phút)",
x = "Hãng hàng không", y = "Thời gian trung bình (phút)", fill = "") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5, color = "#1A237E"),
plot.subtitle = element_text(size = 12, hjust = 0.5, color = "#424242"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 10, color = "#212121"),
legend.position = "top", legend.text = element_text(size = 11),
panel.grid.minor = element_blank(), panel.grid.major.y = element_blank())
Giải thích:
(1)-(4): nạp gói tidyverse và thiết lập hiển thị tiếng Việt bằng font Times New Roman và sử dụng theme_minimal() để tạo nền đồ thị đơn giản, dễ đọc khi in ra PDF.
(5)-(17): tính trung bình thời gian bay dự kiến và thực tế cho từng hãng hàng không, lọc ra 10 hãng có thời gian bay trung bình cao nhất và sắp xếp lại hãng bay theo thời gian trung bình giảm dần.
(18)-(27): vẽ biểu đồ ngang để so sánh 2 giá trị, thêm nhãn giá trị và gán màu xanh cho thời gian dự kiến, hồng cho thời gian thực tế.
Nhận xét: Biểu đồ cho thấy 10 hãng có thời gian bay trung bình cao nhất, trong đó AS, B6 và UA dẫn đầu. Đa số hãng có thời gian bay thực tế dài hơn dự kiến phản ánh ảnh hưởng của điều kiện khai thác và không lưu.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_light(base_family = "TimesVN"))
ggplot(flight_data_no_outlier,
aes(x = distance, y = air_time)) +
geom_hex(bins = 40) +
geom_smooth(method = "lm", color = "red", linewidth = 0.8) +
scale_fill_gradient(low = "#B2EBF2", high = "#01579B") +
labs(
title = "Mối tương quan giữa quãng đường và thời gian bay thực tế",
subtitle = "Biểu đồ Hexbin thể hiện mật độ điểm dữ liệu",
x = "Quãng đường bay (dặm)",
y = "Thời gian bay thực tế (phút)",
fill = "Mật độ") +
theme(plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, color = "gray40", hjust = 0.5),
axis.title = element_text(face = "bold"))
Giải thích:
(4)-(5): khởi tạo ggplot() với trục X là quãng đường bay và trục Y là thời gian bay thực tế.
(6)-(8): chia vùng dữ liệu thành 40 ô lục giác thể hiện mật độ các điểm dữ liệu từ xanh nhạt đến xanh đậm và thêm đường hồi quy tuyến tính.
Nhận xét: Biểu đồ cho thấy mối tương quan thuận mạnh giữa quãng đường và thời gian bay thực tế rằng các chuyến bay càng dài thì thời gian bay càng lớn, chứng tỏ dữ liệu có độ nhất quán cao giữa hai biến này.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
delay_pie <- flight_data_no_outlier %>%
mutate(
arr_delay_group = case_when(
arr_delay <= 0 ~ "Sớm hoặc đúng giờ",
arr_delay <= 15 ~ "Trễ nhẹ",
TRUE ~ "Trễ nặng"),
Cuoi_tuan = ifelse(weekend_flight == 1, "Cuối tuần", "Ngày thường")
) %>%
group_by(month, Cuoi_tuan, arr_delay_group) %>%
summarise(SL = n(), .groups = "drop") %>%
group_by(month, Cuoi_tuan) %>%
mutate(TiLe = SL / sum(SL))
ggplot(delay_pie, aes(x = "", y = TiLe, fill = arr_delay_group)) +
geom_col(width = 1, color = "white") +
coord_polar("y", start = 0) +
geom_text(
aes(label = scales::percent(TiLe, accuracy = 0.1)),
position = position_stack(vjust = 0.5),
size = 3, fontface = "bold") +
facet_grid(month ~ Cuoi_tuan, labeller = labeller(
month = c("1" = "Tháng 1", "2" = "Tháng 2"))) +
scale_fill_manual(values = c(
"Sớm hoặc đúng giờ" = "#81C784",
"Trễ nhẹ" = "#FFD54F",
"Trễ nặng" = "#E57373"),
name = "Nhóm độ trễ") +
labs(
title = "Tỷ lệ nhóm độ trễ khi đến theo tháng và trạng thái cuối tuần",
subtitle = "So sánh giữa ngày thường và cuối tuần trong 2 tháng đầu năm",
y = NULL, x = NULL) +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = -0.05),
plot.subtitle = element_text(size = 12, color = "gray40", hjust = -0.7),
legend.title = element_text(face = "bold"),
strip.text = element_text(face = "bold", size = 11),
axis.text = element_blank(),
panel.grid = element_blank())
Giải thích:
(4)-(15): tạo bảng dữ liệu delay_pie để phân loại độ trễ khi đến thành 3 nhóm: Sớm hoặc đúng giờ, Trễ nhẹ, Trễ nặng. Đồng thời tạo biến Cuoi_tuan để phân biệt chuyến bay cuối tuần với ngày thường và đếm số chuyến bay theo tháng, loại ngày, nhóm độ trễ. Trong đó, tính tỷ lệ (%) từng nhóm độ trễ trong mỗi nhóm tháng và loại ngày.
(16)-(22): khởi tạo ggplot() và vẽ biểu đồ tròn có hiển thị tỷ lệ phần trăm.
(23)-(24): chia biểu đồ theo tháng (1–2) và loại ngày.
(25)-(29): gán màu cho từng nhóm độ trễ: “Sớm hoặc đúng giờ” gán xanh lá, “Trễ nhẹ” gán vàng, “Trễ nặng” gán đỏ.
Nhận xét: Biểu đồ cho thấy tỷ lệ chuyến bay đúng giờ chiếm ưu thế, đặc biệt tăng từ 58–61% (tháng 1) lên 66–70% (tháng 2). Tuy nhiên, cuối tuần có tỷ lệ trễ cao hơn so với ngày thường do lưu lượng bay lớn hơn.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
flight_data_no_outlier <- flight_data_no_outlier %>%
mutate(hour = floor(dep_time / 100))
delay_by_hour <- flight_data_no_outlier %>%
group_by(hour) %>%
summarise(
`Độ trễ khởi hành TB (phút)` = mean(dep_delay),
`Độ trễ khi đến TB (phút)` = mean(arr_delay),
sd_dep = sd(dep_delay)
) %>%
mutate(
ymin = `Độ trễ khởi hành TB (phút)` - sd_dep,
ymax = `Độ trễ khởi hành TB (phút)` + sd_dep
) %>%
tidyr::pivot_longer(
cols = c(`Độ trễ khởi hành TB (phút)`, `Độ trễ khi đến TB (phút)`),
names_to = "Loại độ trễ",
values_to = "Giá trị trung bình"
)
ggplot(delay_by_hour, aes(x = hour, y = `Giá trị trung bình`, color = `Loại độ trễ`)) +
geom_ribbon(data = unique(delay_by_hour[, c("hour", "ymin", "ymax")]),
aes(x = hour, ymin = ymin, ymax = ymax),
fill = "#FFF59D", alpha = 0.4, inherit.aes = FALSE) +
geom_line(linewidth = 1.2) +
geom_point(size = 2.5) +
geom_text(
data = delay_by_hour %>%
group_by(`Loại độ trễ`) %>%
filter(`Giá trị trung bình` == max(`Giá trị trung bình`)) %>%
mutate(vjust_pos = ifelse(`Loại độ trễ` == "Độ trễ khởi hành TB (phút)", -1.4, 6)),
aes(label = paste0("Cao nhất: ", round(`Giá trị trung bình`, 1), " phút"),
vjust = vjust_pos),
fontface = "bold", color = "darkred", size = 3.5, show.legend = FALSE) +
scale_color_manual(values = c(
"Độ trễ khởi hành TB (phút)" = "#E57373",
"Độ trễ khi đến TB (phút)" = "#64B5F6")) +
scale_x_continuous(
breaks = seq(0, 23, by = 2),
labels = paste0(seq(0, 23, by = 2), "h"),
name = "Giờ trong ngày (0–23h)") +
scale_y_continuous(
labels = comma_format(big.mark = "."),
name = "Độ trễ trung bình (phút)",
expand = expansion(mult = c(0.05, 0.15))) +
labs(
title = "Độ trễ khởi hành và đến trung bình theo giờ trong ngày",
subtitle = "Biểu đồ thể hiện xu hướng biến thiên của độ trễ trong khung 24 giờ",
color = "Loại độ trễ") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, color = "gray40", hjust = 0.5),
legend.position = "bottom",
legend.title = element_text(face = "bold"))
Giải thích:
(5)-(12): tạo bảng dữ liệu delay_by_hour được trích xuất giờ khởi hành từ biến thời gian và tính độ trễ khởi hành trung bình, độ trễ khi đến trung bình, và độ lệch chuẩn theo từng giờ.
(13)-(16): xác định khoảng dao động ±1 độ lệch chuẩn của độ trễ khởi hành và chuyển hai cột độ trễ thành dạng dọc, đổi nhãn biến sang tiếng Việt.
(17)-(35): vẽ vùng màu vàng biểu diễn độ biến động, đường biểu diễn và các điểm trung bình cho từng giờ, gắn nhãn tại vị trí có độ trễ trung bình lớn nhất của từng loại.
(36)-(38): gán màu đỏ cho khởi hành và xanh cho khi đến.
(39)-(46): đặt nhãn trục X theo giờ (0–23h) và định dạng trục Y theo chuẩn số có dấu chấm ngăn cách hàng nghìn.
Nhận xét: Biểu đồ cho thấy độ trễ cao nhất vào khoảng 2–3h sáng, sau đó giảm mạnh và ổn định trong ngày rồi tăng nhẹ vào cuối buổi tối. Độ trễ khởi hành luôn cao hơn khi đến, phản ánh việc bù trễ trong quá trình bay.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
delay_weekend_month <- flight_data_no_outlier %>%
filter(month %in% c(1, 2)) %>%
group_by(month, weekend_flight) %>%
summarise(
`Độ trễ khởi hành TB (phút)` = mean(dep_delay),
`Độ trễ khi đến TB (phút)` = mean(arr_delay)
) %>%
pivot_longer(
cols = c(`Độ trễ khởi hành TB (phút)`, `Độ trễ khi đến TB (phút)`),
names_to = "Loại độ trễ",
values_to = "Giá trị trung bình"
) %>%
mutate(
`Trạng thái chuyến bay` = factor(weekend_flight,
levels = c(0, 1),
labels = c("Ngày thường", "Cuối tuần")))
ggplot(delay_weekend_month,
aes(x = `Trạng thái chuyến bay`,
y = `Giá trị trung bình`,
fill = `Loại độ trễ`)) +
geom_col(position = position_dodge(width = 0.7),
color = "black", width = 0.65) +
geom_text(aes(label = round(`Giá trị trung bình`, 1),
vjust = ifelse(month == 2 &
`Trạng thái chuyến bay` == "Ngày thường" &
`Loại độ trễ` == "Độ trễ khi đến TB (phút)",
-1.1, -0.4)),
position = position_dodge(width = 0.7),
size = 3.8, fontface = "bold") +
facet_wrap(~ month, ncol = 2,
labeller = labeller(month = c(`1` = "Tháng 1",
`2` = "Tháng 2"))) +
scale_fill_manual(
values = c(
"Độ trễ khởi hành TB (phút)" = "#FFB6B9",
"Độ trễ khi đến TB (phút)" = "#8AC6D1")) +
scale_y_continuous(
expand = expansion(mult = c(0, 0.15)),
name = "Độ trễ trung bình (phút)") +
labs(
title = "Độ trễ khởi hành và đến trung bình theo trạng thái chuyến bay",
subtitle = "So sánh giữa ngày thường và cuối tuần trong 2 tháng đầu năm",
x = "Trạng thái chuyến bay",
fill = "Loại độ trễ") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 11, color = "gray40", hjust = 0.5),
axis.title = element_text(face = "bold"),
axis.text.x = element_text(face = "bold", size = 11),
axis.text.y = element_text(size = 10),
legend.title = element_text(face = "bold"),
legend.position = "bottom",
panel.grid.minor = element_blank())
Giải thích:
(4)-(19): tạo bảng dữ liệu delay_weekend_month: lọc dữ liệu cho hai tháng đầu năm (1, 2), nhóm theo tháng và trạng thái chuyến bay (ngày thường/cuối tuần) sau đó tính độ trễ trung bình khi khởi hành và khi đến, gom hai cột độ trễ vào cùng một biến và đặt lại nhãn biến weekend_flight thành “Ngày thường” và “Cuối tuần”.
(20)-(42): vẽ các cột so sánh giữa hai loại độ trễ cho từng trạng thái chuyến bay có hiển thị giá trị trung bình phía trên cột, tô màu đỏ nhạt cho khởi hành, xanh cho khi đến.
Nhận xét: Biểu đồ cho thấy độ trễ giảm rõ từ tháng 1 sang tháng 2, trong đó cuối tuần trễ nhiều hơn ngày thường. Độ trễ khởi hành luôn cao hơn khi đến cho thấy các chuyến bay có xu hướng bù trễ trên không.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
speed_by_day <- flight_data_no_outlier %>%
group_by(day_of_week) %>%
summarise(Toc_do_tb = mean(speed_mph, na.rm = TRUE)) %>%
mutate(day_label = factor(day_of_week,
levels = 1:7,
labels =
c("Thứ 2", "Thứ 3", "Thứ 4",
"Thứ 5", "Thứ 6", "Thứ 7",
"Chủ nhật")))
max_point <- speed_by_day %>%
filter(Toc_do_tb == max(Toc_do_tb))
min_point <- speed_by_day %>%
filter(Toc_do_tb == min(Toc_do_tb))
mean_speed <- mean(speed_by_day$Toc_do_tb)
ggplot(speed_by_day, aes(x = day_label,
y = Toc_do_tb, group = 1)) +
geom_line(color = "#2196F3", linewidth = 1.3) +
geom_point(size = 3, color = "#0D47A1") +
geom_hline(yintercept = mean_speed,
linetype = "dashed", color = "red",
linewidth = 0.8) +
annotate("text",
x = 7.1, y = mean_speed + 0.18,
label = paste0("Mức tốc độ trung bình chung: ",
round(mean_speed, 1), " mph"),
color = "red", fontface = "bold",
size = 3.6, hjust = 1) +
geom_text(data = max_point,
aes(label = paste0("Cao nhất: ",
round(Toc_do_tb, 1), " mph")),
vjust = -1.2, fontface = "bold",
color = "darkgreen", size = 3.8) +
geom_text(data = min_point,
aes(label = paste0("Thấp nhất: ",
round(Toc_do_tb, 1), " mph")),
vjust = 2.2, fontface = "bold",
color = "orange", size = 3.8) +
scale_y_continuous(
labels = comma_format(big.mark = ","),
expand = expansion(mult = c(0.2, 0.2))) +
labs(
title = "Tốc độ trung bình của các chuyến bay theo thứ trong tuần",
subtitle = "Biểu đồ thể hiện sự thay đổi tốc độ bay trung bình giữa các ngày trong tuần",
x = "Thứ trong tuần",
y = "Tốc độ trung bình (mph)",
caption = "Nguồn: flight_data_no_outlier") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, color = "gray40", hjust = 0.5),
axis.title = element_text(face = "bold", size = 12),
axis.text = element_text(face = "bold", size = 11),
plot.caption = element_text(size = 9, hjust = 1))
Giải thích:
(4)-(12): tính tốc độ trung bình theo từng ngày trong tuần và gán nhãn tiếng Việt cho từng ngày.
(13)-(17): xác định ngày có tốc độ cao nhất và thấp nhất, đồng thời tính tốc độ trung bình chung để làm mốc tham chiếu.
(18)-(43): vẽ biểu đồ thể hiện biến động tốc độ bay trung bình qua các ngày và đường trung bình màu đỏ, nét đứt có ghi chú các giá trị cao nhất và thấp nhất.
Nhận xét: Biểu đồ cho thấy tốc độ bay trung bình ổn định giữa các ngày trong tuần dao động quanh 407–409 mph. Tốc độ cao nhất đạt 409,5 mph vào Thứ 7, thấp nhất là 406 mph vào Thứ 4. Đường đỏ thể hiện mức trung bình chung 407,8 mph cho thấy hiệu suất bay duy trì ổn định, không có biến động lớn theo ngày.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
options(bitmapType = "cairo")
theme_set(theme_classic(base_family = "TimesVN"))
delay_by_month <- flight_data_no_outlier %>%
group_by(month) %>%
summarise(`Độ trễ trung bình (phút)` =
mean(arr_delay, na.rm = TRUE)) %>%
arrange(month)
ggplot(delay_by_month, aes(x = month, y = `Độ trễ trung bình (phút)`)) +
geom_line(color = "#1565C0", linewidth = 1.3) +
geom_point(color = "#FF7043", size = 4) +
geom_text(
aes(label = round(`Độ trễ trung bình (phút)`, 1)),
nudge_y = 0.6,
size = 4,
family = "TimesVN",
fontface = "bold",
color = "#37474F") +
scale_x_continuous(
breaks = delay_by_month$month,
labels = paste("Tháng", delay_by_month$month)) +
labs(
title = "Xu hướng độ trễ trung bình theo tháng",
subtitle = "Quan sát sự thay đổi độ trễ bay trung bình (arr_delay) giữa tháng 1 và tháng 2",
x = "Tháng",
y = "Độ trễ trung bình (phút)",
caption = "Nguồn: flight_data_no_outlier") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text = element_text(size = 11),
axis.title = element_text(size = 12, face = "bold"),
plot.caption = element_text(size = 9, hjust = 1))
Giải thích:
(5)-(9): nhóm dữ liệu theo tháng, tính độ trễ đến trung bình cho từng tháng và sắp xếp các tháng theo thứ tự thời gian.
(10)-(22): biểu diễn xu hướng độ trễ trung bình theo thời gian, đánh dấu các điểm dữ liệu thực tế, hiển thị giá trị trung bình ngay trên từng điểm và gắn nhãn trục X theo dạng “Tháng 1”, “Tháng 2”.
Nhận xét: Biểu đồ cho thấy độ trễ trung bình giảm mạnh từ 10,2 phút ở tháng 1 xuống còn 0,5 phút ở tháng 2 cho thấy hiệu suất vận hành các chuyến bay được cải thiện đáng kể, có thể nhờ điều kiện thời tiết thuận lợi hơn và lịch khai thác ổn định hơn trong tháng 2.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
options(bitmapType = "cairo")
theme_set(theme_classic(base_family = "TimesVN"))
top10_carriers <- flight_data_no_outlier %>%
filter(!is.na(arr_delay), !is.na(op_unique_carrier)) %>%
group_by(op_unique_carrier) %>%
summarise(mean_arr_delay = mean(arr_delay, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(mean_arr_delay)) %>%
slice_head(n = 10)
top10_codes <- top10_carriers$op_unique_carrier
delay_top10 <- flight_data_no_outlier %>%
filter(op_unique_carrier %in% top10_codes) %>%
mutate(month = as.integer(month)) %>%
filter(!is.na(month), month >= 1, month <= 12) %>%
group_by(month, op_unique_carrier) %>%
summarise(`Độ trễ trung bình (phút)` = mean(arr_delay, na.rm = TRUE), .groups = "drop")
carrier_colors <- setNames(hue_pal()(length(top10_codes)), top10_codes)
ggplot(delay_top10, aes(x = month,
y = `Độ trễ trung bình (phút)`,
fill = op_unique_carrier)) +
geom_area(alpha = 0.85, color = "white", linewidth = 0.2) +
scale_fill_manual(values = carrier_colors, na.value = "#BDBDBD") +
scale_x_continuous(breaks = 1:12, labels = paste("Tháng", 1:12)) +
labs(
title = "Độ trễ trung bình theo tháng của 10 hãng bay có độ trễ đến cao nhất",
x = "Tháng",
y = "Độ trễ trung bình (phút)",
fill = "Hãng bay",
caption = "Nguồn: flight_data_no_outlier") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text = element_text(size = 11),
axis.title = element_text(size = 12, face = "bold"),
legend.position = "right",
legend.title = element_text(face = "bold"),
legend.text = element_text(size = 10),
plot.caption = element_text(size = 9, hjust = 1))
Giải thích:
(5)-(11): tạo bảng top10_carriers: lọc dữ liệu hợp lệ, nhóm theo hãng hàng không để tính độ trễ trung bình khi đến và sắp xếp giảm dần và chọn 10 hãng có độ trễ trung bình cao nhất.
(12)-(22): chuẩn bị dữ liệu delay_top10: giữ lại các hãng thuộc nhóm top 10, chuyển tháng sang số nguyên sau đó nhóm theo tháng và hãng bay để tính độ trễ trung bình (phút) cho từng hãng mỗi tháng.
(23)-(24): tạo bảng màu riêng cho từng hãng hàng không và vẽ biểu đồ vùng thể hiện diện tích độ trễ trung bình theo tháng, mỗi hãng là một lớp màu được hiển thị nhãn trục X theo dạng “Tháng 1”, “Tháng 2”.
Nhận xét: Tất cả các hãng đều có xu hướng giảm độ trễ mạnh từ tháng 1 sang tháng 2 cho thấy sự cải thiện về thời gian đến. AA, UA và DL là những hãng có độ trễ cao phản ánh quy mô khai thác lớn và dễ bị ảnh hưởng dây chuyền, ngược lại, G4, F9, MQ có mức độ trễ thấp hơn thể hiện hoạt động ổn định hơn.
library(lubridate)
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
flight_data_no_outlier <- flight_data_no_outlier %>%
mutate(date = dmy(fl_date))
delay_area <- flight_data_no_outlier %>%
group_by(date) %>%
summarise(`Độ trễ TB (phút)` = mean(arr_delay, na.rm = TRUE))
ggplot(delay_area, aes(x = date, y = `Độ trễ TB (phút)`)) +
geom_area(fill = "#90CAF9", alpha = 0.6) +
geom_line(color = "#1565C0", linewidth = 1) +
labs(
title = "Xu hướng độ trễ trung bình theo ngày (8 tuần đầu năm)",
x = "Ngày", y = "Độ trễ trung bình (phút)",
caption = "Nguồn: flight_data_no_outlier") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
axis.title = element_text(face = "bold"))
Giải thích:
(5)-(6): chuyển cột fl_date sang định dạng ngày theo chuẩn ngày/tháng/năm.
(7)-(9): nhóm dữ liệu theo ngày bay và tính độ trễ trung bình khi đến cho mỗi ngày.
(10)-(12): vẽ biểu đồ diện tích hiển thị vùng độ trễ theo thời gian và thêm đường xu hướng trung bình.
Nhận xét: Đầu tháng 1, độ trễ tăng mạnh và đạt đỉnh khoảng ngày 15-20 tháng 1 (40–50 phút). Từ cuối tháng 1 đến tháng 2, độ trễ giảm rõ rệt khi lưu lượng bay ổn định hơn. Giữa tháng 2 xuất hiện vài đỉnh nhỏ nhưng mức trễ vẫn thấp hơn tháng 1.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
bubble_data <- flight_data_no_outlier %>%
filter(!is.na(speed_mph), !is.na(distance)) %>%
group_by(op_unique_carrier) %>%
summarise(
`Tốc độ trung bình (mph)` = mean(speed_mph, na.rm = TRUE),
`Quãng đường trung bình (dặm)` = mean(distance, na.rm = TRUE),
Số_chuyến = n())
my_gradient_cool <- colorRampPalette(c(
"#E3F2FD", "#90CAF9", "#42A5F5", "#1E88E5", "#5E35B1",
"#7E57C2", "#9FA8DA", "#C5CAE9", "#E8EAF6", "#4A148C",
"#7B1FA2", "#AB47BC", "#BA68C8", "#CE93D8", "#F3E5F5"))(15)
ggplot(bubble_data, aes(x = reorder(op_unique_carrier, `Tốc độ trung bình (mph)`),
y = `Tốc độ trung bình (mph)`,
fill = `Tốc độ trung bình (mph)`)) +
geom_col(width = 0.6, color = "white") +
coord_flip() +
scale_fill_gradientn(colors = my_gradient_cool,
name = "Tốc độ trung bình (mph)") +
labs(
title = "TỐC ĐỘ TRUNG BÌNH CỦA CÁC HÃNG HÀNG KHÔNG",
x = "Hãng hàng không",
y = "Tốc độ trung bình (mph)",
fill = "Hãng") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
legend.position = "none")
Giải thích:
(5)-(10): nhóm dữ liệu theo hãng hàng không và tính tốc độ trung bình, quãng đường trung bình, số chuyến sau khi loại bỏ các giá trị thiếu.
(11)-(14): khai báo bảng màu my_gradient_cool gồm 15 tông xanh–tím.
(15)-(21): sắp xếp hãng theo tốc độ trung bình từ thấp đến cao, vẽ cột thể hiện giá trị tốc độ, xoay biểu đồ sang hướng ngang, áp dụng bảng màu gradient tông lạnh vào biểu đồ.
Nhận xét: Biểu đồ cho thấy AS, G4, UA, F9 có tốc độ trung bình cao nhất (trên 425 mph) phản ánh khai thác đường bay dài và ổn định, ngược lại, HA, YX, OO có tốc độ thấp hơn (khoảng 360–380 mph) do bay nội địa ngắn. Tóm lại, hãng bay đường dài đạt tốc độ cao hơn, còn hãng khu vực duy trì tốc độ thấp hơn nhưng ổn định.
library(ggbump)
rank_data <- flight_data_no_outlier %>%
group_by(month, op_unique_carrier) %>%
summarise(`Số chuyến bay` = n(), .groups = "drop") %>%
group_by(month) %>%
mutate(hang = rank(-`Số chuyến bay`)) %>%
filter(hang <= 8)
ggplot(rank_data, aes(x = month, y = hang, color = op_unique_carrier)) +
geom_bump(linewidth = 1.4, smooth = 8) +
geom_point(size = 3) +
scale_y_reverse(breaks = 1:8) +
scale_x_continuous(breaks = 1:12) +
labs(
title = "Thứ hạng số chuyến bay theo tháng",
subtitle = "Biểu đồ Bump Chart thể hiện vị trí của các hãng hàng không qua thời gian",
x = "Tháng", y = "Thứ hạng (1 = cao nhất)",
color = "Hãng hàng không") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
legend.position = "bottom")
Giải thích:
(1): nạp gói ggbump dùng để tạo biểu đồ Bump Chart.
(2)-(7): nhóm dữ liệu theo tháng và hãng bay, đếm số chuyến bay của từng hãng mỗi tháng, xếp hạng các hãng theo số chuyến bay giảm dần trong từng tháng và chỉ giữ lại 8 hãng có số chuyến bay nhiều nhất mỗi tháng.
(8)-(12): vẽ đường kết nối thứ hạng của từng hãng qua các tháng, đánh dấu vị trí từng hãng ở mỗi tháng, đảo trục Y để hạng 1 nằm trên cùng và hiển thị nhãn tháng 1 đến tháng 12.
Nhận xét: Thứ hạng hầu như không thay đổi giữa tháng 1 và tháng 2 cho thấy mức độ ổn định trong tần suất khai thác của các hãng lớn như WN, DL, AA và UA.
Tên bộ dữ liệu: Báo cáo tài chính Công ty Cổ phần Tập đoàn Đầu tư Địa ốc No Va (NVL).
Nguồn bộ dữ liệu: Tổng hợp từ Báo cáo tài chính hợp nhất cho năm của NVL được công bố công khai trên trang https://www.novaland.com.vn/.
Thông tin bộ dữ liệu: Bộ dữ liệu phản ánh tình hình tài chính của Công ty Cổ phần Tập đoàn Đầu tư Địa ốc No Va (NVL) giai đoạn Q1/2015 – Q1/2024. Dữ liệu được tổng hợp từ báo cáo tài chính hợp nhất thể hiện xu hướng biến động quy mô, cơ cấu vốn và hiệu quả kinh doanh của doanh nghiệp bất động sản này.
Mục đích lấy dữ liệu: Nghiên cứu phân tích xu hướng biến động tài chính của NVL qua các năm bằng cách tính toán và so sánh các chỉ số ROA, ROE, D/E và tỷ trọng tài sản. Đồng thời, xác định giai đoạn biến động mạnh về tài sản, vốn hoặc lợi nhuận và trực quan hóa dữ liệu để làm rõ mối quan hệ giữa các chỉ tiêu tài chính.
Bước tiếp theo sau khi xác định mục đích thu thập dữ liệu là nạp bộ dữ liệu thô vào R để bắt đầu quá trình phân tích.
library(readxl)
BCTC_NVL <- read_excel("C:/Users/TO UYEN/Downloads/BCTC_NVL.xlsx")
Giải thích:
(1): nạp gói readxl, cho phép đọc tệp Excel (.xlsx) trực tiếp vào R mà không cần chuyển đổi định dạng.
(2): đọc dữ liệu từ file Excel chứa báo cáo tài chính của NVL và gán vào biến BCTC_NVL.
Nhận xét: Việc nạp dữ liệu thành công là bước đầu quan trọng giúp kiểm tra cấu trúc và kiểu biến, đảm bảo dữ liệu sẵn sàng cho các bước xử lý, phân tích và trực quan hóa tiếp theo.
Sau khi đưa dữ liệu thô vào R, bước tiếp theo là tiến hành kiểm tra dữ liệu đã được nạp thành công hay chưa.
is.data.frame(BCTC_NVL)
## [1] TRUE
Giải thích: (1): kiểm tra dữ liệu có được nạp đúng dạng bảng (data frame) hay không. Nếu hàm trả về TRUE, bộ dữ liệu đưa vào là một data frame hợp lệ. Ngược lại, hàm trả về FALSE.
Nhận xét: Kết quả là TRUE, đảm bảo cấu trúc dữ liệu phù hợp cho các phân tích và xử lý sau này.
dim(BCTC_NVL)
## [1] 10 11
Giải thích: (1): dùng để kiểm tra kích thước của bộ dữ liệu: Giá trị đầu tiên là số hàng (quan sát), giá trị thứ hai là số cột (biến).
Nhận xét: Bộ dữ liệu có 10 quan sát và 11
biến.
names(BCTC_NVL)
## [1] "Năm" "Tài sản ngắn hạn"
## [3] "Tài sản dài hạn" "Nợ ngắn hạn"
## [5] "Nợ dài hạn" "Vốn chủ sở hữu"
## [7] "Lợi nhuận sau thuế" "Tài sản cố định hữu hình"
## [9] "Hàng tồn kho" "Doanh thu chưa thực hiện ngắn hạn"
## [11] "Chi phí trả trước dài hạn"
Giải thích: (1) dùng để hiển thị tên các biến trong bộ dữ liệu.
Nhận xét: Kết quả cung cấp danh sách tên biến nhằm làm nền tảng cho các bước mô tả, so sánh và mô hình hóa trong phân tích thống kê sau này.
nrow(BCTC_NVL)
## [1] 10
Giải thích: (1) hiển thị số lượng bản ghi (số năm).
Nhận xét: Số dòng phù hợp với số kỳ báo cáo đã thu thập; nếu thiếu dòng, có thể cần rà soát lại file Excel.
ncol(BCTC_NVL)
## [1] 11
Giải thích: (1) trả về số lượng biến (cột).
Nhận xét: Kết quả xác nhận rằng bộ dữ liệu gồm 11 biến — đúng như kế hoạch lựa chọn ban đầu.
kable(sapply(BCTC_NVL, typeof),
col.names = c("Tên biến" , "Kiểu dữ liệu"))
| Tên biến | Kiểu dữ liệu |
|---|---|
| Năm | double |
| Tài sản ngắn hạn | double |
| Tài sản dài hạn | double |
| Nợ ngắn hạn | double |
| Nợ dài hạn | double |
| Vốn chủ sở hữu | double |
| Lợi nhuận sau thuế | double |
| Tài sản cố định hữu hình | double |
| Hàng tồn kho | double |
| Doanh thu chưa thực hiện ngắn hạn | double |
| Chi phí trả trước dài hạn | double |
Giải thích:
(1)-(2): xác định kiểu dữ liệu của từng biến trong BCTC_NVL và hiển thị kết quả thành bảng gồm tên biến và kiểu dữ liệu.
Nhận xét: Các biến tài chính đều có kiểu double, có thể tính toán trực tiếp mà không cần chuyển đổi kiểu dữ liệu.
kable(t(head(BCTC_NVL, 5)))
| Năm | 2015 | 2016 | 2017 | 2018 | 2019 |
| Tài sản ngắn hạn | 18133289908529 | 30288729450391 | 41165965853502 | 50860944465153 | 71194821173128 |
| Tài sản dài hạn | 8437118726514 | 6238346263606 | 8300996138739 | 19051268698390 | 18784421425391 |
| Nợ ngắn hạn | 3354623721533 | 15011223881816 | 22658196187952 | 27969394567002 | 18809633988008 |
| Nợ dài hạn | 7120575498092 | 11468961695110 | 13552375300869 | 21482692110763 | 46708534778664 |
| Vốn chủ sở hữu | 6095209415418 | 10046890137071 | 13256390503420 | 20460126485778 | 24461073831847 |
| Lợi nhuận sau thuế | 550370777697 | 952449830514 | 2907218106652 | 6107694627582 | 8722828720589 |
| Tài sản cố định hữu hình | 60086312739 | 120180246302 | 281845599120 | 705600012062 | 698416074605 |
| Hàng tồn kho | 7201718027433 | 15795037614256 | 27136318547663 | 32833620893772 | 57209437130190 |
| Doanh thu chưa thực hiện ngắn hạn | 2300539353 | 2201411807 | 1974280808 | 1457601871 | 1677668051 |
| Chi phí trả trước dài hạn | 160651074570 | 288077446389 | 449352171677 | 414115027558 | 262799866843 |
Giải thích: (1) hiển thị 5 dòng đầu tiên trong bộ dữ liệu.
Nhận xét: Các cột hiển thị đúng định dạng, giá trị tiền tệ được nhập chuẩn, không xuất hiện ký tự lạ.
kable(t(tail(BCTC_NVL, 5)))
| Năm | 2020 | 2021 | 2022 | 2023 | 2024 |
| Tài sản ngắn hạn | 114203561614442 | 156048716497795 | 198114675000040 | 191154819021853 | 207831078798684 |
| Tài sản dài hạn | 30332784019580 | 45784830488255 | 59620201167981 | 50331560521272 | 29946901858972 |
| Nợ ngắn hạn | 31427343626571 | 49214630460474 | 78174120549026 | 87282658320119 | 107222351548398 |
| Nợ dài hạn | 81176854821744 | 111445603193607 | 134743025238830 | 108900871180603 | 83264604750644 |
| Vốn chủ sở hữu | 31932147185707 | 41173113331969 | 44817730380165 | 45302850042403 | 47291024358614 |
| Lợi nhuận sau thuế | 12051422037059 | 10707524273613 | 12888775711396 | 13494207570271 | 13281118742079 |
| Tài sản cố định hữu hình | 1101914150337 | 1345065108658 | 3853811931218 | 2331565433184 | 1875694928140 |
| Hàng tồn kho | 86867908152180 | 110159027675309 | 134957802212263 | 139096217236865 | 147027941663523 |
| Doanh thu chưa thực hiện ngắn hạn | 6629217351 | 685208573 | 435435329 | 1395098660 | 265182735 |
| Chi phí trả trước dài hạn | 419763171833 | 828185441183 | 1575118212493 | 1689485786703 | 1500140582061 |
Giải thích: (1) cho biết 5 quan sát ở cuối tập dữ liệu.
Nhận xét: Giúp xác nhận dữ liệu cập nhật đầy đủ cho các năm mới nhất và đảm bảo không bị thiếu quan sát cuối.
bien_giai_thich <- data.frame(
`Tên biến` = c(
"Nam",
"TaiSanNganHan",
"TaiSanDaiHan",
"NoNganHan",
"NoDaiHan",
"VonChuSoHuu",
"LNST",
"TSCD_HH",
"HangTonKho",
"DT_ChuaTH_NganHan",
"CP_TraTruoc_DaiHan"),
`Ý nghĩa` = c(
"Năm báo cáo tài chính.",
"Tài sản có thể chuyển đổi thành tiền trong 1 năm.",
"Tài sản sử dụng dài hạn trên 1 năm.",
"Nợ phải trả trong vòng 12 tháng.",
"Nợ có kỳ hạn trên 1 năm.",
"Phần vốn thuộc sở hữu cổ đông.",
"Lợi nhuận sau khi trừ thuế.",
"Giá trị tài sản cố định hữu hình.",
"Giá trị hàng hóa, vật tư tồn kho.",
"Doanh thu đã thu nhưng chưa ghi nhận.",
"Chi phí trả trước có thời gian sử dụng dài."),
check.names = FALSE)
kable(
bien_giai_thich,
caption = "**Tên và ý nghĩa của các biến trong bộ dữ liệu BCTC_NVL**")
| Tên biến | Ý nghĩa |
|---|---|
| Nam | Năm báo cáo tài chính. |
| TaiSanNganHan | Tài sản có thể chuyển đổi thành tiền trong 1 năm. |
| TaiSanDaiHan | Tài sản sử dụng dài hạn trên 1 năm. |
| NoNganHan | Nợ phải trả trong vòng 12 tháng. |
| NoDaiHan | Nợ có kỳ hạn trên 1 năm. |
| VonChuSoHuu | Phần vốn thuộc sở hữu cổ đông. |
| LNST | Lợi nhuận sau khi trừ thuế. |
| TSCD_HH | Giá trị tài sản cố định hữu hình. |
| HangTonKho | Giá trị hàng hóa, vật tư tồn kho. |
| DT_ChuaTH_NganHan | Doanh thu đã thu nhưng chưa ghi nhận. |
| CP_TraTruoc_DaiHan | Chi phí trả trước có thời gian sử dụng dài. |
Giải thích:
(1): tạo bảng mới để mô tả các biến.
(2)-(26): liệt kê tên biến và nêu ý nghĩa của từng biến.
(27)-(29): in bảng mô tả với tiêu đề rõ ràng phục vụ trình bày báo cáo.
Nhận xét: Bảng trên giúp định danh rõ ý nghĩa kinh tế của từng biến, đảm bảo người đọc hiểu nội dung và vai trò của các chỉ tiêu tài chính trong báo cáo NVL.
Kiểm tra xem trong toàn bộ bảng dữ liệu có tồn tại giá trị bị thiếu (NA) ở bất kỳ vị trí nào hay không:
sum(is.na(BCTC_NVL))
## [1] 0
Giải thích: (1) dùng để đếm tổng số ô bị thiếu dữ liệu trong toàn bộ bảng.
Nhận xét: Kết quả bằng 0 chứng tỏ dữ liệu của NVL hoàn chỉnh và không cần xử lý giá trị khuyết.
library(janitor)
BCTC_NVL <- BCTC_NVL %>% clean_names()
colnames(BCTC_NVL)
## [1] "nam" "tai_san_ngan_han"
## [3] "tai_san_dai_han" "no_ngan_han"
## [5] "no_dai_han" "von_chu_so_huu"
## [7] "loi_nhuan_sau_thue" "tai_san_co_dinh_huu_hinh"
## [9] "hang_ton_kho" "doanh_thu_chua_thuc_hien_ngan_han"
## [11] "chi_phi_tra_truoc_dai_han"
Giải thích:
(1): nạp gói janitor chuyên dùng để làm sạch và chuẩn hóa tên biến trong dữ liệu.
(2)-(3): chuyển tên biến của BCTC_NVL về dạng chữ thường nối bằng dấu gạch dưới và hiển thị danh sách tên cột mới sau khi đã được chuẩn hóa.
Nhận xét: Tên biến được thống nhất giúp thuận tiện khi phân tích và vẽ đồ thị.
sapply(BCTC_NVL, class)
## nam tai_san_ngan_han
## "numeric" "numeric"
## tai_san_dai_han no_ngan_han
## "numeric" "numeric"
## no_dai_han von_chu_so_huu
## "numeric" "numeric"
## loi_nhuan_sau_thue tai_san_co_dinh_huu_hinh
## "numeric" "numeric"
## hang_ton_kho doanh_thu_chua_thuc_hien_ngan_han
## "numeric" "numeric"
## chi_phi_tra_truoc_dai_han
## "numeric"
Giải thích: (1) xác định kiểu dữ liệu cho từng cột.
Nhận xét: Tất cả biến đều là numeric, sẵn sàng cho tính toán thống kê.
BCTC_NVL$nam <- as.factor(BCTC_NVL$nam)
Giải thích: (1) chuyển biến năm sang kiểu phân loại (factor).
Nhận xét: Biến “Nam” được mã hóa thành nhãn phân loại giúp dễ biểu diễn trên trục hoành.
sapply(BCTC_NVL, class)
## nam tai_san_ngan_han
## "factor" "numeric"
## tai_san_dai_han no_ngan_han
## "numeric" "numeric"
## no_dai_han von_chu_so_huu
## "numeric" "numeric"
## loi_nhuan_sau_thue tai_san_co_dinh_huu_hinh
## "numeric" "numeric"
## hang_ton_kho doanh_thu_chua_thuc_hien_ngan_han
## "numeric" "numeric"
## chi_phi_tra_truoc_dai_han
## "numeric"
Giải thích: (1) kiểm tra lại kiểu dữ liệu của từng biến sau khi chuyển đổi.
Nhận xét: Kết quả cho thấy biến “nam” đã chuyển sang kiểu factor, còn các biến tài chính khác vẫn là numeric.
Giải thích chung:
mutate(): tạo cột mới bằng tổng hai loại tài sản ngắn và dài hạn.
colnames(): giúp người phân tích xác định các biến có trong bộ dữ liệu.
BCTC_NVL <- BCTC_NVL %>%
mutate(tong_tai_san = tai_san_ngan_han + tai_san_dai_han)
colnames(BCTC_NVL)
## [1] "nam" "tai_san_ngan_han"
## [3] "tai_san_dai_han" "no_ngan_han"
## [5] "no_dai_han" "von_chu_so_huu"
## [7] "loi_nhuan_sau_thue" "tai_san_co_dinh_huu_hinh"
## [9] "hang_ton_kho" "doanh_thu_chua_thuc_hien_ngan_han"
## [11] "chi_phi_tra_truoc_dai_han" "tong_tai_san"
Nhận xét: Tổng tài sản” là chỉ tiêu cơ bản để tính các tỷ suất tài chính như ROA, D/E.
BCTC_NVL <- BCTC_NVL %>%
mutate(tong_no = no_ngan_han + no_dai_han)
colnames(BCTC_NVL)
## [1] "nam" "tai_san_ngan_han"
## [3] "tai_san_dai_han" "no_ngan_han"
## [5] "no_dai_han" "von_chu_so_huu"
## [7] "loi_nhuan_sau_thue" "tai_san_co_dinh_huu_hinh"
## [9] "hang_ton_kho" "doanh_thu_chua_thuc_hien_ngan_han"
## [11] "chi_phi_tra_truoc_dai_han" "tong_tai_san"
## [13] "tong_no"
Nhận xét: Biến này cần thiết cho việc đánh giá mức độ phụ thuộc vốn vay của NVL.
BCTC_NVL <- BCTC_NVL %>%
mutate(ty_le_no_von = tong_no / von_chu_so_huu)
colnames(BCTC_NVL)
## [1] "nam" "tai_san_ngan_han"
## [3] "tai_san_dai_han" "no_ngan_han"
## [5] "no_dai_han" "von_chu_so_huu"
## [7] "loi_nhuan_sau_thue" "tai_san_co_dinh_huu_hinh"
## [9] "hang_ton_kho" "doanh_thu_chua_thuc_hien_ngan_han"
## [11] "chi_phi_tra_truoc_dai_han" "tong_tai_san"
## [13] "tong_no" "ty_le_no_von"
Nhận xét: Giá trị cao cho thấy NVL sử dụng nhiều nợ vay; giá trị thấp phản ánh cấu trúc vốn an toàn hơn.
BCTC_NVL <- BCTC_NVL %>%
mutate(ROA = loi_nhuan_sau_thue / tong_tai_san)
colnames(BCTC_NVL)
## [1] "nam" "tai_san_ngan_han"
## [3] "tai_san_dai_han" "no_ngan_han"
## [5] "no_dai_han" "von_chu_so_huu"
## [7] "loi_nhuan_sau_thue" "tai_san_co_dinh_huu_hinh"
## [9] "hang_ton_kho" "doanh_thu_chua_thuc_hien_ngan_han"
## [11] "chi_phi_tra_truoc_dai_han" "tong_tai_san"
## [13] "tong_no" "ty_le_no_von"
## [15] "ROA"
Nhận xét: ROA dương cho thấy NVL hoạt động hiệu quả; giá trị âm thể hiện giai đoạn thua lỗ.
BCTC_NVL <- BCTC_NVL %>%
mutate(ROE = loi_nhuan_sau_thue / von_chu_so_huu)
colnames(BCTC_NVL)
## [1] "nam" "tai_san_ngan_han"
## [3] "tai_san_dai_han" "no_ngan_han"
## [5] "no_dai_han" "von_chu_so_huu"
## [7] "loi_nhuan_sau_thue" "tai_san_co_dinh_huu_hinh"
## [9] "hang_ton_kho" "doanh_thu_chua_thuc_hien_ngan_han"
## [11] "chi_phi_tra_truoc_dai_han" "tong_tai_san"
## [13] "tong_no" "ty_le_no_von"
## [15] "ROA" "ROE"
Nhận xét: Chỉ tiêu này thường được so sánh qua các năm để đánh giá xu hướng hiệu quả đầu tư.
BCTC_NVL <- BCTC_NVL %>%
mutate(across(
.cols = c(tai_san_ngan_han, tai_san_dai_han, no_ngan_han, no_dai_han,
von_chu_so_huu, loi_nhuan_sau_thue, tai_san_co_dinh_huu_hinh,
hang_ton_kho, doanh_thu_chua_thuc_hien_ngan_han,
chi_phi_tra_truoc_dai_han, tong_tai_san, tong_no),
.fns = ~ round(. / 1e9, 3)))
View(BCTC_NVL)
Nhận xét: Các biến tài chính được chuẩn hóa về đơn vị tỷ đồng giúp dễ so sánh và trực quan hóa hơn.
summary(BCTC_NVL$loi_nhuan_sau_thue)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 550.4 3707.3 9715.2 8166.4 12679.4 13494.2
Giải thích: (1) thống kê mô tả cơ bản cho biến “lợi nhuận sau thuế”.
Nhận xét: Biến loi_nhuan_sau_thue được chọn làm biến chính để phân tích vì thể hiện rõ khả năng sinh lời của NVL. Lợi nhuận sau thuế của NVL dao động từ 550,4 đến 13.494,2 tỷ đồng, trung bình 8.166,4 tỷ cho thấy mức sinh lời cao nhưng biến động lớn giữa các năm.
data.frame(
sd_tong_ts = sd(BCTC_NVL$tong_tai_san),
var_tong_ts = var(BCTC_NVL$tong_tai_san),
sd_von = sd(BCTC_NVL$von_chu_so_huu),
var_von = var(BCTC_NVL$von_chu_so_huu))
Giải thích: tạo bảng chứa các chỉ tiêu thống kê gồm độ lệch chuẩn và phương sai của tổng tài sản và vốn chủ sở hữu.
Nhận xét: Tổng tài sản có độ lệch chuẩn 92.227,9 cho thấy biến động lớn hơn so với vốn chủ sở hữu phản ánh quy mô tài sản của NVL thay đổi mạnh qua các năm trong khi vốn chủ ổn định hơn.
sd_lnst <- sd(BCTC_NVL$loi_nhuan_sau_thue)
mean_lnst <- mean(BCTC_NVL$loi_nhuan_sau_thue)
cv_lnst <- sd_lnst / mean_lnst
cv_lnst
## [1] 0.6332022
Giải thích:
(1)-(2): tính độ lệch chuẩn và giá trị trung bình của lợi nhuận sau thuế.
(3)-(4): tính hệ số biến thiên (CV) và hiển thị kết quả của hệ số biến thiên.
Nhận xét: CV = 0.6332022 (tức 63,32022%) cho thấy lợi nhuận sau thuế biến động khá mạnh qua các năm phản ánh rủi ro tài chính đáng kể. Tuy nhiên, mức này chưa vượt ngưỡng 1 nên NVL vẫn duy trì khả năng sinh lời ổn định tương đối.
Q1 <- quantile(BCTC_NVL$hang_ton_kho, 0.25)
Q3 <- quantile(BCTC_NVL$hang_ton_kho, 0.75)
iqr <- Q3 - Q1
outliers <- subset(
BCTC_NVL,
hang_ton_kho < Q1 - 1.5 * iqr | hang_ton_kho > Q3 + 1.5 * iqr)
outliers[, c("nam", "hang_ton_kho")]
Giải thích:
(1)-(2): tính tứ phân vị thứ nhất và thứ ba của biến hàng tồn kho.
(3): tính khoảng tứ phân vị (IQR) = Q3 – Q1.
(4)-(7): lọc ra các giá trị ngoại lệ, tức là những quan sát có hàng tồn kho nhỏ hơn (Q1 − 1.5×IQR) hoặc lớn hơn (Q3 + 1.5×IQR) và hiển thị năm và giá trị hàng tồn kho của các ngoại lệ.
Nhận xét: Không có giá trị ngoại lệ theo IQR cho thấy hàng tồn kho của NVL ổn định. Tuy nhiên, tồn kho lớn kéo dài vẫn có thể gây rủi ro thanh khoản, cần theo dõi thêm tỷ trọng tồn kho trên tổng tài sản để đánh giá mức phụ thuộc vốn lưu động.
BCTC_NVL <- BCTC_NVL %>%
mutate(ty_trong_htk_tsnh = (hang_ton_kho / tai_san_ngan_han) * 100)
summary_ton_kho_tsnh <- data.frame(
Min = min(BCTC_NVL$ty_trong_htk_tsnh, na.rm = TRUE),
Q1 = as.numeric(quantile(BCTC_NVL$ty_trong_htk_tsnh, 0.25, na.rm = TRUE)),
Median = median(BCTC_NVL$ty_trong_htk_tsnh, na.rm = TRUE),
Mean = mean(BCTC_NVL$ty_trong_htk_tsnh, na.rm = TRUE),
Q3 = as.numeric(quantile(BCTC_NVL$ty_trong_htk_tsnh, 0.75, na.rm = TRUE)),
Max = max(BCTC_NVL$ty_trong_htk_tsnh, na.rm = TRUE),
SD = sd(BCTC_NVL$ty_trong_htk_tsnh, na.rm = TRUE))
kable(round(summary_ton_kho_tsnh, 2),
caption = "Thống kê tỷ trọng hàng tồn kho trong tài sản ngắn hạn của NVL (%)",
align = "c")
| Min | Q1 | Median | Mean | Q3 | Max | SD |
|---|---|---|---|---|---|---|
| 39.72 | 64.9 | 69.36 | 66.1 | 72.26 | 80.36 | 11.95 |
Giải thích:
(1)-(2): tạo biến mới ty_trong_htk_tsnh thể hiện tỷ trọng hàng tồn kho trong tài sản ngắn hạn (%).
(3)-(10): tạo bảng thống kê mô tả gồm giá trị nhỏ nhất và lớn, tứ phân vị thứ nhất và thứ ba, giá trị trung vị, giá trị trung bình và độ lệch chuẩn.
(11)-(12): làm tròn số liệu đến 2 chữ số sau dấu thập phân và trình bày kết quả dưới dạng bảng với tiêu đề mô tả nội dung thống kê.
Nhận xét: Tỷ trọng hàng tồn kho trong tài sản ngắn hạn dao động từ 39,72% đến 80,36%, trung bình 66,1%, độ lệch chuẩn ≈ 12% cho thấy hơn một nửa tài sản ngắn hạn nằm ở hàng tồn kho, phản ánh mức phụ thuộc cao vào hàng tồn kho trong cơ cấu vốn lưu động.
BCTC_NVL <- BCTC_NVL %>%
mutate(ty_trong_tscd = (tai_san_co_dinh_huu_hinh / tong_tai_san) * 100)
summary_tscd <- data.frame(
Min = min(BCTC_NVL$ty_trong_tscd, na.rm = TRUE),
Q1 = as.numeric(quantile(BCTC_NVL$ty_trong_tscd, 0.25, na.rm = TRUE)),
Median = median(BCTC_NVL$ty_trong_tscd, na.rm = TRUE),
Mean = mean(BCTC_NVL$ty_trong_tscd, na.rm = TRUE),
Q3 = as.numeric(quantile(BCTC_NVL$ty_trong_tscd, 0.75, na.rm = TRUE)),
Max = max(BCTC_NVL$ty_trong_tscd, na.rm = TRUE),
SD = sd(BCTC_NVL$ty_trong_tscd, na.rm = TRUE))
kable(round(summary_tscd, 2), align = "c",
caption = "Thống kê tỷ trọng tài sản cố định hữu hình trong tổng tài sản của NVL (%)")
| Min | Q1 | Median | Mean | Q3 | Max | SD |
|---|---|---|---|---|---|---|
| 0.23 | 0.59 | 0.77 | 0.76 | 0.92 | 1.5 | 0.36 |
Giải thích:
(1)-(2): tạo biến mới ty_trong_tscd (%) tính bằng (tai_san_co_dinh_huu_hinh / tong_tai_san) × 100.
(3)-(10): khởi tạo bảng kết quả thống kê mô tả gồm giá trị nhỏ nhất của tỷ trọng, tính tứ phân vị thứ nhất, tính trung vị, tính trung vị, tứ phân vị thứ ba, giá trị lớn nhất, độ lệch chuẩn của tỷ trọng.
(11)-(12): làm tròn số liệu đến 2 chữ số sau dấu thập phân và trình bày kết quả dưới dạng bảng với tiêu đề mô tả nội dung thống kê.
Nhận xét: Tỷ trọng tài sản cố định hữu hình của NVL dao động 0,23–1,50%, trung bình 0,76% cho thấy mức đầu tư tài sản hữu hình rất thấp và cơ cấu dài hạn ổn định, phù hợp mô hình “tài sản nhẹ” của doanh nghiệp bất động sản.
BCTC_NVL$ty_trong_ts_ngan_han <-
BCTC_NVL$tai_san_ngan_han / BCTC_NVL$tong_tai_san
BCTC_NVL$ty_trong_ts_dai_han <-
BCTC_NVL$tai_san_dai_han / BCTC_NVL$tong_tai_san
summary_ts_cau_truc <- data.frame(
Biến = c("Tài sản ngắn hạn", "Tài sản dài hạn"),
Min = c(min(BCTC_NVL$ty_trong_ts_ngan_han, na.rm = TRUE),
min(BCTC_NVL$ty_trong_ts_dai_han, na.rm = TRUE)),
Mean = c(mean(BCTC_NVL$ty_trong_ts_ngan_han, na.rm = TRUE),
mean(BCTC_NVL$ty_trong_ts_dai_han, na.rm = TRUE)),
Max = c(max(BCTC_NVL$ty_trong_ts_ngan_han, na.rm = TRUE),
max(BCTC_NVL$ty_trong_ts_dai_han, na.rm = TRUE)),
SD = c(sd(BCTC_NVL$ty_trong_ts_ngan_han, na.rm = TRUE),
sd(BCTC_NVL$ty_trong_ts_dai_han, na.rm = TRUE)))
summary_ts_cau_truc[, 2:5] <- round(summary_ts_cau_truc[, 2:5], 4)
kable(summary_ts_cau_truc, align = "l",
caption =
"Thống kê tỷ trọng tài sản ngắn hạn và dài hạn trong tổng tài sản của NVL")
| Biến | Min | Mean | Max | SD |
|---|---|---|---|---|
| Tài sản ngắn hạn | 0.6825 | 0.786 | 0.8741 | 0.0542 |
| Tài sản dài hạn | 0.1259 | 0.214 | 0.3175 | 0.0542 |
Giải thích:
(1)-(2): tạo hai biến mới thể hiện tỷ trọng tài sản ngắn hạn và dài hạn trong tổng tài sản của NVL.
(3)-(12): bảng thống kê mô tả gồm: giá trị nhỏ nhất, trung bình, lớn nhất và độ lệch chuẩn cho hai loại tài sản và làm tròn đến 4 chữ số thập phân.
(13)-(14): in kết quả dưới dạng bảng trình bày đẹp có tiêu đề.
Nhận xét: Tài sản ngắn hạn chiếm 78,6%, dao động 68–87% phản ánh vốn lưu động lớn và ổn định. Tài sản dài hạn chiếm 21,4%, biến động nhẹ phù hợp mô hình “tài sản nhẹ” của doanh nghiệp bất động sản. Cơ cấu tài sản nhìn chung ổn định, không biến động đột ngột giữa vốn lưu động và đầu tư dài hạn.
BCTC_NVL$ty_le_no_von <- BCTC_NVL$tong_no / BCTC_NVL$von_chu_so_huu
summary_de <- data.frame(
Min = min(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
Q1 = as.numeric(quantile(BCTC_NVL$ty_le_no_von, 0.25, na.rm = TRUE)),
Median = median(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
Mean = mean(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
Q3 = as.numeric(quantile(BCTC_NVL$ty_le_no_von, 0.75, na.rm = TRUE)),
Max = max(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
SD = sd(BCTC_NVL$ty_le_no_von, na.rm = TRUE))
kable(round(summary_de, 3), align = "c",
caption = "Thống kê tỷ lệ nợ trên vốn chủ sở hữu của NVL")
| Min | Q1 | Median | Mean | Q3 | Max | SD |
|---|---|---|---|---|---|---|
| 1.719 | 2.646 | 3.129 | 3.272 | 3.996 | 4.751 | 0.974 |
Giải thích:
(1): tạo biến mới ty_le_no_von thể hiện tỷ lệ nợ trên vốn chủ sở hữu (D/E).
(2)-(8): tính các chỉ tiêu thống kê mô tả cho tỷ lệ D/E: giá trị nhỏ nhất, lớn nhất, tứ phân vị 25% và 75%, giá trị trung vị, trung bình và độ lệch chuẩn.
(9)-(10): làm tròn 3 chữ số thập phân và hiển thị bảng kết quả với tiêu đề.
Nhận xét: Tỷ lệ nợ trên vốn chủ sở hữu (D/E) dao động 1,72–4,75 lần, trung bình 3,27 lần cho thấy đòn bẩy tài chính cao và biến động mạnh. Cơ cấu vốn phụ thuộc lớn vào nợ vay, đặc trưng của doanh nghiệp bất động sản. Mức D/E cao giúp tăng ROE nhưng cũng làm gia tăng rủi ro và chi phí lãi vay khi thị trường biến động.
BCTC_NVL$ty_trong_dt_chua_th <-
BCTC_NVL$doanh_thu_chua_thuc_hien_ngan_han / BCTC_NVL$tong_tai_san
BCTC_NVL$ty_trong_cp_tra_truoc <-
BCTC_NVL$chi_phi_tra_truoc_dai_han / BCTC_NVL$tong_tai_san
summary_dt_cp <- data.frame(
Biến = c("Doanh thu chưa thực hiện", "Chi phí trả trước dài hạn"),
Min = c(min(BCTC_NVL$ty_trong_dt_chua_th, na.rm = TRUE),
min(BCTC_NVL$ty_trong_cp_tra_truoc, na.rm = TRUE)),
Mean = c(mean(BCTC_NVL$ty_trong_dt_chua_th, na.rm = TRUE),
mean(BCTC_NVL$ty_trong_cp_tra_truoc, na.rm = TRUE)),
Max = c(max(BCTC_NVL$ty_trong_dt_chua_th, na.rm = TRUE),
max(BCTC_NVL$ty_trong_cp_tra_truoc, na.rm = TRUE)),
SD = c(sd(BCTC_NVL$ty_trong_dt_chua_th, na.rm = TRUE),
sd(BCTC_NVL$ty_trong_cp_tra_truoc, na.rm = TRUE)))
summary_dt_cp[, 2:5] <- round(summary_dt_cp[, 2:5], 5)
kable(summary_dt_cp, align = "l",
caption =
"Thống kê tỷ trọng doanh thu chưa thực hiện và chi phí trả trước của NVL")
| Biến | Min | Mean | Max | SD |
|---|---|---|---|---|
| Doanh thu chưa thực hiện | 0.0000 | 0.00003 | 0.00009 | 0.00003 |
| Chi phí trả trước dài hạn | 0.0029 | 0.00583 | 0.00908 | 0.00202 |
Giải thích:
(1)-(2): tạo hai biến mới thể hiện tỷ trọng doanh thu chưa thực hiện và chi phí trả trước dài hạn trong tổng tài sản.
(3)-(12): tạo bảng thống kê mô tả gồm giá trị nhỏ nhất và lớn nhất, giá trị trung bình, độ lệch chuẩn và làm tròn đến 5 chữ số thập phân.
(13)-(14): trình bày bảng kết quả có tiêu đề.
Nhận xét: Doanh thu chưa thực hiện gần như 0% cho thấy NVL ghi nhận doanh thu sau khi bàn giao sản phẩm. Chi phí trả trước dài hạn chiếm ≈0,6% tổng tài sản với biến động nhỏ và ổn định. Cả hai chỉ tiêu duy trì mức thấp, ổn định phản ánh cơ cấu tài sản lành mạnh và chính sách kế toán nhất quán của doanh nghiệp bất động sản.
BCTC_NVL <- BCTC_NVL[order(BCTC_NVL$nam), ]
BCTC_NVL$tang_truong_tong_ts <-
c(NA, diff(BCTC_NVL$tong_tai_san) / head(BCTC_NVL$tong_tai_san, -1))
BCTC_NVL$tang_truong_von <-
c(NA, diff(BCTC_NVL$von_chu_so_huu) / head(BCTC_NVL$von_chu_so_huu, -1))
BCTC_NVL$tang_truong_loi_nhuan <-
c(NA, diff(BCTC_NVL$loi_nhuan_sau_thue) / head(BCTC_NVL$loi_nhuan_sau_thue, -1))
summary_tangtruong <- data.frame(
Biến = c("Tổng tài sản", "Vốn chủ sở hữu", "Lợi nhuận sau thuế"),
Min = c(min(BCTC_NVL$tang_truong_tong_ts, na.rm = TRUE),
min(BCTC_NVL$tang_truong_von, na.rm = TRUE),
min(BCTC_NVL$tang_truong_loi_nhuan, na.rm = TRUE)),
Mean = c(mean(BCTC_NVL$tang_truong_tong_ts, na.rm = TRUE),
mean(BCTC_NVL$tang_truong_von, na.rm = TRUE),
mean(BCTC_NVL$tang_truong_loi_nhuan, na.rm = TRUE)),
Max = c(max(BCTC_NVL$tang_truong_tong_ts, na.rm = TRUE),
max(BCTC_NVL$tang_truong_von, na.rm = TRUE),
max(BCTC_NVL$tang_truong_loi_nhuan, na.rm = TRUE)),
SD = c(sd(BCTC_NVL$tang_truong_tong_ts, na.rm = TRUE),
sd(BCTC_NVL$tang_truong_von, na.rm = TRUE),
sd(BCTC_NVL$tang_truong_loi_nhuan, na.rm = TRUE)))
summary_tangtruong[, 2:5] <- round(summary_tangtruong[, 2:5], 2)
kable(summary_tangtruong, align = "l",
caption = "Thống kê tốc độ tăng trưởng năm sau so với năm trước của NVL")
| Biến | Min | Mean | Max | SD |
|---|---|---|---|---|
| Tổng tài sản | -0.06 | 0.29 | 0.61 | 0.21 |
| Vốn chủ sở hữu | 0.01 | 0.27 | 0.65 | 0.22 |
| Lợi nhuận sau thuế | -0.11 | 0.54 | 2.05 | 0.69 |
Giải thích:
(1)-(4): sắp xếp dữ liệu theo thứ tự năm tăng dần và tính tốc độ tăng trưởng (%) năm sau so với năm trước cho tổng tài sản, vốn chủ sở hữu và lợi nhuận sau thuế.
(5)-(15): tạo bảng thống kê mô tả tốc độ tăng trưởng gồm: tăng trưởng thấp nhất, cao nhất, tăng trưởng trung bình, độ lệch chuẩn và tròn các giá trị thống kê đến 2 chữ số thập phân.
(16)-(17): trình bày bảng kết quả.
Nhận xét: Tổng tài sản của NVL tăng trung bình 29,2%/năm, vốn chủ 27,2%/năm và lợi nhuận sau thuế 53,5%/năm cho thấy quy mô mở rộng nhanh. Tuy nhiên, lợi nhuận biến động mạnh phản ánh tính chu kỳ của ngành bất động sản và sự phụ thuộc vào tiến độ dự án, khiến tăng trưởng chưa ổn định hoàn toàn.
BCTC_NVL <- BCTC_NVL %>%
mutate(
nam = as.numeric(as.character(nam)),
tong_tai_san = as.numeric(as.character(tong_tai_san)),
von_chu_so_huu = as.numeric(as.character(von_chu_so_huu)),
loi_nhuan_sau_thue = as.numeric(as.character(loi_nhuan_sau_thue)))
nam_dau <- min(BCTC_NVL$nam)
nam_cuoi <- max(BCTC_NVL$nam)
so_nam <- nam_cuoi - nam_dau
CAGR_tong_ts <- (tail(BCTC_NVL$tong_tai_san, 1) /
head(BCTC_NVL$tong_tai_san, 1))^(1 / so_nam) - 1
CAGR_von <- (tail(BCTC_NVL$von_chu_so_huu, 1) /
head(BCTC_NVL$von_chu_so_huu, 1))^(1 / so_nam) - 1
CAGR_loi_nhuan <- (tail(BCTC_NVL$loi_nhuan_sau_thue, 1) /
head(BCTC_NVL$loi_nhuan_sau_thue, 1))^(1 / so_nam) - 1
summary_CAGR <- data.frame(
Biến = c("Tổng tài sản", "Vốn chủ sở hữu", "Lợi nhuận sau thuế"),
CAGR = round(c(CAGR_tong_ts, CAGR_von, CAGR_loi_nhuan), 2))
kable(summary_CAGR, align = "l",
caption = "Tốc độ tăng trưởng kép bình quân giai đoạn 2015–2024 của NVL")
| Biến | CAGR |
|---|---|
| Tổng tài sản | 0.28 |
| Vốn chủ sở hữu | 0.26 |
| Lợi nhuận sau thuế | 0.42 |
Giải thích:
(1)-(5): chuyển các biến nam, tong_tai_san, von_chu_so_huu, loi_nhuan_sau_thue về kiểu số.
(6)-(14): xác định năm đầu, năm cuối và số năm phân tích để tính tốc độ tăng trưởng kép bình quân cho tổng tài sản, vốn chủ sở hữu và lợi nhuận sau thuế.
(15)-(17): tạo bảng kết quả được làm tròn 2 chữ số thập phân.
Nhận xét: Tổng tài sản của NVL tăng 28%/năm, vốn chủ 26%/năm và lợi nhuận sau thuế 42%/năm cho thấy doanh nghiệp mở rộng nhanh, sinh lời tốt. Cả ba chỉ tiêu đều có CAGR dương và cao, khẳng định tăng trưởng bền vững, hiệu quả trong dài hạn.
BCTC_NVL <- BCTC_NVL %>%
mutate(ty_le_no_von = tong_no / von_chu_so_huu)
BCTC_NVL <- BCTC_NVL %>%
mutate(bien_dong_DE = c(NA, diff(ty_le_no_von)))
summary_DE <- data.frame(
Min = min(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
Q1 = as.numeric(quantile(BCTC_NVL$ty_le_no_von, 0.25, na.rm = TRUE)),
Median = median(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
Mean = mean(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
Q3 = as.numeric(quantile(BCTC_NVL$ty_le_no_von, 0.75, na.rm = TRUE)),
Max = max(BCTC_NVL$ty_le_no_von, na.rm = TRUE),
SD = sd(BCTC_NVL$ty_le_no_von, na.rm = TRUE))
kable(round(summary_DE, 2), align = "c",
caption = "Thống kê tỷ lệ Nợ trên Vốn chủ sở hữu và mức biến động của NVL")
| Min | Q1 | Median | Mean | Q3 | Max | SD |
|---|---|---|---|---|---|---|
| 1.72 | 2.65 | 3.13 | 3.27 | 4 | 4.75 | 0.97 |
Giải thích:
(1)-(4): tạo biến ty_le_no_von và biến bien_dong_DE.
(5)-(13): tính các chỉ tiêu thống kê: giá trị nhỏ nhất, lớn nhất, tứ phân vị 25% và 75%, trung vị, trung bình và độ lệch chuẩn.
(14)-(15): hiển thị bảng thống kê với kết quả được làm tròn 2 chữ số.
Nhận xét: Tỷ lệ nợ trên vốn chủ sở hữu (D/E) dao động 1,72–4,75 lần, trung bình 3,27 lần cho thấy đòn bẩy tài chính cao và biến động mạnh. Cơ cấu vốn phụ thuộc lớn vào nợ vay, đặc trưng của doanh nghiệp bất động sản. Mức D/E cao giúp tăng ROE nhưng cũng làm gia tăng rủi ro và chi phí lãi vay khi thị trường biến động.
bien_tuong_quan <- BCTC_NVL %>%
select(tong_tai_san, tong_no, von_chu_so_huu, loi_nhuan_sau_thue)
ma_tran_tq <- cor(bien_tuong_quan, use = "pairwise.complete.obs", method = "pearson")
ma_tran_tq <- round(ma_tran_tq, 3)
kable(
ma_tran_tq, align = "c",
caption = "Ma trận tương quan Pearson giữa các biến tài chính của NVL")
| tong_tai_san | tong_no | von_chu_so_huu | loi_nhuan_sau_thue | |
|---|---|---|---|---|
| tong_tai_san | 1.000 | 0.999 | 0.984 | 0.926 |
| tong_no | 0.999 | 1.000 | 0.981 | 0.920 |
| von_chu_so_huu | 0.984 | 0.981 | 1.000 | 0.964 |
| loi_nhuan_sau_thue | 0.926 | 0.920 | 0.964 | 1.000 |
Giải thích:
(1)-(2): Chọn 4 biến chính (tổng tài sản, tổng nợ, vốn chủ sở hữu, lợi nhuận sau thuế) để phân tích mức độ tương quan giữa các chỉ tiêu tài chính.
(3)-(4): Tính ma trận tương quan Pearson, phản ánh mối quan hệ tuyến tính giữa các biến (hệ số từ -1 đến 1) và làm tròn 3 chữ số thập phân.
(5)-(7): hiển thị kết quả dưới dạng bảng tương quan.
Nhận xét: Các biến tài chính của NVL có tương quan dương rất mạnh (r > 0.9) cho thấy tổng tài sản, nợ, vốn và lợi nhuận tăng cùng chiều. Mối liên hệ chặt chẽ nhất giữa tài sản – nợ (r = 0.999) và vốn – lợi nhuận (r = 0.964) phản ánh cơ cấu tài chính đồng bộ, quy mô mở rộng gắn liền với hiệu quả sinh lời.
cor_spearman <- cor(
BCTC_NVL$loi_nhuan_sau_thue,
BCTC_NVL$tong_tai_san,
method = "spearman",
use = "complete.obs")
cor_spearman
## [1] 0.9515152
Giải thích:
(1)-(4): chọn phương pháp Spearman tính hệ số tương quan Spearman giữa lợi nhuận sau thuế và tổng tài sản và loại bỏ các giá trị thiếu để tính trên các cặp quan sát đầy đủ.
(5): in giá trị hệ số tương quan Spearman để đánh giá mức độ và chiều hướng quan hệ giữa tài sản và lợi nhuận.
Nhận xét: Hệ số Spearman (rs = 0.9515) cho thấy mối tương quan thuận rất mạnh giữa tổng tài sản và lợi nhuận sau thuế chứng tỏ khi quy mô tài sản tăng thì lợi nhuận cũng tăng tương ứng. Giá trị rs cao hơn Pearson (0.926) phản ánh mối quan hệ đồng biến ổn định, thể hiện chiến lược mở rộng tài sản của NVL đi kèm hiệu quả sinh lời bền vững.
acf_result <- acf(BCTC_NVL$loi_nhuan_sau_thue, plot = FALSE)
autocorr_1 <- acf_result$acf[2]
autocorr_1
## [1] 0.7438508
Giải thích:
(1)-(2): tính hàm tự tương quan (ACF) cho biến lợi nhuận sau thuế mà không vẽ đồ thị và trích hệ số tự tương quan bậc 1.
(3): in ra giá trị hệ số.
Nhận xét: Hệ số tự tương quan bậc 1 (r = 0.74) cho thấy mối liên hệ dương mạnh giữa lợi nhuận các năm liên tiếp phản ánh xu hướng ổn định và chu kỳ rõ rệt trong hoạt động của NVL. Lợi nhuận năm sau thường tăng cùng chiều năm trước dù vẫn có dao động nhẹ do yếu tố thị trường và dự án.
library(lmtest)
library(sandwich)
library(broom)
library(kableExtra)
model_roa_de <- lm(ROA ~ ty_le_no_von, data = BCTC_NVL)
reg_summary <- tidy(model_roa_de)
kable(reg_summary,
caption = "Kết quả hồi quy tuyến tính ROA theo tỷ lệ Nợ trên Vốn (D/E)",
align = "c") %>%
kable_styling(latex_options = c("striped", "hold_position"), font_size = 13)
| term | estimate | std.error | statistic | p.value |
|---|---|---|---|---|
| (Intercept) | 0.0521881 | 0.0304851 | 1.7119215 | 0.1252705 |
| ty_le_no_von | 0.0020220 | 0.0089667 | 0.2255011 | 0.8272435 |
Giải thích:
(1)-(4): nạp các gói hỗ trợ kiểm định mô hình (lmtest, sandwich), tóm tắt kết quả (broom), và trình bày bảng đẹp (kableExtra).
(5)-(6): xây dựng mô hình hồi quy tuyến tính đơn, trong đó ROA là biến phụ thuộc và ty_le_no_von là biến độc lập và chuyển kết quả hồi quy sang dạng bảng với các cột: hệ số, sai số chuẩn, giá trị t, và p-value.
(7)-(10): hiển thị bảng kết quả hồi quy.
Nhận xét: Phương trình hồi quy ước lượng: ROA=0.0522+0.0020×(D/E)
Trong đó: Hệ số chặn β₀ = 0.0522 cho thấy khi D/E = 0, ROA trung bình khoảng 5,22%. Hệ số β₁ = 0.0020 (p = 0.827 > 0.05) biểu thị mối quan hệ cùng chiều yếu giữa D/E và ROA nhưng không có ý nghĩa thống kê. Vì vậy, tỷ lệ nợ trên vốn chưa ảnh hưởng rõ ràng đến hiệu suất sinh lời của NVL trong giai đoạn phân tích.
test_results <- data.frame(
Kiem_dinh = c("Durbin–Watson", "Shapiro–Wilk", "Breusch–Pagan"),
p_value = c(
dwtest(model_roa_de)$p.value,
shapiro.test(residuals(model_roa_de))$p.value,
bptest(model_roa_de)$p.value))
kable(test_results,
caption = "Kết quả các kiểm định mô hình hồi quy ROA theo D/E",
align = "c") %>%
kable_styling(latex_options = c("striped", "hold_position"), font_size = 13)
| Kiem_dinh | p_value |
|---|---|
| Durbin–Watson | 0.0002224 |
| Shapiro–Wilk | 0.4956205 |
| Breusch–Pagan | 0.0184165 |
Giải thích:
(1): tạo bảng chứa tên các kiểm định chẩn đoán mô hình hồi quy và giá trị p-value tương ứng để đánh giá độ phù hợp mô hình.
(2): kiểm định Durbin–Watson xem có hiện tượng tự tương quan phần dư hay không.
(3): kiểm định Shapiro–Wilk để đánh giá phân phối chuẩn của phần dư.
(4): kiểm định Breusch–Pagan nhằm phát hiện hiện tượng phương sai thay đổi.
(5): trình bày kết quả kiểm định trong bảng.
Nhận xét:
Kiểm định Durbin–Watson
Giả thuyết:
H0: Không có tự tương quan phần dư.
H1: Có tự tương quan phần dư.
Kết quả: p-value = 0.0002224 < 0.05 → bác bỏ H0.
Kết luận: Có hiện tượng tự tương quan dương giữa các phần dư của mô hình, tức là giá trị sai số của các quan sát liên tiếp có xu hướng cùng chiều nhau.
Kiểm định Shapiro–Wilk
Giả thuyết:
H0: Phần dư có phân phối chuẩn.
H1: Phần dư không phân phối chuẩn.
Kết quả: p-value = 0.4956205 > 0.05 → không bác bỏ H0.
Kết luận: Phần dư của mô hình tuân theo phân phối chuẩn, phù hợp với giả định của mô hình hồi quy tuyến tính cổ điển (OLS).
Kiểm định Breusch–Pagan
Giả thuyết:
H0: Phương sai của sai số đồng nhất (không có heteroskedasticity).
H1: Có phương sai thay đổi.
Kết quả: p-value = 0.0184165 > 0.05 → không bác bỏ H0.
Kết luận: Có hiện tượng phương sai thay đổi, tức là mức độ biến động của phần dư không đồng nhất giữa các quan sát.
BCTC_NVL <- BCTC_NVL %>%
mutate(current_ratio = tai_san_ngan_han / no_ngan_han)
summary_cr <- data.frame(
Min = min(BCTC_NVL$current_ratio, na.rm = TRUE),
Mean = mean(BCTC_NVL$current_ratio, na.rm = TRUE),
Max = max(BCTC_NVL$current_ratio, na.rm = TRUE),
SD = sd(BCTC_NVL$current_ratio, na.rm = TRUE))
kable(summary_cr,
caption = "Thống kê hệ số thanh khoản hiện hành của NVL",
align = "c") %>%
kable_styling(latex_options = c("striped", "hold_position"), font_size = 10)
| Min | Mean | Max | SD |
|---|---|---|---|
| 1.816825 | 2.831082 | 5.405461 | 1.169473 |
Giải thích:
(1)-(2): tạo biến mới current_ratio biểu thị hệ số thanh khoản hiện hành.
(3)-(7): tính các chỉ tiêu thống kê mô tả: giá trị nhỏ nhất, trung bình, lớn nhất và độ lệch chuẩn.
(8)-(11): xuất bảng kết quả có tiêu đề.
Nhận xét: Hệ số thanh khoản hiện hành trung bình 2,83, cao hơn mức an toàn (≥1) cho thấy khả năng thanh toán ngắn hạn rất tốt. Dao động 1,82 đến 5,41 tức tài sản ngắn hạn luôn gấp ≥1,8 lần nợ ngắn hạn, rủi ro thanh khoản thấp .Độ lệch chuẩn 1,17 phản ánh sự biến động theo chu kỳ kinh doanh. Nhìn chung, NVL duy trì mức thanh khoản an toàn và ổn định thể hiện hiệu quả quản lý vốn lưu động.
BCTC_NVL <- BCTC_NVL %>%
mutate(ty_trong_hang_ton_kho_ts = (hang_ton_kho / tong_tai_san) * 100)
summary_inv <- data.frame(
Min = min(BCTC_NVL$ty_trong_hang_ton_kho_ts, na.rm = TRUE),
Mean = mean(BCTC_NVL$ty_trong_hang_ton_kho_ts, na.rm = TRUE),
Max = max(BCTC_NVL$ty_trong_hang_ton_kho_ts, na.rm = TRUE),
SD = sd(BCTC_NVL$ty_trong_hang_ton_kho_ts, na.rm = TRUE))
kable(summary_inv,
caption = "Độ tập trung tài sản vào hàng tồn kho của NVL",
align = "c") %>%
kable_styling(latex_options = c("striped", "hold_position"), font_size = 13)
| Min | Mean | Max | SD |
|---|---|---|---|
| 27.10428 | 52.22259 | 63.5807 | 10.87364 |
Giải thích:
(1)-(2): tạo biến mới ty_trong_hang_ton_kho_ts.
(3)-(7): tính các chỉ tiêu thống kê mô tả gồm tỷ trọng thấp nhất, trung bình, cao nhất và độ lệch chuẩn.
(8)-(11): hiển thị bảng kết quả có tiêu đề.
Nhận xét: Tỷ trọng hàng tồn kho trung bình 52,22%, đặc trưng của doanh nghiệp bất động sản với tài sản chủ yếu là dự án dở dang. Dao động 27,10% đến 63,58% (SD = 10,87%) phản ánh chu kỳ đầu tư, bàn giao biến động mạnh.Tỷ trọng cao thể hiện đầu tư lớn vào dự án nhưng cũng làm giảm thanh khoản khi thị trường chậm tiêu thụ.
BCTC_NVL <- BCTC_NVL %>%
mutate(tong_no = no_ngan_han + no_dai_han)
BCTC_NVL <- BCTC_NVL %>%
mutate(chenh_lech = tong_tai_san - (tong_no + von_chu_so_huu))
summary_diff <- data.frame(
Min = min(BCTC_NVL$chenh_lech, na.rm = TRUE),
Mean = mean(BCTC_NVL$chenh_lech, na.rm = TRUE),
Max = max(BCTC_NVL$chenh_lech, na.rm = TRUE),
SD = sd(BCTC_NVL$chenh_lech, na.rm = TRUE))
kable(summary_diff,
caption =
"Kiểm tra logic kế toán: Tổng tài sản so với Tổng nợ và Vốn chủ sở hữu",
align = "c") %>%
kable_styling(latex_options = c("striped", "hold_position"), font_size = 13)
| Min | Mean | Max | SD |
|---|---|---|---|
| 0 | 1000.02 | 10000 | 3162.271 |
Giải thích:
(1)-(4): tạo biến mới tong_no và tính chênh lệch giữa tổng tài sản và tổng nguồn vốn.
(5)-(9): tính Min, Mean, Max, SD của chênh lệch để đánh giá độ lệch giữa hai bên bảng cân đối.
(10)-(13): hiển thị bảng kiểm tra logic kế toán giúp xác nhận dữ liệu tài chính tuân thủ phương trình kế toán cơ bản.
Nhận xét: Độ chênh trung bình giữa hai vế kế toán là 1.000,02 tỷ đồng, SD là 3.162,27 tỷ cho thấy biến động lớn. Do đó phương trình kế toán chưa cân đối, cần rà soát và chuẩn hóa số liệu tài sản, nợ và vốn.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
ggplot(BCTC_NVL, aes(x = nam, y = tong_tai_san)) +
geom_area(aes(fill = tong_tai_san), alpha = 0.35, show.legend = FALSE) +
geom_line(color = "#1E88E5", linewidth = 0.8) +
geom_point(size = 3, color = "#0D47A1") +
geom_text(aes(
label = comma(round(tong_tai_san, 0))),
vjust = -1,
hjust = 1,
size = 2, color = "#0D47A1") +
scale_fill_gradient(low = "#BBDEFB", high = "#0D47A1") +
scale_x_continuous(breaks = seq(2015, 2024, by = 1)) +
scale_y_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
labs(title = "Tổng tài sản của NVL (2015–2024)",
x = "Năm", y = "Tổng tài sản (tỷ đồng)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(face = "bold", size = 20, hjust = 0.2, color = "#0D47A1"),
axis.text.x = element_text(size = 10, face = "bold"),
axis.text.y = element_text(size = 10, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray80", linetype = "dotted"))
Giải thích:
(1)-(3): thiết lập phông chữ TimesVN, bật hiển thị tiếng Việt và chọn giao diện.
(4)-(7): khởi tạo đồ thị ggplot, trục X là năm, trục Y là tổng tài sản; thêm vùng màu, đường và điểm thể hiện xu hướng tài sản qua từng năm.
(8)-(9): thêm nhãn giá trị tổng tài sản trên từng điểm dữ liệu.
(10)-(12): định dạng màu nền theo gradient, hiển thị mốc năm 2015–2024 và trục Y theo đơn vị tỷ đồng.
(13)-(14): gắn tiêu đề và nhãn trục.
(15)-(22): căn chỉnh bố cục, định dạng tiêu đề, trục và thêm lưới chấm ngang giúp biểu đồ rõ ràng, trực quan hơn.
Nhận xét: Giai đoạn 2015–2018, tài sản NVL tăng từ 26.570 lên 49.467 tỷ đồng. Từ 2019–2022, tăng mạnh đạt đỉnh 257.735 tỷ phản ánh mở rộng đầu tư. Giai đoạn 2023–2024, tài sản ổn định quanh 237.778 tỷ cho thấy tái cơ cấu và duy trì tăng trưởng bền vững.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
ts_long <- BCTC_NVL %>%
select(nam, tai_san_ngan_han, tai_san_dai_han) %>%
pivot_longer(cols = c(tai_san_ngan_han, tai_san_dai_han),
names_to = "Loai_TS", values_to = "GiaTri") %>%
mutate(Loai_TS = recode(Loai_TS,
"tai_san_ngan_han" = "Tài sản ngắn hạn",
"tai_san_dai_han" = "Tài sản dài hạn"))
ggplot(ts_long, aes(x = nam, y = GiaTri, color = Loai_TS)) +
geom_line(linewidth = 1) +
geom_point(size = 2.5) +
geom_text(aes(
label = comma(round(GiaTri, 0)),
vjust = ifelse(
Loai_TS == "Tài sản ngắn hạn" & nam == 2024, 2,
ifelse(Loai_TS == "Tài sản dài hạn" & nam == 2015, 2,
-1.0))),
size = 3, fontface = "bold") +
scale_color_manual(values = c("#1565C0", "#2E7D32")) +
scale_y_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
labs(title = "Xu hướng Tài sản ngắn hạn và dài hạn của NVL (2015–2024)",
subtitle = "Đường màu xanh dương thể hiện TS ngắn hạn, màu xanh lá là TS dài hạn",
x = "Năm", y = "Giá trị (tỷ đồng)", color = "Loại tài sản") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
plot.subtitle = element_text(size = 13, hjust = 0.5),
axis.text = element_text(size = 12),
axis.title = element_text(size = 12, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"))
Nhận xét:
(5)-(11): chọn 3 biến chính: năm, tài sản ngắn hạn và tài sản dài hạn, gom hai cột tài sản thành một cột chung Loai_TS để dễ vẽ theo nhóm và đổi tên tiếng Việt rõ nghĩa cho biến loại tài sản.
(12)-(14): tạo đối tượng ggplot với trục X là nam, Y là GiaTri, và phân biệt màu theo Loai_TS, vẽ đường nối biểu diễn xu hướng giá trị theo thời gian, đánh dấu từng điểm dữ liệu trên đường. (15)-(23): thêm nhãn giá trị thực tế trên từng điểm, điều chỉnh vị trí chữ, gán màu xanh dương cho tài sản ngắn hạn và xanh lá cho tài sản dài hạn và định dạng trục Y hiển thị đơn vị “tỷ”, và trục X từ 2015–2024.
Nhận xét: Tài sản ngắn hạn tăng từ 8.437 tỷ năm 2015 lên 59.620 tỷ năm 2022 rồi giảm nhẹ còn 29.947 tỷ năm 2024, phản ánh mở rộng rồi điều chỉnh vốn lưu động. Tài sản dài hạn tăng mạnh từ 18.133 lên 207.831 tỷ đồng cho thấy tập trung đầu tư vào dự án và hạ tầng. Nhìn chung, cơ cấu tài sản chuyển dần sang dài hạn thể hiện chiến lược đầu tư bền vững và nền tảng tài chính vững chắc của NVL.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
ggplot(BCTC_NVL, aes(x = hang_ton_kho, y = doanh_thu_chua_thuc_hien_ngan_han)) +
geom_point(size = 3, color = "#1565C0", alpha = 0.8) +
geom_smooth(method = "lm", se = TRUE, color = "#2E7D32",
linetype = "dashed", linewidth = 1.2) +
geom_text(aes(label = nam,
vjust = ifelse(nam == 2020, 2, -1)),
size = 4.5, color = "black") +
scale_x_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
scale_y_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
labs(
title = "Mối quan hệ giữa Hàng tồn kho và Doanh thu của NVL (2015–2024)",
subtitle = "Biểu đồ phân tán với đường hồi quy tuyến tính thể hiện xu hướng đồng biến",
x = "Hàng tồn kho (tỷ đồng)",
y = "Doanh thu (tỷ đồng)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray25"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 12, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "gray85", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(10): chuyển dữ liệu sang dạng dài để vẽ hai loại tài sản trên cùng biểu đồ.
(11)-(13): khởi tạo biểu đồ đường thể hiện xu hướng tài sản theo năm.
(14)-(23): thêm nhãn giá trị tài sản lên từng điểm, điều chỉnh vị trí hiển thị, tùy chỉnh màu và định dạng trục Y theo tỷ đồng, trục X theo năm.
Nhận xét: Giai đoạn 2015–2019, tồn kho và doanh thu chưa thực hiện thấp phản ánh quy mô dự án nhỏ. Năm 2020, doanh thu tăng mạnh dù tồn kho ổn định cho thấy ghi nhận ngắn hạn. Từ 2021–2024, tồn kho tăng nhưng doanh thu giảm thể hiện bán hàng chậm. Đường hồi quy dốc xuống cho thấy hiệu quả khai thác tồn kho giảm.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
no_long <- BCTC_NVL %>%
select(nam, no_ngan_han, no_dai_han) %>%
pivot_longer(cols = c(no_ngan_han, no_dai_han),
names_to = "Loai_No", values_to = "GiaTri") %>%
mutate(Loai_No = recode(Loai_No,
"no_ngan_han" = "Nợ ngắn hạn",
"no_dai_han" = "Nợ dài hạn"))
ggplot(no_long, aes(x = factor(nam), y = GiaTri, fill = Loai_No)) +
geom_bar(stat = "identity", color = "black", linewidth = 0.3) +
geom_text(aes(
label = comma(round(GiaTri, 0)),
vjust = ifelse(nam == 2015 & Loai_No == "Nợ dài hạn", 2.1,
ifelse(nam == 2015 & Loai_No == "Nợ ngắn hạn", -1.3, 0.5))),
position = position_stack(vjust = 0.5),
size = 3) +
scale_fill_manual(values = c("#64B5F6", "#81C784")) +
scale_y_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
labs(
title = "Cấu trúc Nợ phải trả của NVL (2015–2024)",
subtitle = "Phân tách tỷ trọng giữa Nợ ngắn hạn và Nợ dài hạn qua các năm",
x = "Năm", y = "Giá trị (tỷ đồng)", fill = "Loại nợ") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 18, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray25"),
axis.title = element_text(size = 13, face = "bold"),
axis.text = element_text(size = 12, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(10): chọn biến nợ ngắn hạn, nợ dài hạn chuyển sang dạng dài và gán nhãn tiếng Việt.
(11)-(18): tạo biểu đồ cột chồng thể hiện cơ cấu nợ từng năm và thêm nhãn giá trị cụ thể lên cột.
(19)-(20): tô màu xanh dương cho nợ ngắn hạn và xanh lá cho nợ dài hạn và định dạng trục Y theo đơn vị tỷ đồng.
Nhận xét: Năm 2015–2018, nợ tăng từ gần 10.000 lên gần 50.000 tỷ đồng, chủ yếu là nợ ngắn hạn cho thấy phụ thuộc vốn ngắn hạn. Năm 2019–2022, nợ dài hạn tăng mạnh từ 18.810 lên 78.000 tỷ phản ánh mở rộng đầu tư dự án lớn. Năm 2023–2024, tổng nợ ổn định, nợ dài hạn chiếm tỷ trọng cao thể hiện tái cơ cấu vốn an toàn hơn. Do đó, doanh nghiệp chuyển từ vốn ngắn hạn sang dài hạn cho thấy chiến lược tài chính bền vững và giảm rủi ro thanh khoản.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
BCTC_NVL <- BCTC_NVL %>%
mutate(DR = tong_no / tong_tai_san)
ggplot(BCTC_NVL, aes(x = nam, y = DR)) +
geom_area(fill = "#FFCC80", alpha = 0.4) +
geom_line(color = "#E65100", linewidth = 1) +
geom_point(size = 2.5, color = "#E65100") +
geom_text(aes(label = percent(DR, accuracy = 0.1)),
vjust = -1, size = 4.5, color = "#E65100") +
scale_y_continuous(
labels = label_percent(accuracy = 1),
expand = expansion(mult = c(0, 0.15)))+
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
labs(
title = "Tỷ lệ đòn bẩy tài chính của NVL (2015–2024)",
subtitle = "Phản ánh mức độ sử dụng nợ trong tổng tài sản của doanh nghiệp",
x = "Năm", y = "Tỷ lệ nợ trên tổng tài sản (%)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 18, face = "bold", hjust = 0.5, color = "Black"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray25"),
axis.title = element_text(size = 13, face = "bold"),
axis.text = element_text(size = 12, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray80", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(5): tạo biến DR = Tổng nợ / Tổng tài sản.
(6)-(15): vẽ biểu đồ vùng có đường xu hướng và nhãn phần trăm thể hiện tỷ lệ DR qua các năm, định dạng trục tung theo đơn vị %, trục hoành hiển thị năm 2015–2024.
Nhận xét: Năm 2015, DR 39,4% cho thấy nợ thấp và tự chủ cao. Giai đoạn 2016–2018, DR tăng lên 72–73% do mở rộng đầu tư bằng vốn vay. 2019–2022 đạt đỉnh 82,6% phản ánh rủi ro tài chính cao. 2023–2024 giảm còn 80,1% cho thấy xu hướng kiểm soát nợ và tái cấu trúc vốn an toàn hơn.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
vars <- BCTC_NVL %>%
select(tong_tai_san, tong_no, von_chu_so_huu, loi_nhuan_sau_thue,
hang_ton_kho, tai_san_ngan_han, tai_san_dai_han, DR, ROA, ROE)
corr_matrix <- round(cor(vars, use = "complete.obs"), 2)
corr_long <- corr_matrix %>%
as.data.frame() %>%
mutate(var1 = rownames(.)) %>%
pivot_longer(-var1, names_to = "var2", values_to = "value")
ggplot(corr_long, aes(x = var1, y = var2, fill = value)) +
geom_tile(color = "white", linewidth = 0.6) +
geom_text(aes(label = round(value, 2)),
size = 4, fontface = "bold", color = "black") +
scale_fill_gradient2(
low = "#A5D6A7",
mid = "white",
high = "#2E7D32",
midpoint = 0, limits = c(-1, 1),
name = "Hệ số
tương quan") +
labs(
title = "Ma trận tương quan giữa các chỉ tiêu tài chính của NVL (2015–2024)",
subtitle = "Màu xanh đậm thể hiện tương quan thuận mạnh, màu nhạt thể hiện tương quan yếu hoặc nghịch",
x = NULL, y = NULL) +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
axis.text.x = element_text(size = 10, angle = 45, hjust = 1, face = "bold"),
axis.text.y = element_text(size = 10, face = "bold"),
legend.title = element_text(face = "bold", size = 11),
legend.text = element_text(size = 10))
Giải thích:
(4)-(6): chọn 10 biến tài chính chủ đạo để phân tích mối liên hệ tương quan.
(7)-(11): Tính ma trận tương quan Pearson sau đó chuyển dữ liệu sang dạng “dài” để ggplot2 có thể trực quan hóa.
(12)-(15): vẽ từng ô tương quan và hiển thị giá trị hệ số trong từng ô.
(16)-(21): Thiết lập dải màu gradient xanh → trắng → xanh đậm.
Nhận xét: NVL mở rộng quy mô nhanh nhưng lợi nhuận tăng chậm, cần tiếp tục tái cấu trúc nợ để đảm bảo an toàn tài chính. Tài sản, nợ và vốn tương quan chặt (r≈0.98–0.99) phản ánh tăng trưởng cân bằng. ROA–ROE và lợi nhuận gắn với quy mô (r≈0.73–0.95) cho thấy hiệu quả sinh lời thấp dần. Nợ và DR gần đồng biến (r≈1), tồn kho cao làm giảm hiệu quả (r<0.5).
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
ts_2024 <- BCTC_NVL %>%
filter(nam == 2024) %>%
summarise(
`Tài sản ngắn hạn` = tai_san_ngan_han,
`Tài sản dài hạn` = tai_san_dai_han,
`Tài sản cố định hữu hình` = tai_san_co_dinh_huu_hinh,
`Hàng tồn kho` = hang_ton_kho,
`Chi phí trả trước dài hạn` = chi_phi_tra_truoc_dai_han
) %>%
pivot_longer(cols = everything(),
names_to = "Khoan_muc",
values_to = "Gia_tri") %>%
mutate(Ty_trong = Gia_tri / sum(Gia_tri))
ggplot(ts_2024, aes(x = "", y = Ty_trong, fill = Khoan_muc)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(
label = ifelse(Ty_trong >= 0.01, paste0(round(Ty_trong * 100, 1), "%"), "")
),
position = position_stack(vjust = 0.5),
color = "black", size = 4, fontface = "bold") +
scale_fill_brewer(palette = "Set2") +
labs(
title = "Cơ cấu tài sản của NVL năm 2024",
subtitle = "Phân bổ tỷ trọng giữa các khoản mục tài sản chính",
fill = "Khoản mục tài sản") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 18, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
legend.title = element_text(face = "bold", size = 12),
legend.text = element_text(size = 11),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid = element_blank())
Giải thích:
(4)-(15): lọc dữ liệu năm 2024, lấy các khoản mục tài sản chính chuyển sang dạng dài và tính tỷ trọng (%) từng loại.
(16)-(24): vẽ biểu đồ tròn thể hiện tỷ lệ phân bổ tài sản, để hiển thị nhãn phần trăm cho từng phần có tỷ trọng ≥ 1% và gán màu.
Nhận xét: Tài sản ngắn hạn chiếm 53,5%, cho thấy khả năng thanh toán và linh hoạt tài chính tốt. Hàng tồn kho 37,9% phản ánh đặc thù ngành nhưng cần kiểm soát rủi ro. Tài sản dài hạn 7,7%, TSCĐ 0,5% cho thấy cơ cấu linh hoạt, chi phí thấp, hiệu quả vốn cao.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
ggplot(BCTC_NVL, aes(x = nam)) +
geom_line(aes(y = ROA * 100, color = "ROA"), linewidth = 1) +
geom_point(aes(y = ROA * 100, color = "ROA"), size = 2.5) +
geom_line(aes(y = ROE * 100, color = "ROE"), linewidth = 1, linetype = "dashed") +
geom_point(aes(y = ROE * 100, color = "ROE"), size = 2.5) +
geom_text(aes(y = ROA * 100, label = paste0(round(ROA * 100, 1), "%")),
vjust = -1, color = "#2E7D32", size = 4, fontface = "bold") +
geom_text(aes(y = ROE * 100,
label = paste0(round(ROE * 100, 1), "%"),
vjust = ifelse(nam == 2020, 3, -1.1)),
color = "#1565C0", size = 4, fontface = "bold") +
scale_color_manual(values = c("ROA" = "#2E7D32", "ROE" = "#1565C0")) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
scale_y_continuous(labels = label_percent(scale = 1)) +
labs(
title = "Hiệu quả sinh lời của NVL (2015–2024)",
subtitle = "So sánh giữa ROA (hiệu quả tài sản) và ROE (hiệu quả vốn chủ sở hữu)",
x = "Năm", y = "Tỷ suất lợi nhuận (%)", color = "Chỉ tiêu") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray25"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray80", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(16): vẽ hai đường biểu diễn ROA và ROE, gắn nhãn phần trăm cho từng giá trị và gán màu riêng cho từng chỉ tiêu.
Nhận xét: Giai đoạn 2015–2017, ROA và ROE tăng mạnh cho thấy hiệu quả sử dụng vốn cao. Năm 2018–2020 đạt đỉnh (ROA ~9,7%, ROE ~37,7%). Từ 2021–2024, ROA giảm còn 5,6%, ROE duy trì ~28–29% phản ánh khả năng sinh lời ổn định nhưng phụ thuộc đòn bẩy tài chính.
library(ggridges)
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
BCTC_NVL <- BCTC_NVL %>%
mutate(DR = tong_no / tong_tai_san)
financial_ratios <- BCTC_NVL %>%
select(nam, ROA, ROE, DR) %>%
pivot_longer(-nam, names_to = "Chỉ_tiêu", values_to = "Giá_trị")
ggplot(financial_ratios, aes(x = Giá_trị, y = Chỉ_tiêu, fill = Chỉ_tiêu)) +
geom_density_ridges(alpha = 0.85, scale = 1.1, color = "white", linewidth = 0.4) +
scale_fill_manual(values = c(
"ROA" = "#81C784",
"ROE" = "#64B5F6",
"DR" = "#FFD54F")) +
labs(
title = "Phân bố các tỷ số tài chính của NVL (2015–2024)",
subtitle = "Biểu đồ thể hiện mật độ phân bố của ROA, ROE và DR",
x = "Giá trị tỷ số", y = "Chỉ tiêu") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray35"),
legend.position = "none",
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"))
Giải thích:
(1)-(4): khai báo gói, thiết lập font TimesVN và theme hiển thị chuẩn tiếng Việt.
(5)-(6): tạo biến mới DR = Tổng nợ / Tổng tài sản.
(7)-(9): gom dữ liệu của ba chỉ tiêu ROA, ROE, DR vào một cột để dễ trực quan hóa.
(10)-(16): vẽ biểu đồ phân bố mật độ và đặt màu riêng cho từng chỉ tiêu: xanh lá (ROA), xanh dương (ROE), vàng (DR).
Nhận xét: ROA tập trung quanh mức thấp, biến động nhỏ cho thấy hiệu quả tài sản ổn định. ROE có hai đỉnh phản ánh giai đoạn đầu sinh lời thấp và sau tăng mạnh. DR lệch phải (70–85%) cho thấy đòn bẩy tài chính cao, phụ thuộc vốn vay.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
pareto_data <- BCTC_NVL %>%
filter(nam == 2024) %>%
summarise(
`Tài sản ngắn hạn` = tai_san_ngan_han,
`Hàng tồn kho` = hang_ton_kho,
`Tài sản cố định hữu hình` = tai_san_co_dinh_huu_hinh
) %>%
pivot_longer(cols = everything(), names_to = "Khoản_mục", values_to = "Giá_trị") %>%
arrange(desc(Giá_trị)) %>%
mutate(
Tỷ_trọng = Giá_trị / sum(Giá_trị),
Tích_lũy = cumsum(Tỷ_trọng))
ggplot(pareto_data, aes(x = reorder(Khoản_mục, -Giá_trị))) +
geom_col(aes(y = Giá_trị), fill = "#F48FB1", alpha = 0.85) +
geom_text(aes(y = Giá_trị, label = comma(round(Giá_trị, 0))),
vjust = -0.6, size = 4,
fontface = "bold", color = "#0D47A1") +
geom_line(aes(y = Tích_lũy * max(Giá_trị), group = 1),
color = "#E64A19", linewidth = 1) +
geom_point(aes(y = Tích_lũy * max(Giá_trị)),
color = "#D84315", size = 2.5) +
geom_text(aes(y = Tích_lũy * max(Giá_trị),
label = paste0(round(Tích_lũy * 100, 1), "%")),
vjust = -1, size = 4, color = "#BF360C",
fontface = "bold") +
scale_y_continuous(
name = "Giá trị (tỷ đồng)",
sec.axis = sec_axis(~ . / max(pareto_data$Giá_trị),
name = "Tỷ trọng tích lũy",
labels = label_percent(accuracy = 1)),
expand = expansion(mult = c(0, 0.15))) +
labs(
title = "Đóng góp các khoản mục trong Tài sản ngắn hạn năm 2024",
subtitle = "Cột màu xanh biểu thị giá trị tuyệt đối, đường màu cam thể hiện tỷ trọng tích lũy",
x = "Khoản mục TSNH", y = "Giá trị (tỷ đồng)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 15, face = "bold", hjust = 0.5, color = "Black"),
plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray35"),
axis.text.x = element_text(size = 11, face = "bold", angle = 15, hjust = 1),
axis.text.y = element_text(size = 11, face = "bold"),
axis.title = element_text(size = 12, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dotted"))
Giải thích:
(4)-(16): lọc dữ liệu năm 2024, lấy ba khoản mục tài sản chính để tính tỷ trọng và tích lũy (%) của từng khoản mục.
(17)-(33): dựng biểu đồ gồm cột biểu diễn giá trị tuyệt đối và đường thể hiện tỷ lệ tích lũy, gắn nhãn số và phần trăm trực tiếp trên biểu đồ, thiết lập trục phụ hiển thị tỷ trọng tích lũy theo %.
Nhận xét: Tài sản ngắn hạn chiếm 58,3% (207.831 tỷ đồng) thể hiện thanh khoản cao. Hàng tồn kho 41,6% (147.028 tỷ) phản ánh đặc trưng ngành nhưng hạn chế luân chuyển vốn. Tài sản cố định chỉ 0,5% (1.876 tỷ) cho thấy NVL tập trung vốn vào dự án.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
lollipop_data <- BCTC_NVL %>%
mutate(nam = as.numeric(as.character(nam)))
ggplot(lollipop_data, aes(x = nam, y = loi_nhuan_sau_thue)) +
geom_segment(aes(x = nam, xend = nam, y = 0, yend = loi_nhuan_sau_thue),
color = "gray80", linewidth = 2) +
geom_point(color = "#FF7043", size = 5, alpha = 0.9) +
geom_text(aes(label = comma(round(loi_nhuan_sau_thue, 0))),
vjust = -1, color = "#BF360C", size = 4) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
scale_y_continuous(
labels = label_comma(big.mark = ",", suffix = " tỷ"),
expand = expansion(mult = c(0, 0.08))) +
labs(
title = "Lợi nhuận sau thuế của NVL (2015–2024)",
subtitle = "Minh họa sự thay đổi lợi nhuận qua các năm bằng thanh que và đầu tròn",
x = "Năm", y = "Lợi nhuận sau thuế (tỷ đồng)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#E64A19"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray35"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(5): chuyển biến nam sang dạng số để sắp xếp chính xác theo năm.
(6)-(15): tạo thanh dọc biểu diễn giá trị lợi nhuận từng năm, thêm đầu tròn thể hiện đỉnh lợi nhuận, hiển thị nhãn số rõ ràng ngay trên đầu cột và định dạng trục, thêm dấu phẩy phân cách hàng nghìn và đơn vị “tỷ đồng”.
Nhận xét: Giai đoạn 2015–2020, lợi nhuận sau thuế tăng mạnh từ 550 lên 12.051 tỷ đồng cho thấy tăng trưởng vượt trội. Từ 2021–2024, lợi nhuận chững quanh 10.000–13.000 tỷ do chi phí vốn và nợ vay cao phản ánh giai đoạn bão hòa sau tăng trưởng mạnh.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
smooth_data <- BCTC_NVL %>%
mutate(nam = as.numeric(as.character(nam))) %>%
select(nam, tong_tai_san, tong_no, von_chu_so_huu, loi_nhuan_sau_thue) %>%
rename(
`Tổng tài sản` = tong_tai_san,
`Tổng nợ` = tong_no,
`Vốn chủ sở hữu` = von_chu_so_huu,
`Lợi nhuận sau thuế` = loi_nhuan_sau_thue
) %>%
pivot_longer(cols = -nam, names_to = "Chỉ_tiêu", values_to = "Giá_trị")
ggplot(smooth_data, aes(x = nam, y = Giá_trị, color = `Chỉ_tiêu`)) +
geom_line(linewidth = 1, alpha = 0.9) +
geom_smooth(se = FALSE, linewidth = 0.8, linetype = "dashed") +
scale_color_manual(values = c(
"Tổng tài sản" = "#1565C0",
"Tổng nợ" = "#E64A19",
"Vốn chủ sở hữu" = "#2E7D32",
"Lợi nhuận sau thuế" = "#8E24AA")) +
scale_y_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
labs(
title = "Xu hướng tài chính của NVL (2015–2024)",
subtitle = "Đường nét thể hiện biến động quy mô tài chính mà không hiển thị giá trị số",
x = "Năm", y = "Giá trị (tỷ đồng)", color = "Chỉ tiêu") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray30"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(13): chuyển dữ liệu thành dạng dài để dễ dàng phân tích sự thay đổi qua các năm và đổi tên các cột tài chính chính như tổng tài sản, nợ, lợi nhuận sau thuế.
(14)-(23): vẽ đường thể hiện xu hướng biến động từng chỉ tiêu tài chính và thêm đường mượt giúp nhìn rõ xu hướng tổng quát, không bị ảnh hưởng bởi biến động, đặt màu sắc riêng cho các chỉ tiêu tài chính và định dạng trục X, Y.
Nhận xét: Biểu đồ thể hiện cấu trúc tài chính đồng biến và ổn định, sau 2022, NVL chuyển từ tăng trưởng nóng sang phát triển bền vững hơn.
Tổng tài sản: Tăng mạnh từ 16.570 tỷ (2015) lên 257.735 tỷ (2022), sau đó giảm nhẹ còn 237.778 tỷ (2024) cho thấy NVL bước vào giai đoạn tái cơ cấu và điều chỉnh quy mô sau thời kỳ mở rộng.
Tổng nợ: Tăng song song với tài sản, đạt đỉnh trên 200.000 tỷ (2022) rồi giảm phản ánh xu hướng giảm đòn bẩy và kiểm soát rủi ro tài chính.
Vốn chủ sở hữu: Tăng đều nhưng chậm hơn tài sản cho thấy NVL vẫn dựa nhiều vào nợ song vẫn duy trì mức tự chủ ổn định.
Lợi nhuận sau thuế: Tăng mạnh đến 2022 (≈13.500 tỷ) sau đó chững lại thể hiện tác động từ thị trường bất động sản.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
waterfall_data <- BCTC_NVL %>%
arrange(nam) %>%
mutate(
Thay_doi = tong_tai_san - lag(tong_tai_san),
Loai = case_when(
is.na(Thay_doi) ~ "Giá trị đầu kỳ",
Thay_doi >= 0 ~ "Tăng",
TRUE ~ "Giảm")) %>%
mutate(
Gia_tri_bat_dau = lag(cumsum(replace_na(Thay_doi, 0)), default = 0),
Gia_tri_ket_thuc = cumsum(replace_na(Thay_doi, 0)))
ggplot(waterfall_data, aes(x = factor(nam))) +
geom_rect(aes(
xmin = as.numeric(factor(nam)) - 0.35,
xmax = as.numeric(factor(nam)) + 0.35,
ymin = Gia_tri_bat_dau,
ymax = Gia_tri_ket_thuc,
fill = Loai
), color = "gray40") +
geom_text(aes(
x = factor(nam),
y = ifelse(Loai == "Giảm", Gia_tri_ket_thuc - 15000,
Gia_tri_ket_thuc + 8000),
label = comma(round(tong_tai_san, 0))),
size = 4, color = "black") +
scale_fill_manual(values = c(
"Tăng" = "#81C784",
"Giảm" = "#E57373",
"Giá trị đầu kỳ" = "#64B5F6")) +
labs(
title = "Biểu đồ biến động tổng tài sản của NVL (2015–2024)",
subtitle = "Thể hiện mức tăng và giảm của Tổng tài sản qua các năm",
x = "Năm", y = "Giá trị (tỷ đồng)",
fill = "Xu hướng") +
scale_y_continuous(
labels = label_comma(big.mark = ",", suffix = " tỷ"),
expand = expansion(mult = c(0, 0.1))) +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray30"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85", linetype = "dotted"),
plot.margin = margin(10, 15, 15, 15))
Giải thích:
(4)-(14): sắp xếp dữ liệu theo năm để tính thay đổi của tổng tài sản mỗi năm và phân loại các thay đổi, tính giá trị đầu kỳ và cuối kỳ dựa trên sự thay đổi tích lũy.
(15)-(32): dựng biểu đồ thay đổi từng giai đoạn có gắn nhãn tổng tài sản tại mỗi điểm, đặt màu sắc cho các mức tăng, giảm và đặt nhãn cho trục X, Y.
Nhận xét: Giai đoạn 2015–2018, tổng tài sản tăng ổn định từ 26.570 lên 69.912 tỷ đồng phản ánh tích lũy bền vững. Từ 2019–2021, tăng vọt vượt 200.000 tỷ đồng cho thấy mở rộng mạnh và huy động vốn hiệu quả. Năm 2022 đạt đỉnh 257.735 tỷ, sau đó 2023–2024 giảm nhẹ do thị trường khó khăn và tái cơ cấu đầu tư.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
dr_rank <- BCTC_NVL %>%
mutate(
nam = as.numeric(as.character(nam)),
DR = tong_no / tong_tai_san
) %>%
select(nam, DR) %>%
mutate(
DR_rank = rank(-DR),
DR_label = round(DR * 100, 1))
ggplot(dr_rank, aes(x = nam, y = DR_rank)) +
geom_bump(linewidth = 1.6, smooth = 8, color = "#1976D2") +
geom_point(size = 4, color = "#0D47A1") +
geom_text(aes(label = paste0(DR_label, "%")),
nudge_y = 0.8,
size = 4.3, color = "#0D47A1") +
scale_y_reverse(breaks = 1:max(dr_rank$DR_rank)) +
scale_x_continuous(breaks = seq(2015, 2024, 1),
expand = expansion(mult = c(0.02, 0.08))) +
labs(
title = "Thứ hạng tỷ lệ nợ của NVL theo năm (2015–2024)",
subtitle = "Biểu đồ Bump thể hiện sự thay đổi vị trí xếp hạng tỷ lệ nợ qua thời gian",
x = "Năm", y = "Thứ hạng") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray35"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(9): chuyển cột “nam” về dạng số, tạo biến DR = tong_no / tong_tai_san và giữ lại hai biến chính: nam và DR.
(10)-(12): tạo biến DR_rank = rank(-DR) và DR_label để hiển thị giá trị phần trăm của tỷ lệ nợ.
(13)-(18): khởi tạo biểu đồ ggplot, trục X là năm, trục Y là DR_rank, vẽ đường cong thể hiện thay đổi thứ hạng theo thời gian, thêm các điểm tròn tại vị trí từng năm và gắn nhãn phần trăm tỷ lệ nợ trên từng điểm.
(19)-(21): đảo trục Y và tùy chỉnh trục X hiển thị từ 2015 đến 2024 và thêm khoảng giãn nhỏ hai đầu đồ thị.
Nhận xét: Tỷ lệ nợ (DR) tăng mạnh suốt 10 năm thể hiện chiến lược dùng đòn bẩy tài chính để mở rộng quy mô. Mức >80% gần đây cho thấy áp lực lớn, cần kiểm soát nợ và chi phí vốn. Sau 2022, DR giảm nhẹ phản ánh nỗ lực tái cơ cấu, hướng tới cân bằng tài chính an toàn hơn.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
heat_data <- BCTC_NVL %>%
mutate(
growth_TS = (tong_tai_san / lag(tong_tai_san) - 1) * 100,
growth_LN = (loi_nhuan_sau_thue / lag(loi_nhuan_sau_thue) - 1) * 100,
growth_NO = (tong_no / lag(tong_no) - 1) * 100
) %>%
select(nam, growth_TS, growth_LN, growth_NO) %>%
filter(nam != 2015) %>%
pivot_longer(cols = -nam, names_to = "Chỉ_tiêu", values_to = "Tăng_trưởng")
ggplot(heat_data, aes(x = factor(nam), y = Chỉ_tiêu, fill = Tăng_trưởng)) +
geom_tile(color = "white", linewidth = 0.6) +
scale_fill_gradient2(
low = "#FFB6B9",
mid = "#FFF5BA",
high = "#8FD9A8",
midpoint = 0,
limits = c(min(heat_data$Tăng_trưởng, na.rm = TRUE),
max(heat_data$Tăng_trưởng, na.rm = TRUE)),
name = "Tăng trưởng (%)") +
labs(
title = "Ma trận tốc độ tăng trưởng của NVL (2016–2024)",
subtitle = "Màu xanh thể hiện tăng, vàng là ổn định, hồng là giảm",
x = "Năm", y = "Chỉ tiêu") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold", hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray35"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
panel.grid = element_blank(),
legend.position = "right",
legend.title = element_text(face = "bold"))
Giải thích:
(4)-(9): tạo ba biến mới biểu diễn tốc độ tăng trưởng: growth_TS: tăng trưởng tổng tài sản, growth_LN: tăng trưởng lợi nhuận sau thuế, growth_NO: tăng trưởng tổng nợ bằng cách lấy giá trị của năm trước để tính chênh lệch tỷ lệ.
(10)-(12): giữ lại cột: năm và ba chỉ tiêu tăng trưởng, loại bỏ năm 2015 và chuyển dữ liệu sang dạng “dài”, mỗi dòng là một năm.
(13)-(22): khởi tạo biểu đồ ggplot, trục X là năm, trục Y là chỉ tiêu, và màu sắc thể hiện mức tăng trưởng và tạo ô màu cho từng cặp năm vs chỉ tiêu.
Nhận xét: Năm 2015 bị loại do thiếu dữ liệu so sánh. Giai đoạn 2016–2018 thể hiện tăng trưởng mạnh, nhất là lợi nhuận và nợ. Giai đoạn 2019–2021 cho thấy ổn định, tái cơ cấu vốn. Từ 2022–2024 phản ánh tăng trưởng chậm, phù hợp xu hướng giảm tốc thị trường.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
ts_ratio <- BCTC_NVL %>%
select(nam, tai_san_ngan_han, tai_san_dai_han,
hang_ton_kho, tai_san_co_dinh_huu_hinh) %>%
mutate(
`Tài sản ngắn hạn` = tai_san_ngan_han,
`Tài sản dài hạn` = tai_san_dai_han,
`Hàng tồn kho` = hang_ton_kho,
`Tài sản hữu hình` = tai_san_co_dinh_huu_hinh
) %>%
select(nam, `Tài sản ngắn hạn`, `Tài sản dài hạn`,
`Hàng tồn kho`, `Tài sản hữu hình`) %>%
pivot_longer(cols = -nam, names_to = "Khoản_mục", values_to = "Giá_trị") %>%
group_by(nam) %>%
mutate(Tỷ_trọng = Giá_trị / sum(Giá_trị))
ggplot(ts_ratio, aes(x = nam, y = Tỷ_trọng, fill = Khoản_mục)) +
geom_area(alpha = 0.85, color = "white") +
scale_fill_manual(values = c(
"Tài sản ngắn hạn" = "#81C784",
"Tài sản dài hạn" = "#64B5F6",
"Hàng tồn kho" = "#FFB74D",
"Tài sản hữu hình" = "Red")) +
scale_y_continuous(labels = label_percent(accuracy = 1)) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
labs(
title = "Cơ cấu tỷ trọng tài sản của NVL (2015–2024)",
subtitle = "Biểu đồ tỷ trọng giữa các loại tài sản qua thời gian",
x = "Năm", y = "Tỷ trọng (%)", fill = "Khoản mục tài sản") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 17, face = "bold",
hjust = 0.5, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray30"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85", linetype = "dotted"))
Giải thích:
(4)-(17): chọn các biến tài sản chính từ tài sản ngắn hạn, tài sản dài hạn, hàng tồn kho và tài sản cố định hữu hình, đổi tên cột thành tiếng Việt, giữ lại các cột vừa đổi tên cùng biến năm, nhóm theo năm và tính tỷ trọng (%) của từng loại tài sản trong tổng tài sản năm đó.
(18)-(26): khởi tạo biểu đồ ggplot, trục X là năm, trục Y là tỷ trọng, tô màu theo khoản mục, tạo biểu đồ vùng chồng (stacked area) thể hiện tỷ trọng từng nhóm và thiết lập bảng màu riêng cho từng loại tài sản với định dạng trục Y hiển thị theo phần trăm, trục X hiển thị từ 2015 đến 2024.
Nhận xét: Tài sản ngắn hạn chiếm 50–60% thể hiện chiến lược duy trì thanh khoản cao cho hoạt động dự án. Hàng tồn kho 35–40% phản ánh đặc trưng ngành và được kiểm soát ổn định. Tài sản dài hạn 10–15% cho thấy đầu tư bền vững, còn TSCĐ hữu hình rất nhỏ (~0,5%) phù hợp mô hình phát triển dự án.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
BCTC_NVL <- BCTC_NVL %>%
mutate(nam = as.numeric(as.character(nam)))
area4_data <- BCTC_NVL %>%
select(nam, tong_tai_san, tong_no, von_chu_so_huu, loi_nhuan_sau_thue) %>%
rename(
`Tổng tài sản` = tong_tai_san,
`Tổng nợ` = tong_no,
`Vốn chủ sở hữu` = von_chu_so_huu,
`Lợi nhuận sau thuế` = loi_nhuan_sau_thue
) %>%
pivot_longer(
cols = c(`Tổng tài sản`, `Tổng nợ`, `Vốn chủ sở hữu`, `Lợi nhuận sau thuế`),
names_to = "Chỉ tiêu",
values_to = "Giá trị")
ggplot(area4_data, aes(x = nam, y = `Giá trị`, fill = `Chỉ tiêu`)) +
geom_area(alpha = 0.6, position = "identity",
color = "black", linewidth = 0.2) +
geom_line(aes(color = `Chỉ tiêu`), linewidth = 1.1) +
geom_point(aes(color = `Chỉ tiêu`), size = 2.8) +
scale_fill_manual(values = c(
"Tổng tài sản" = "#64B5F6",
"Tổng nợ" = "#FFB74D",
"Vốn chủ sở hữu" = "#81C784",
"Lợi nhuận sau thuế" = "#F48FB1")) +
scale_color_manual(values = c(
"Tổng tài sản" = "#1565C0",
"Tổng nợ" = "#E65100",
"Vốn chủ sở hữu" = "#2E7D32",
"Lợi nhuận sau thuế" = "#AD1457")) +
scale_y_continuous(labels = label_comma(big.mark = ",", suffix = " tỷ")) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
labs(
title = "Biến động quy mô và hiệu quả tài chính của NVL (2015–2024)",
subtitle = "Biểu đồ cấu trúc tài chính và xu hướng tăng trưởng qua thời gian",
x = "Năm", y = "Giá trị (tỷ đồng)",
fill = "Chỉ tiêu", color = "Chỉ tiêu") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 16, face = "bold",
hjust = 1, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 1, color = "gray30"),
axis.title = element_text(size = 11, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
legend.position = "top",
legend.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(17): chuyển biến năm sang dạng số, chọn 4 biến: tổng tài sản, tổng nợ, vốn chủ sở hữu và lợi nhuận sau thuế, đổi tên các cột sang tiếng Việt và chuyển dữ liệu từ dạng rộng sang dài.
(18)-(22): khởi tạo biểu đồ ggplot, trục X là năm, trục Y là giá trị (tỷ đồng), tô màu theo “Chỉ tiêu”, thêm đường viền và điểm dữ liệu để nhấn mạnh xu hướng từng chỉ tiêu.
(23)-(32): thiết lập màu nền cho từng chỉ tiêu: xanh cho tài sản, cam cho nợ, xanh lá cho vốn, hồng cho lợi nhuận và đặt màu đường (line) tương ứng.
(33)-(34): trục Y hiển thị đơn vị “tỷ đồng” với dấu phẩy ngăn cách hàng nghìn, trục X hiển thị từ năm 2015 đến 2024.
Nhận xét: Tổng tài sản NVL tăng gần 15 lần (2015–2022), sau đó giảm nhẹ 2023–2024 cho thấy giai đoạn tái cơ cấu. Nợ tăng nhanh hơn vốn chủ, đòn bẩy tài chính cao, rủi ro tăng. Lợi nhuận đạt đỉnh 2020–2021 rồi giảm, biên lợi nhuận thu hẹp. Do đó, NVL tăng trưởng mạnh nhưng hiệu quả sử dụng vốn suy giảm.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
BCTC_NVL <- BCTC_NVL %>%
mutate(nam = as.numeric(as.character(nam)))
ggplot(BCTC_NVL, aes(x = nam, y = ROE * 100)) +
geom_ribbon(aes(ymin = (ROE * 100) - 5, ymax = (ROE * 100) + 5),
fill = "#BBDEFB", alpha = 0.4) +
geom_line(color = "#1565C0", linewidth = 1.5) +
geom_point(size = 3.5, color = "#0D47A1") +
geom_text(aes(y = ROE * 100,
label = paste0(round(ROE * 100, 1), "%"),
vjust = ifelse(nam == 2020, 3, -1.2)),
color = "#1565C0", size = 4) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
scale_y_continuous(labels = label_percent(scale = 1)) +
labs(
title = "Biến động tỷ suất lợi nhuận trên vốn chủ sở hữu của NVL (2015–2024)",
subtitle = "Đường thể hiện xu hướng ROE, vùng mờ biểu thị biên độ biến động ±5%",
x = "Năm", y = "Tỷ suất ROE (%)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 16, face = "bold",
hjust = 0.7, color = "#0D47A1"),
plot.subtitle = element_text(size = 13, hjust = 0.5, color = "gray30"),
axis.title = element_text(size = 13, face = "bold"),
axis.text = element_text(size = 12, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray85", linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(5): chuyển cột nam sang kiểu số (numeric) để vẽ đúng trục thời gian.
(6)-(10): khởi tạo biểu đồ ggplot với trục hoành là năm và trục tung là ROE (%), vẽ vùng mờ ±5% quanh đường ROE màu xanh nhạt, vẽ đường xu hướng ROE theo thời gian màu xanh dương đậm và thêm các điểm dữ liệu cho từng năm để dễ quan sát.
(11)-(16): hiển thị nhãn giá trị ROE, điều chỉnh vị trí nhãn, cài đặt trục X hiển thị từ 2015–2024, trục Y hiển thị theo đơn vị phần trăm (%).
Nhận xét: ROE tăng mạnh từ 9% (2015) lên đỉnh 37,7% (2020) phản ánh hiệu quả sử dụng vốn vượt trội. Giai đoạn 2021–2024, ROE giảm còn 28,1% nhưng vẫn cao cho thấy năng lực sinh lời tốt dù thị trường biến động. Xu hướng giảm sau 2020 cho thấy cần kiểm soát chi phí và tối ưu vốn để duy trì hiệu quả.
font_add("TimesVN", "C:/Windows/Fonts/times.ttf")
showtext_auto()
theme_set(theme_minimal(base_family = "TimesVN"))
combo_data <- BCTC_NVL %>%
mutate(nam = as.numeric(as.character(nam)))
ggplot(combo_data, aes(x = nam)) +
geom_col(aes(y = tong_tai_san / 1e3), fill = "#64B5F6", alpha = 0.85) +
geom_text(aes(y = tong_tai_san / 1e3,
label = comma(round(tong_tai_san / 1e3, 0))),
vjust = -0.9, size = 4, color = "#0D47A1", fontface = "bold") +
geom_line(aes(y = ROE * 100 * max(tong_tai_san / 1e3) / 100),
color = "#E64A19", linewidth = 1) +
geom_point(aes(y = ROE * 100 * max(tong_tai_san / 1e3) / 100),
color = "#BF360C", size = 2) +
scale_y_continuous(
name = "Tổng tài sản (nghìn tỷ đồng)",
sec.axis = sec_axis(~ . / max(combo_data$tong_tai_san / 1e3) * 100,
name = "Tỷ suất sinh lời trên vốn chủ sở hữu (ROE, %)",
labels = label_percent(accuracy = 1)),
expand = expansion(mult = c(0, 0.1))) +
scale_x_continuous(breaks = seq(2015, 2024, 1)) +
labs(
title = "Tổng tài sản và Hiệu quả sinh lời (ROE) của NVL (2015–2024)",
subtitle = "Cột thể hiện quy mô tài sản; Đường biểu thị tỷ suất lợi nhuận ROE (%)",
x = "Năm", y = "Tổng tài sản (nghìn tỷ đồng)") +
theme_minimal(base_family = "TimesVN") +
theme(
plot.title = element_text(size = 15,
face = "bold",
hjust = 0.5,
color = "#0D47A1"),
plot.subtitle = element_text(size = 12,
hjust = 0.5,
color = "gray40"),
axis.title = element_text(size = 12, face = "bold"),
axis.text = element_text(size = 11, face = "bold"),
panel.grid.minor = element_blank(),
panel.grid.major.y = element_line(color = "gray90",
linetype = "dotted"),
plot.margin = margin(15, 15, 15, 15))
Giải thích:
(4)-(5): chuẩn hóa nam sang số để vẽ trục thời gian.
(6)-(10): khởi tạo ggplot theo trục X = năm, cột biểu diễn tổng tài sản theo đơn vị nghìn tỷ và vẽ ROE lên trục phụ bằng cách nhân ROE với max(tong_tai_san/1e3)/100.
(11)-(16): đặt tên trục trái, đảo phép biến đổi để hiện ROE (%) đúng trên trục phải, trục X hiển thị mốc 2015–2024.
Nhận xét: Giai đoạn 2015–2022, tài sản NVL tăng từ 27 lên 258 nghìn tỷ thể hiện mở rộng mạnh. Từ 2023–2024, giảm nhẹ còn 238 nghìn tỷ cho thấy tái cơ cấu. ROE đạt đỉnh ~10% năm 2020 rồi giảm 2–3%, phản ánh quy mô tăng nhưng hiệu quả giảm.