Trong kỷ nguyên tài chính định lượng, các quyết định đầu tư ngày càng được dẫn dắt bởi sự phân tích chặt chẽ các chỉ số hiệu suất, định giá và yếu tố rủi ro. Nghiên cứu này tập trung vào việc áp dụng ngôn ngữ lập trình R để thực hiện phân tích chuyên sâu về mối liên hệ giữa các Chỉ số tài chính, định giá, và yếu tố môi trường, xã hội và quản trị (ESG) với hiệu suất đầu tư thực tế.
Bộ dữ liệu nền tảng là “400K NYSE Random Investments + Financial Ratios” (thu thập từ Kaggle), mô phỏng hơn 400.000 giao dịch đầu tư ngẫu nhiên vào các cổ phiếu niêm yết trên sàn giao dịch chứng khoán New York (NYSE) trong giai đoạn 2013-2018. Khác với các phân tích tập trung vào Hành vi Giao dịch, nghiên cứu này khai thác Nhóm Biến 2 (Chỉ số Công ty, Định giá, ESG), bao gồm các chỉ số trọng yếu như tỷ số giá/thu nhập (PE), tỷ suất sinh lời trên vốn chủ sở hữu (ROE), đòn bẩy tài chính (Leverage_Ratio), và xếp hạng ESG.
Nghiên cứu này được thực hiện với các mục tiêu định lượng và khám phá cụ thể như sau:
Lượng hóa đặc trưng phân bố: Thực hiện các tiêu
chí như thống kê mô tả, tương quan, và kiểm định giả thuyết) để lượng
hóa độ tập trung, độ phân tán và hình dạng phân bố của các chỉ số tài
chính và lợi suất thực tế (Real_Return).
Trực quan hóa khám phá: Xây dựng tối thiểu các
biểu đồ để trực quan hóa mối quan hệ giữa các chỉ số
(Log_PE, ROE, ESG) và hiệu suất
đầu tư.
Kiểm định Giả thuyết: Kiểm tra sự khác biệt có ý
nghĩa thống kê về hiệu suất đầu tư (Real_Return) và đặc
điểm tài chính (ví dụ: Log_PE) giữa các nhóm ngành
(sector) và nhóm kết quả đầu tư (investment
GOOD/BAD) thông qua các kiểm định như \(t\)-test và ANOVA.
Kiểm soát Độ tin cậy: Thực hiện nhận diện và xử
lý Outlier trong các biến số quan trọng (như Real_Return,
PE_ratio) để đảm bảo các kết quả thống kê và kiểm định là
đáng tin cậy.
Phạm vi phân tích sẽ giới hạn trong các biến thuộc Nhóm 2, bao gồm:
Real_Return (Biến phụ thuộc), Log_PE,
PB, PS, ROE, ROA,
EPS, NetProfitMargin,
Current_Ratio, Leverage_Ratio,
ESG, và các biến phân loại liên quan (sector,
investment).
Lý thuyết ESG bắt nguồn từ các nền tảng của Thuyết các bên liên quan (Stakeholder Theory – Freeman, 1984) và Thuyết hợp pháp hóa (Legitimacy Theory), cho rằng doanh nghiệp không chỉ chịu trách nhiệm với cổ đông mà còn với toàn bộ các bên liên quan bao gồm nhân viên, khách hàng, cộng đồng và môi trường. Thực hiện tốt các tiêu chí về môi trường (E), xã hội (S), và quản trị (G) giúp doanh nghiệp giảm thiểu rủi ro pháp lý, nâng cao uy tín, tăng cường niềm tin của nhà đầu tư, đồng thời cải thiện hiệu quả tài chính dài hạn (Eccles, Ioannou & Serafeim, 2014; Fatemi et al., 2018).
Theo hướng tiếp cận này, điểm số ESG (ESG) phản ánh
chất lượng quản trị và cam kết phát triển bền vững của doanh nghiệp, từ
đó ảnh hưởng tích cực đến tỷ suất sinh lời (ROE, ROA)
và hiệu suất đầu tư thực tế (Real_Return). Các nghiên
cứu gần đây cũng chỉ ra rằng doanh nghiệp có điểm ESG cao thường có
chi phí vốn thấp hơn, dễ thu hút dòng vốn đầu tư bền
vững và đạt mức lợi nhuận điều chỉnh rủi ro cao hơn so
với nhóm còn lại. Trong nghiên cứu này, biến ESG được dùng
để kiểm định vai trò của hiệu suất bền vững trong việc giải thích sự
khác biệt về lợi suất đầu tư giữa các công ty niêm yết.
Trước khi đi vào phân tích chuyên sâu nhóm biến 2, ta cần làm sạch,
chuẩn hóa và tạo biến phái sinh đã được thực hiện trên dữ liệu gốc
(nyse_raw). Quá trình này bao gồm việc loại bỏ cột thừa
(...1, date_SELL_fix), chuẩn hóa tên biến,
chuyển đổi kiểu dữ liệu (từ character sang
factor cho sector, investment),
và tạo ra các biến mới có ý nghĩa tài chính/thống kê như sau:
Real_Return: Lợi suất thực tế (sau khi
điều chỉnh lạm phát).Log_PE: Logarit tự nhiên của Tỷ số P/E
(nhằm chuẩn hóa phân bố lệch phải nặng).Leverage_Ratio: Tỷ số Đòn bẩy Tài
chính.1. # KHỐI NÀY GIẢ ĐỊNH QUÁ TRÌNH TIỀN XỬ LÝ ĐÃ HOÀN TẤT
2. # nyse_processed <- nyse_raw %>%
3. # select(-c("...1", "date_SELL_fix")) %>%
4. # rename(Horizon_Days = `horizon (days)`, Nominal_Return = nominal_return,
5. # Expected_Return_Yr = `expected_return (yearly)`, ESG = ESG_ranking,
6. # PE = PE_ratio, EPS = EPS_ratio, PS = PS_ratio, PB = PB_ratio,
7. # NetProfitMargin = NetProfitMargin_ratio, Current_Ratio = current_ratio,
8. # ROA = roa_ratio, ROE = roe_ratio) %>%
9. # mutate(
10. # sector = as.factor(sector),
11. # investment = as.factor(investment),
12. # Date_Buy = as.Date(date_BUY_fix),
13. # # Feature Engineering
14. # Real_Return = Nominal_Return - inflation,
15. # Log_PE = log(PE),
16. # Leverage_Ratio = 1 / (1 - (PB / (ROE/100))),
17. )
18. # # TẠO BỘ DỮ LIỆU NHÓM 2 CỐT LÕI
19. # nyse_group2_data <- nyse_processed %>%
20. # select(company, sector, Date_Buy, Buy_Year, Buy_Quarter, investment, Real_Return,
21. # Log_PE, PB, PS, ROE, ROA, EPS, NetProfitMargin, Current_Ratio, Leverage_Ratio, ESG)
22. # # Lưu bộ dữ liệu (giả định đã lưu)
23. # # save(nyse_group2_data, file = "nyse_group2_data.RData") 1. if (!exists("nyse_group2_data")) {
2. nyse_group2_data <- nyse_raw %>%
3. select(-c("...1", "date_SELL_fix")) %>%
4. rename(Horizon_Days = `horizon (days)`, Nominal_Return = nominal_return,
5. Expected_Return_Yr = `expected_return (yearly)`, ESG = ESG_ranking,
6. PE = PE_ratio, EPS = EPS_ratio, PS = PS_ratio, PB = PB_ratio,
7. NetProfitMargin = NetProfitMargin_ratio, Current_Ratio = current_ratio,
8. ROA = roa_ratio, ROE = roe_ratio,
9. Date_Buy = date_BUY_fix, investment = investment) %>%
10. mutate(
11. sector = as.factor(sector),
12. investment = as.factor(investment),
13. Buy_Year = factor(year(Date_Buy)),
14. Buy_Quarter = factor(quarter(Date_Buy, with_year = TRUE)),
15. Real_Return = Nominal_Return - inflation,
16. Log_PE = ifelse(PE > 0, log(PE), NA),
17. Leverage_Ratio = ifelse(ROE != 0 & PB != 0, abs(PB / (ROE/100)), NA)
18. ) %>%
19. select(company, sector, Date_Buy, Buy_Year, Buy_Quarter, investment, Real_Return,
20. Log_PE, PB, PS, ROE, ROA, EPS, NetProfitMargin, Current_Ratio, Leverage_Ratio, ESG)
21. }Giả thích kĩ thuật
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1 | Kiểm tra nếu chưa tồn tại nyse_group2_data thì mới chạy
khối code bên dưới. |
| 2-3 | Tạo dữ liệu từ nyse_raw, loại bỏ cột thừa
(...1, date_SELL_fix) bằng
select(). |
| 4-9 | Đổi tên các cột cho dễ hiểu và thống nhất (ví dụ:
horizon (days) → Horizon_Days,
PE_ratio → PE, roa_ratio →
ROA, …). |
| 10 | Bắt đầu khối mutate() để tạo hoặc chuyển đổi biến. |
| 11-12 | Chuyển sector và investment sang dạng
factor. |
| 13-14 | Tạo biến thời gian: Buy_Year (năm mua) và
Buy_Quarter (quý mua). |
| 15-17 | Tính các biến mới: lợi nhuận thực (Real_Return),
log(P/E) có điều kiện, và tỷ lệ đòn bẩy (Leverage_Ratio)
tránh chia cho 0. |
| 19-20 | Chọn các cột chính để tạo bộ dữ liệu hoàn chỉnh
nyse_group2_data. |
Kiểm tra kích thước
[1] 405258 17
Nhận xét: Lệnh
print(dim(nyse_group2_data)) dùng để in ra kích thước của
bộ dữ liệu. Qua đó có thể thấy bộ dữ liệu gồm 405258 quan sát với 17
biến
Kiểm tra kiểu dữ liệu (str)
tibble [405,258 × 6] (S3: tbl_df/tbl/data.frame)
$ Real_Return: num [1:405258] -1.997 0.524 0.194 0.142 0.503 ...
$ Log_PE : num [1:405258] 2.53 2.43 2.36 2.41 2.24 ...
$ ROE : num [1:405258] 26.69 5.54 25.78 11.35 8.91 ...
$ ESG : num [1:405258] 12 26.3 19.8 12.9 27.9 17.6 31.6 24.8 26.3 27.9 ...
$ sector : Factor w/ 5 levels "AUTO","BANK",..: 4 2 2 4 2 3 5 2 2 2 ...
$ investment : Factor w/ 2 levels "BAD","GOOD": 1 2 1 1 2 2 2 2 1 2 ...
Nhận xét:
Code 1 -3 thể lấy dữ liệu nyse_group2_data, chọn
các biến quan trọng (Real_Return,
Log_PE, ROE, ESG,
sector, investment) bằng
select(), sau đó dùng str() để xem cấu
trúc chi tiết
Kết quả cho thấy các biến (Real_Return,
Log_PE, ROE, ESG) đều có kiểu
numeric, trong khi các biến phân loại (sector,
investment) đã được chuẩn hóa sang kiểu
factor.
Tóm tắt tổng quan
Real_Return Log_PE ROE ESG Leverage_Ratio
Min. :-2.61 Min. :1 Min. :-99.5 Min. :12.0 Min. : 2
1st Qu.:-1.69 1st Qu.:2 1st Qu.: 8.8 1st Qu.:16.3 1st Qu.: 11
Median : 0.14 Median :3 Median : 16.1 Median :25.1 Median : 16
Mean :-0.51 Mean :3 Mean : 15.6 Mean :22.6 Mean : 46
3rd Qu.: 0.35 3rd Qu.:3 3rd Qu.: 26.0 3rd Qu.:27.9 3rd Qu.: 27
Max. : 9.05 Max. :7 Max. : 57.2 Max. :31.6 Max. :2800
NA's :39751 NA's :9158
Nhận xét
Lệnh summary() áp dụng cho các cột được chọn
(Real_Return, Log_PE, ROE,
ESG, Leverage_Ratio) để tóm tắt thống kê mô
tả.
Kết quả cho thấy biến Real_Return dao động từ –2.61 đến 9.05, tức lợi suất thực tế vẫn tồn tại trường hợp lỗ. Biến Log_PE có giá trị nhỏ (0.1–0.7) và thiếu dữ liệu khá nhiều với 39.751 giá trị NA. Chỉ số ROE biến động rất lớn, từ –99.5 đến 57.2, điều này thể hiện sự khác biệt đáng kể về hiệu quả sinh lời giữa các doanh nghiệp.Điểm ESG nằm trong khoảng –12.0 đến 31.6, trung bình khoảng 22.6, cho thấy phần lớn doanh nghiệp đạt mức đánh giá trung bình đến khá. Cuối cùng, Leverage_Ratio trải rộng từ 0.2 đến 2800 và có 9.158 giá trị thiếu, cho thấy sự chênh lệch lớn về đòn bẩy tài chính. Ở đây không nhận xét về hình dạng phân phối vì chưa đảm bảo các biến tuân theo phân phối chuẩn.
Giá trị thiếu trong biến phái sinh
1. nyse_group2_data %>%
2. summarise_all(list(n_NA = ~sum(is.na(.)))) %>%
3. pivot_longer(cols = everything(), names_to = "Variable", values_to = "NA_Count") %>%
4. filter(NA_Count > 0) %>%
5. arrange(desc(NA_Count)) %>%
6. kable(caption = "Bảng 1.2.1: Số lượng NA trong các biến phái sinh")| Variable | NA_Count |
|---|---|
| Log_PE_n_NA | 39751 |
| Leverage_Ratio_n_NA | 9158 |
Giải thích kĩ thuật
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1 | Gọi dữ liệu nyse_group2_data. |
| 2 | Dùng summarise_all() để đếm số lượng giá trị
thiếu (NA) bằng sum(is.na(.)). |
| 3 | Dùng pivot_longer() để chuyển dữ liệu cột thành
hàng, tạo hai cột: Variable (tên biến) và
NA_Count (số lượng NA). |
| 4 | Lọc ra chỉ các biến có giá trị NA
(NA_Count > 0). |
| 5 | Sắp xếp giảm dần theo số lượng NA để xem biến nào thiếu nhiều nhất. |
| 6 | Dùng kable() để hiện thị bảng. |
Nhận xét
Log_PE có số lượng NA rất lớn (39.751) điều này xuất phát từ các trường hợp tỷ số P/E không xác định hoặc không hợp lệ (PE \(\le\) 0)
Leverage_Ratio cũng có nhiều NA ( 9158 NA),do các trường hợp ROE \(\approx\) 0 hoặc PB \(\approx\) 0, hoặc mẫu số trong công thức đòn bẩy bằng 0.
1. nyse_group2_clean <- nyse_group2_data %>%
2. drop_na(Real_Return, Log_PE, Leverage_Ratio)
3. na_removed_count <- nrow(nyse_group2_data) - nrow(nyse_group2_clean)
4. na_removed_ratio <- (na_removed_count / nrow(nyse_group2_data)) * 100
5. cat("Số quan sát bị loại bỏ do NA trong biến tạo sinh:", na_removed_count, "\n")Số quan sát bị loại bỏ do NA trong biến tạo sinh: 48909
Tỷ lệ dữ liệu bị loại bỏ: 12.07%
1. # Kiểm tra lại kích thước bộ dữ liệu cuối cùng
2. cat("\nKích thước bộ dữ liệu đã làm sạch cuối cùng (nyse_group2_clean) sau khi loại bỏ NA:\n")
Kích thước bộ dữ liệu đã làm sạch cuối cùng (nyse_group2_clean) sau khi loại bỏ NA:
[1] 356349 17
Giải thích kĩ thuật
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 2 | Dùng drop_na() để loại bỏ các hàng có giá trị
thiếu (NA) ở ba biến: Real_Return,
Log_PE, Leverage_Ratio. |
| 3 | Tính số lượng quan sát bị loại bỏ bằng cách lấy chênh lệch số hàng trước và sau khi làm sạch. |
| 4 | Tính tỷ lệ phần trăm dữ liệu bị loại bỏ so với tổng số hàng ban đầu. |
Nhận xét: Sau khi loại bỏ các quan sát có giá trị NA
trong các biến Real_Return, Log_PE, và
Leverage_Ratio, 48909 quan sát đã bị loại,
tương đương với 12.07% tổng số dữ liệu. Bộ dữ liệu cuối
cùng, nyse_group2_clean, có
356349 quan sát.
Các giá trị ngoại lai (Outlier) có thể làm sai lệch nghiêm trọng các
thống kê mô tả và ảnh hưởng đến kết quả phân tích. Mục tiêu của phần này
là nhận diện và kiểm soát các giá trị cực đoan trong các biến định lượng
cốt lõi như Real_Return, PE (trước khi Log),
và ROE.
Sử dụng phương pháp Interquartile Range (IQR) để xác định Outlier (các giá trị nằm ngoài khoảng \([Q_1 - 1.5 \times IQR, Q_3 + 1.5 \times IQR]\)).
1. # Hàm tính số lượng outlier
2. get_outlier_count <- function(data, var_name) {
3. x <- data[[var_name]]
4. Q1 <- quantile(x, 0.25, na.rm = TRUE)
5. Q3 <- quantile(x, 0.75, na.rm = TRUE)
6. IQR_val <- Q3 - Q1
7. lower_bound <- Q1 - 1.5 * IQR_val
8. upper_bound <- Q3 + 1.5 * IQR_val
9. outliers <- sum(x < lower_bound | x > upper_bound, na.rm = TRUE)
10. return(outliers)
11. }
12. vars_to_check <- c("Real_Return", "PE", "ROE")
13. outlier_counts <- data.frame(
14. Variable = vars_to_check,
15. Outlier_Count = sapply(vars_to_check, function(v) get_outlier_count(nyse_raw, v)),
16. Total_Count = nrow(nyse_raw)
17. )
18. outlier_counts <- outlier_counts %>%
19. mutate(Outlier_Ratio = (Outlier_Count / Total_Count) * 100)
20. # Chuyển PE_ratio về nyse_group2_clean
21. outlier_counts_clean <- data.frame(
22. Variable = c("Real_Return", "ROE"),
23. Outlier_Count = sapply(c("Real_Return", "ROE"), function(v) get_outlier_count(nyse_group2_clean, v)),
24. Total_Count = nrow(nyse_group2_clean)
25. ) %>%
26. mutate(Outlier_Ratio = (Outlier_Count / Total_Count) * 100)
27. knitr::kable(outlier_counts_clean, caption = "Bảng 1.3.1: Định lượng Outlier trong dữ liệu đã làm sạch NA")| Variable | Outlier_Count | Total_Count | Outlier_Ratio | |
|---|---|---|---|---|
| Real_Return | Real_Return | 616 | 356349 | 0.173 |
| ROE | ROE | 7678 | 356349 | 2.155 |
Giải thích kĩ thuật
| Dòng code | Giải thích |
|---|---|
| 1-11 | Sử dụng hàm get_outlier_count()để tính số lượng giá trị
ngoại lai cho từng biến. Hàm lấy dữ liệu cột var_name, tính
Q1 và Q3, xác định IQR = Q3 -
Q1, rồi đặt ngưỡng dưới/trên lần lượt là
Q1 - 1.5*IQR và Q3 + 1.5*IQR. Đếm các giá trị
nằm ngoài bằng sum(). |
| 12-17 | Tạo vector vars_to_check gồm Real_Return,
PE, ROE). Sau đó dùng sapply() để
áp dụng hàm get_outlier_count() cho từng biến, tạo bảng
outlier_counts được tính trong nyse_raw. |
| 18-19 | Dùng mutate() để thêm biến mới
Outlier_Ratio, tính tỷ lệ % outlier =
(Outlier_Count / Total_Count) * 100. |
| 20-26 | Thực hiện lại bước tính outlier cho dữ liệu đã làm sạch NA
(nyse_group2_clean) cho hai biến
Real_Return và ROE, rồi thêm tỷ lệ outlier
(%). |
| 27 | Dùng knitr::kable() để hiển thị bảng kết
quả với tiêu đề “Bảng 1.3.1: Định lượng Outlier trong dữ liệu
đã làm sạch NA”. |
Nhận xét:
Real_Return: Mặc dù đã loại bỏ NA, biến
này vẫn có tỷ lệ ngoại lai cao là 0.17%. Điều này phản
ánh sự biến động cực đoan của lợi suất trong thị trường chứng khoán.
ROE: Biến này cũng có tỷ lệ ngoại lai
đáng kể là
rsprintf("%.2f", outlier_counts_clean$Outlier_Ratio[2])%,
có thể do các trường hợp sinh lời quá cao hoặc thua lỗ nghiêm trọng.
1. outlier_viz_data <- nyse_group2_clean %>%
2. select(Real_Return, ROE, Log_PE) %>%
3. pivot_longer(cols = everything(), names_to = "Variable", values_to = "Value")
4. ggplot(outlier_viz_data, aes(x = Variable, y = Value)) +
5. geom_boxplot(fill = "#1E90FF", color = "#1E90FF", alpha = 0.7, outlier.colour = "red", outlier.shape = 1) +
6. facet_wrap(~Variable, scales = "free_y") +
7. labs(
8. title = "Hình 1.3.1: Nhận diện Outlier trong các biến cốt lõi",
9. y = "Giá trị"
10. ) +
11. theme_minimal() +
12. theme(plot.title = element_text(face = "bold", size = 12), axis.title.x = element_blank())Nhận xét kĩ thuật
| Phần / Dòng code | Giải thích |
|---|---|
| Tiền xử lý (dòng 1–3) | chọn các biến Real_Return, ROE,
Log_PE từ nyse_group2_clean, sau đó dùng
pivot_longer() để chuyển đổi dữ liệu với hai cột
Variable (tên biến) và Value (giá trị). |
| Layer 1 (dòng 4) | Khởi tạo biểu đồ bằng ggplot(), ánh xạ
(mapping) trục hoành là Variable, trục tung là
Value |
| Layer 2 (dòng 5) | geom_boxplot() để vẽ biểu đồ hộp, hiển
thị outlier bằng chấm đỏ rỗng (outlier.shape = 1) và tô màu
xanh dương (#1E90FF). |
| Layer 3 (dòng 6) | facet_wrap(~Variable) để **tạo nhiều biểu đồ con hiển
thị mỗi ô riêng biệt, scales = "free_y" nhằm cho mỗi biểu
đồ có trục tung riêng |
| Layer 4 (dòng 7–9) | labs() để đặt tiêu đề và nhãn trục tung cho biểu
đồ. |
| Layer 5 (dòng 11–12) | theme_minimal(), chỉnh lại tiêu đề in đậm, cỡ chữ 12 và
ẩn nhãn trục hoành. |
Nhận xét
Biến Log_PE: Phần hộp (IQR) tập trung quanh giá trị 2–3, có một số lượng nhỏ outlier nằm phía trên hộp ( trên mức 6), cho thấy chỉ số P/E của một vài công ty cao bất thường so với phần lớn còn lại.
Biến Real_Return: Xuất hiện rất nhiều outlier ở phía trên ( khoảng từ 3 - 9), phản ánh nhiều công ty đạt mức lợi nhuận thực cao vượt trội, trong khi phần lớn dữ liệu tập trung quanh mức lợi nhuận gần 0.
Biến ROE: Có một vài outlier ở giá trị cao vượt ngưỡng 50–60 so với phần hộp tập trung trong khoảng 10–30, thể hiện một số công ty có khả năng sinh lời trên vốn chủ sở hữu vượt trội so với trung bình.
Có thể thấy giá trị outlier ở các biến Real_Return,
ROE, Log_PE có nhiều giá trị cực đoan, nên áp
dụng kỹ thuật Winsorizing ở ngưỡng 1% và 99% để giới hạn các giá trị bất
thường thay vì loại bỏ chúng.
1. winsorize <- function(x, lower = 0.01, upper = 0.99) {
2. quantiles <- quantile(x, c(lower, upper), na.rm = TRUE)
3. x[x < quantiles[1]] <- quantiles[1]
4. x[x > quantiles[2]] <- quantiles[2]
5. return(x)
6. }
7. nyse_final_data <- nyse_group2_clean %>%
8. mutate(
9. Real_Return_Winsorized = winsorize(Real_Return, 0.01, 0.99),
10. ROE_Winsorized = winsorize(ROE, 0.01, 0.99),
11. Log_PE_Winsorized = winsorize(Log_PE, 0.01, 0.99)
12. )
13. cat("Đã tạo bộ dữ liệu cuối cùng 'nyse_final_data' với các biến Winsorized.\n")Đã tạo bộ dữ liệu cuối cùng 'nyse_final_data' với các biến Winsorized.
Giải thích kĩ thuật
| Dòng code | Giải thích |
|---|---|
| 1-6 | Hàm winsorize() tính hai phân vị
(quantiles) ở mức 1% và 99%, rồi thay giá trị nhỏ hơn
phân vị 1% và lớn hơn phân vị 99% bằng chính hai ngưỡng đó. |
| 7 | Khởi tạo bộ dữ liệu mới nyse_final_data dựa trên
nyse_group2_clean sau thực hiện Winsorization. |
| 8–11 | Dùng mutate() để tạo ba biến mới:
Real_Return_Winsorized, ROE_Winsorized, và
Log_PE_Winsorized |
1. comparison_stats <- nyse_final_data %>%
2. summarise(
3. Mean_Return_Raw = mean(Real_Return, na.rm = TRUE),
4. Mean_Return_Win = mean(Real_Return_Winsorized, na.rm = TRUE),
5. SD_Return_Raw = sd(Real_Return, na.rm = TRUE),
6. SD_Return_Win = sd(Real_Return_Winsorized, na.rm = TRUE),
7. Skew_Return_Raw = moments::skewness(Real_Return, na.rm = TRUE),
8. Skew_Return_Win = moments::skewness(Real_Return_Winsorized, na.rm = TRUE),
9. Mean_ROE_Raw = mean(ROE, na.rm = TRUE),
10. Mean_ROE_Win = mean(ROE_Winsorized, na.rm = TRUE),
11. Skew_ROE_Raw = moments::skewness(ROE, na.rm = TRUE),
12. Skew_ROE_Win = moments::skewness(ROE_Winsorized, na.rm = TRUE)
13. ) %>%
14. tidyr::pivot_longer(cols = everything(), names_to = "Statistic", values_to = "Value") %>%
15. separate(Statistic, into = c("Statistic_Type", "Variable", "Adjustment"), sep = "_") %>%
16. mutate(Adjustment = replace_na(Adjustment, "Raw")) %>%
17. pivot_wider(names_from = Adjustment, values_from = Value)
18. knitr::kable(comparison_stats, caption = "Bảng 1.3.2: So sánh thống kê trước và sau Winsorizing")| Statistic_Type | Variable | Raw | Win |
|---|---|---|---|
| Mean | Return | -0.492 | -0.502 |
| SD | Return | 1.079 | 1.047 |
| Skew | Return | -0.048 | -0.327 |
| Mean | ROE | 19.773 | 19.772 |
| Skew | ROE | 0.774 | 0.763 |
Nhận xét kĩ thuật
| Dòng code | Giải thích |
|---|---|
| 1 | Lấy comparison_stats từ dữ liệu
nyse_final_data. |
| 2–12 | Tính các thống kê mô tả cho biến
Real_Return và ROE trước và sau Winsorizing,
gồm: giá trị trung bình (mean), độ lệch chuẩn
(sd), và độ lệch (skewness). |
| 14 | Dùng pivot_longer()để chyển dữ liệu và gom các chỉ số
thống kê vào hai cột: Statistic và Value. |
| 15 | Dùng separate() để tách tên cột trong
Statistic thành ba phần: (Statistic_Type),
(Variable), (Adjustment). |
| 16 | Hàm mutate thay các giá trị thiếu trong
Adjustment bằng “Raw” _ dữ liệu gốc |
| 17 | Dùng pivot_wider()để hiển thị song song giá trị “Raw”
và “Winsorized”. |
Nhận xét
Biến Return: Giá trị (Mean) thay đổi không đáng kể, Tuy nhiên, độ lệch chuẩn (SD) giảm nhẹ từ 1.079 xuống 1.047 nghĩa là mức độ phân tán dữ liệu giảm sau khi loại bỏ ảnh hưởng của các giá trị cực đoan. Hệ số (Skew) thay đổi từ -0.048 sang -0.327 cũng phản ánh rằng phân phối lợi suất trở nên cân đối hơn.
Biến ROE: Giá trị trung bình (Mean) chỉ thay đổi nhỏ(19.773 → 19.772), hệ số (Skew) giảm nhẹ từ 0.774 xuống 0.763, ít bị thay đổi.
1. viz_data_final <- nyse_final_data %>%
2. select(Real_Return, Real_Return_Winsorized) %>%
3. pivot_longer(cols = everything(), names_to = "Version", values_to = "Value") %>%
4. mutate(Version = factor(Version, levels = c("Real_Return", "Real_Return_Winsorized"),
5. labels = c("1. Ban đầu (Raw)", "2. Đã Winsorized (1%-99%)")))
6. ggplot(viz_data_final, aes(x = Version, y = Value, fill = Version)) +
7. geom_boxplot(outlier.shape = NA) +
8. scale_fill_manual(values = c("1. Ban đầu (Raw)" = "#FF7F50", "2. Đã Winsorized (1%-99%)" = "#1E90FF")) +
9. labs(
10. title = "Hình 1.3.2: Trực quan hóa lợi suất thực tế (Real_Return) trước và sau Winsorizing",
11. y = "Lợi suất thực tế",
12. fill = "Phiên bản dữ liệu"
13. ) +
14. theme_minimal() +
15. theme(plot.title = element_text(face = "bold", size = 12), axis.title.x = element_blank(), legend.position = "bottom")Giải thích kĩ thuật
| Phần / Dòng code | Giải thích |
|---|---|
| Layer 1 (dòng 6) | ggplot(), ánh xạ (mapping) trục hoành
là Version, trục tung là Value. |
| Layer 2 (dòng 7) | geom_boxplot() để vẽ biểu đồ hộp,
outlier.shape = NA ẩn các điểm outlier để đồ thị gọn
hơn. |
| Layer 3 (dòng 8) | scale_fill_manual() để quy định màu riêng cho từng
nhóm: cam(#FF7F50) cho dữ liệu gốc và xanh dương(#1E90FF) cho dữ liệu
Winsorized. |
| Layer 4 (dòng 9–12) | labs() gồm tiêu đề, tên trục tung và chú thích của biến
fill. |
| Layer 5 (dòng 14–15) | theme_minimal(), định dạng tiêu đề và đặt chú thích
(legend) ở phía dưới |
Nhận xét: Biểu đồ cho thấy lợi suất thực tế (Real_Return) trước và sau Winsorizing có hình dạng tương tự nhau. Giá trị trung vị của cả hai biểu đồ đều gần 0 nghĩa là xu hướng lợi suất không thay đổi. Tuy nhiên, pahmj vi phân tán ở phiên bản đã Winsorized (1%-99%) hẹp hơn phản ánh mức độ biến động giảm nhẹ sau khi điều chỉnh các giá trị cực đoan, điều này phù hợp với nhận định độ lệch chuẩn giảm từ 1.079 xuống 1.047, chứng tỏ dữ liệu ổn định hơn và ít bị ảnh hưởng bởi ngoại lai.
1. vars_desc_fixed <- c("Real_Return_Winsorized", "Log_PE_Winsorized", "ROE_Winsorized", "Leverage_Ratio", "ESG")
2. get_desc_stats <- function(df, vars) {
3. df_stats <- data.frame(Variable = vars)
4. for (var in vars) {
5. x <- df[[var]]
6. x <- x[!is.na(x)]
7. n_obs <- length(x)
8. stats_row <- data.frame(
9. Variable = var,
10. N = n_obs,
11. Mean = mean(x),
12. Median = median(x),
13. SD = sd(x),
14. SE = sd(x) / sqrt(n_obs),
15. Min = min(x),
16. Q1 = quantile(x, 0.25),
17. Q3 = quantile(x, 0.75),
18. Max = max(x)
19. )
20. if (var == vars[1]) {
21. result_df <- stats_row
22. } else {
23. result_df <- rbind(result_df, stats_row)
24. }
25. }
26. return(result_df)
27. }
28. desc_table_fixed <- get_desc_stats(nyse_final_data, vars_desc_fixed)
29. desc_table_fixed %>%
30. knitr::kable(caption = "Bảng 1.2.1: Thống kê mô tả các biến chính")| Variable | N | Mean | Median | SD | SE | Min | Q1 | Q3 | Max | |
|---|---|---|---|---|---|---|---|---|---|---|
| 25% | Real_Return_Winsorized | 356349 | -0.502 | 0.143 | 1.047 | 0.002 | -2.11 | -1.68 | 0.348 | 1.16 |
| 25%1 | Log_PE_Winsorized | 356349 | 2.896 | 2.717 | 0.833 | 0.001 | 1.47 | 2.40 | 3.224 | 6.40 |
| 25%2 | ROE_Winsorized | 356349 | 19.772 | 18.660 | 11.001 | 0.018 | 1.19 | 11.66 | 26.400 | 55.99 |
| 25%3 | Leverage_Ratio | 356349 | 38.284 | 14.887 | 155.899 | 0.261 | 2.83 | 10.79 | 24.864 | 2800.00 |
| 25%4 | ESG | 356349 | 21.815 | 22.800 | 6.349 | 0.011 | 12.00 | 14.80 | 27.300 | 31.60 |
Giải thích kĩ thuật
| Dòng code | Giải thích |
|---|---|
| 1 | Tạo vector vars_desc_fixed gồm các biến đã Winsorized
và Leverage_Ratio và ESG. |
| 3–6 | Tạo df_stats và xử lý bằng vòng lặp
forloại bỏ giá trị thiếu (NA). |
| 7–19 | Tính các thống kê cho từng biến bằng các chỉ tiêu thông thường: mean, medium,… |
| 20–24 | Ghép từng dòng thống kê vào bảng kết quả result_df
thông qua rbind(). |
| 28 | Gọi hàm get_desc_stats() trên dữ liệu
nyse_final_data để tạo bảng thống kê mô tả
desc_table_fixed. |
Nhận xét
1. Lợi suất Thực tế
(Real_Return_Winsorized): Lợi suất thực tế có
trung bình -0.502 và trung vị 0.143, nghĩa là phần lớn giao dịch có lợi
nhuận dương. Độ lệch chuẩn 1.047 cho thấy mức biến động
cao, phản ánh rủi ro lớn ngay cả sau khi đã Winsorizing dữ liệu.
2. Hiệu suất Vốn (ROE_Winsorized): ROE
có trung bình 19.77% và trung vị 18.66%, phản ánh phân phối lệch phải
nhẹ.Giá trị trung vị 18.7% cho thấy các doanh nghiệp
trong mẫu có khả năng sinh lời trên vốn mạnh
3. Định giá (Log_PE_Winsorized): Chỉ số
Log_PE có giá trị trung bình 2.896 (tương đương P/E ≈
18.1) và trung vị 2.717 (P/E ≈ 15.1), cho thấy các công
ty trong mẫu nhìn chung được định giá ở mức hợp lý đến hơi
cao. Điều này phản ánh sự tích cực của thị trường vào
hiệu quả hoạt động và tiềm năng tăng trưởng của phần
lớn doanh nghiệp.
4. Đòn bẩy (Leverage_Ratio): Đây là
biến có độ lệch nghiêm trọng nhất. Trung bình (Mean =
38.284) lớn hơn gấp 2.5 lần so với
trung vị (Median = 14.887), và độ lệch
chuẩn (SD = 155.899) là cực kỳ cao.Điều
này cho thấy một tỷ lệ rất nhỏ các công ty trong mẫu có mức đòn bẩy cực
kỳ lớn.
5. Yếu tố ESG (ESG): Trung bình
(Mean = \(21.815\)) thấp
hơn Trung vị (Median = \(22.800\)), cho thấy phân bố hơi lệch trái
âm. Điều này ngụ ý rằng đa số các giao dịch tập trung vào các công ty có
xếp hạng ESG tương đối cao. Phạm vi hẹp (Min=12.00, Max=31.60) và SD
thấp (\(6.349\)) cho thấy xếp hạng ESG
là một biến số ổn định và ít biến động hơn so với các chỉ số tài chính
khác.
1. vars_shape_fixed <- c("Real_Return_Winsorized", "Log_PE_Winsorized", "ROE_Winsorized", "Leverage_Ratio")
2. get_desc_stats_shape <- function(df, vars) {
3. # Khởi tạo data frame kết quả
4. result_df <- data.frame(Variable = vars)
5. for (var in vars) {
6. x <- df[[var]]
7. x <- x[!is.na(x)]
8. mean_val <- mean(x)
9. sd_val <- sd(x)
10. stats_row <- data.frame(
11. Variable = var,
12. CV = sd_val / mean_val, # Coefficient of Variation
13. Skewness = moments::skewness(x),
14. Kurtosis = moments::kurtosis(x)
15. )
16. if (var == vars[1]) {
17. result_df <- stats_row
18. } else {
19. result_df <- rbind(result_df, stats_row)
20. }
21. }
22. return(result_df)
23. }
24. shape_table_fixed <- get_desc_stats_shape(nyse_final_data, vars_shape_fixed)
25. shape_table_fixed %>%
26. knitr::kable(caption = "Bảng 1.2.2: Đặc trưng thống kê biến")| Variable | CV | Skewness | Kurtosis |
|---|---|---|---|
| Real_Return_Winsorized | -2.085 | -0.327 | 1.34 |
| Log_PE_Winsorized | 0.288 | 1.596 | 7.02 |
| ROE_Winsorized | 0.556 | 0.763 | 3.74 |
| Leverage_Ratio | 4.072 | 14.141 | 238.06 |
Giải thích kĩ thuật
| Dòng code | Giải thích |
|---|---|
| 1 | vector vars_shape_fixed tạo gồm
Real_Return_Winsorized, Log_PE_Winsorized,
ROE_Winsorized, Leverage_Ratio. |
| 4–7 | tạo bảng kết quả và loại bỏ (NA) và dùng vòng lặp
for để lần lượt tính CV, Skewness,
Kurtosis cho từng biến |
| 8–9 | Tính giá trị trung bình (mean) và độ lệch chuẩn (sd) của biến hiện tại. |
| 10–15 | Tính ba chỉ tiêu: CV (mức biến động), Skewness (độ lệch), Kurtosis (độ nhọn). |
| 16–20 | Lệnh ifđể kiểm tra nếu là biến đầu
tiên thì khởi tạo result_df, còn nếu không thì
ghép thêm dòng kết quả vào bảng bằng
rbind(). |
| 24 | get_desc_stats_shape() để tính toán cho toàn bộ các
biến trong nyse_final_data. |
Nhận xét về Độ Lệch, Độ Nhọn và Hệ số Biến thiên
Real_Return_Winsorized: Có hệ số biến thiên (CV = -2.085) và độ lệch (Skewness = -0.327) nhỏ, cho thấy lợi suất thực tế khá ổn định và phân bố gần đối xứng,tuy nhiên độ biến động lợi suất vẫn cao
Log_PE_Winsorized: Có CV = 0.288, độ lệch dương (Skewness = 1.596) và độ nhọn cao (Kurtosis = 7.02), phản ánh một số cổ phiếu vẫn được định giá cao vượt trội so với phần lớn còn lại.
ROE_Winsorized: Với CV = 0.556, Skewness = 0.763, phân phối hơi lệch phải, cho thấy một nhóm nhỏ có ROE vượt trội.
Leverage_Ratio: Biến động cực lớn (CV = 4.072) và (Skewness = 14.141, Kurtosis = 238.06), thể hiện sự chênh lệch đòn bẩy tài chính rất cao một số có mức nợ vượt trội bất thường.
1. sample_size <- 5000
2. set.seed(42)
3. sample_real_return <- nyse_final_data$Real_Return_Winsorized %>%
4. sample(size = sample_size, replace = FALSE)
5. current_scipen <- options(scipen = 0)
6. shapiro_test <- shapiro.test(sample_real_return)
7. test_output <- broom::tidy(shapiro_test) %>%
8. mutate(
9. statistic = format(statistic, digits = 3),
10. p.value = format(p.value, scientific = TRUE, digits = 3)
11. )
12. options(scipen = current_scipen$scipen)
13. print(test_output)# A tibble: 1 × 3
statistic p.value method
<chr> <chr> <chr>
1 0.816 4.95e-60 Shapiro-Wilk normality test
Giải thích kĩ thuật
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1–2 | Xác định kích thước mẫu (5000) và đặt seed = 42 |
| 3–4 | Lấy mẫu gồm 5000 giá trị từ biến Real_Return_Winsorized
trong nyse_final_data không lặp lại
(replace = FALSE). |
| 5 | Lưu hiển thị số học (scipen) sau khi kiểm định |
| 6 | Thực hiện kiểm định Shapiro–Wilk |
Nhận xét
| Statistic | p.value |
|---|---|
| W | \(\approx 0.816\) |
| p-value | \(\approx 4.95 \times 10^{-60}\) |
Giá trị thống kê W ≈ 0.816 cùng p-value ≈ 4.95 × 10⁻⁶⁰ (rất nhỏ, < 0.05) điều này có nghĩa là biến Real_Return_Winsorized không tuân theo phân phối chuẩn dù đã được Winsorizing.
1. nyse_final_data %>%
2. count(investment) %>%
3. mutate(
4. Percentage = (n / sum(n)) * 100
5. ) %>%
6. knitr::kable(
7. col.names = c("Kết quả Đầu tư", "Số lượng (Count)", "Tỷ lệ (%)"),
8. digits = c(0, 0, 2),
9. caption = "Bảng 1.2.3: Phân bố kết quả đầu tư (GOOD/BAD)"
10. )| Kết quả Đầu tư | Số lượng (Count) | Tỷ lệ (%) |
|---|---|---|
| BAD | 229328 | 64.3 |
| GOOD | 127021 | 35.6 |
Giải thích kĩ thuật
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1–2 | count(investment) để đếm số lượng quan
sát trong từng nhóm kết quả đầu tư (GOOD hoặc
BAD). |
| 3–5 | Thêm cột tỷ lệ phần trăm (%) |
Nhận xét: Kết quả cho thấy nhóm BAD (thua
lỗ/lợi suất thấp) chiếm đa số với 64.3% tổng
số quan sát, tương ứng 229,328 giao dịch.
Trong khi đó, nhóm GOOD (sinh lời/lợi suất cao) chỉ
chiếm 35.7% với 127,021 giao
dịch.
Điều này cho thấy phần lớn các khoản đầu tư trong mẫu có hiệu quả thấp,
phản ánh mức độ rủi ro và khả năng sinh lời chưa ổn định trên thị
trường.
1. vars_corr <- c("Real_Return_Winsorized", "Log_PE_Winsorized", "ROE_Winsorized", "Leverage_Ratio", "ESG")
2. corr_matrix <- nyse_final_data %>%
3. select(all_of(vars_corr)) %>%
4. cor(use = "pairwise.complete.obs")
5. corr_matrix %>%
6. knitr::kable(digits = 3, caption = "Bảng 1.2.4: Ma trận tương quan giữa các biến")| Real_Return_Winsorized | Log_PE_Winsorized | ROE_Winsorized | Leverage_Ratio | ESG | |
|---|---|---|---|---|---|
| Real_Return_Winsorized | 1.000 | -0.056 | -0.090 | -0.048 | -0.001 |
| Log_PE_Winsorized | -0.056 | 1.000 | -0.224 | 0.398 | 0.150 |
| ROE_Winsorized | -0.090 | -0.224 | 1.000 | -0.193 | -0.427 |
| Leverage_Ratio | -0.048 | 0.398 | -0.193 | 1.000 | 0.104 |
| ESG | -0.001 | 0.150 | -0.427 | 0.104 | 1.000 |
Giải thích kĩ thuật
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1 | tạo ma trận gồm các biến Real_Return_Winsorized,
Log_PE_Winsorized, ROE_Winsorized,
Leverage_Ratio, và ESG. |
| 2–4 | tính ma trận hệ số tương quan (correlation matrix) bằng hàm
cor(), với tùy chọn pairwise.complete.obs để
NA. |
Nhận xét
1. Mối quan hệ với Lợi suất Thực tế
(Real_Return_Winsorized): Lợi suất thực tế có mối
tương quan rất yếu và âm với các biến tài chính: ROE (r =
-0.090), Log_PE (r = -0.056) và
Leverage_Ratio (r ≈ -0.048). Điều này cho thấy các chỉ
tiêu hiệu quả và định giá chưa dự báo mạnh mẽ lợi suất , thậm chí các
công ty có ROE hoặc P/E cao lại có xu hướng đạt
lợi suất thấp hơn nhẹ. Ngoài ra, yếu tố ESG (r
≈ -0.001) gần như không ảnh hưởng đáng kể đến hiệu quả đầu
tư**.
2. Mối quan hệ giữa các chỉ số chất lượng/định giá/đòn bẩy):
ROE và ESG (r = -0.427): Hệ số tương quan âm trung bình-mạnh cho thấy công ty có ROE cao hơn (hiệu suất tài chính tốt) lại có xu hướng có xếp hạng ESG thấp hơn (ESG thấp).
Leverage và Log_PE (r = 0.398): Mối tương quan dương trung bình cho thấy các công ty sử dụng đòn bẩy cao hơn cũng có xu hướng được thị trường định giá cao hơn (Log_PE cao hơn). Nghĩa là đòn bẩy cao có thể được xem là các doanh nghiệp tăng trưởng, chấp nhận rủi ro cao để tối ưu hóa hiệu suất vốn.
ROE và Log_PE (r = -0.224): Mối tương quan âm yếu cho thấy các công ty được định giá cao hơn (Log_PE cao) lại có xu hướng có ROE thấp hơn.
Kiểm định giả thuyết \(H_0: \rho = 0\) cho các cặp tương quan quan trọng.
Tương quan giữa Real_Return và ROE
1. current_scipen <- options(scipen = 0)
2. test_corr_return_roe <- cor.test(nyse_final_data$Real_Return_Winsorized, nyse_final_data$ROE_Winsorized)
3. broom::tidy(test_corr_return_roe) %>%
4. mutate(
5. p.value = format(p.value, scientific = TRUE, digits = 3),
6. statistic = round(statistic, 2),
7. estimate = round(estimate, 4)
8. ) %>%
9. print()# A tibble: 1 × 8
estimate statistic p.value parameter conf.low conf.high method alternative
<dbl> <dbl> <chr> <int> <dbl> <dbl> <chr> <chr>
1 -0.0904 -54.2 0e+00 356347 -0.0936 -0.0871 Pearson's… two.sided
Nhận xét
| estimate (\(\rho\)) | statistic (\(t\)) | p.value | conf.low | conf.high |
|---|---|---|---|---|
| -0.0904 | -54.2 | \(\approx 0\) | -0.0936 | -0.0871 |
Giá trị p - value rất nhỏ nên ~ 0, Khoảng tin cậy 95% (-0.0936 đến -0.0871) nên cặp biến có ý nghĩa thống kê mạnh mẽ. Hệ số tương quan giữa ROE và lợi suất thực tế là -0.0904, cho thấy mối quan hệ âm rất yếu nên ROE rất có khả năng giải thích được biến động lợi suất.
Tương quan giữa Real_Return và Log_PE
1. test_corr_return_logpe <- cor.test(nyse_final_data$Real_Return_Winsorized, nyse_final_data$Log_PE_Winsorized)
2. broom::tidy(test_corr_return_logpe) %>%
3. mutate(
4. p.value = format(p.value, scientific = TRUE, digits = 3),
5. statistic = round(statistic, 2),
6. estimate = round(estimate, 4)
7. ) %>%
8. print()# A tibble: 1 × 8
estimate statistic p.value parameter conf.low conf.high method alternative
<dbl> <dbl> <chr> <int> <dbl> <dbl> <chr> <chr>
1 -0.056 -33.5 2.34e-245 356347 -0.0593 -0.0527 Pearson… two.sided
Nhận xét
| estimate (\(\rho\)) | statistic (\(t\)) | p.value | conf.low | conf.high |
|---|---|---|---|---|
| -0.0560 | -33.5 | \(\approx 0\) | -0.0593 | -0.0527 |
Giá trị \(p\)-value cực kỳ nhỏ (cũng \(\approx 0\)), nên mối tương quan này cũng có ý nghĩa thống kê. Tuy nhiên hệ số tương quan ước tính là \(-0.0560\), là một mối tương quan âm và cực kỳ yếu. Mức độ giải thích của biến định giá Log_PE đối với lợi suất thực tế thậm chí còn thấp hơn cả ROE.
Giải thích kĩ thuật (tương tự ở hai cặp)
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1 | Lưu thiết lập hiển thị số (scipen) dạng khoa học |
| 2 | Thực hiện kiểm định tương quan Pearson giữa các cặp
cor.test() |
| 3–8 | Dùng broom::tidy() chuyển kết quả kiểm định thành dạng
bảng |
1. nyse_final_data %>%
2. group_by(sector) %>%
3. summarise(
4. N = n(),
5. Mean_Return = mean(Real_Return_Winsorized, na.rm = TRUE),
6. SD_Return = sd(Real_Return_Winsorized, na.rm = TRUE),
7. Median_Return = median(Real_Return_Winsorized, na.rm = TRUE)
8. ) %>%
9. arrange(desc(Mean_Return)) %>%
10. knitr::kable(caption = "Bảng 1.2.5: Thống kê lợi suất thực tế theo ngành nghề")| sector | N | Mean_Return | SD_Return | Median_Return |
|---|---|---|---|---|
| TECH | 89107 | -0.441 | 1.09 | 0.169 |
| AUTO | 53098 | -0.473 | 1.02 | 0.137 |
| RETAIL | 92346 | -0.510 | 1.01 | 0.135 |
| FMCG | 49273 | -0.546 | 1.04 | 0.156 |
| BANK | 72525 | -0.559 | 1.05 | 0.103 |
Nhận xét
Ngành TECH (0.169) và FMCG (0.156) có lợi suất trung vị cao nhất, cho thấy phần lớn giao dịch trong hai ngành này mang lại hiệu quả đầu tư tốt hơn so với các ngành khác. Ngược lại, BANK (0.103) có lợi suất trung vị thấp nhất, thể hiện mức sinh lời thấp nhưng rủi ro cũng thấp hơn, phản ánh đặc trưng ổn định của nhóm ngành tài chính – ngân hàng.
Ngành TECH có lợi suất trung vị cao nhưng độ biến
động lớn (SD = 1.09), phản ánh rõ nguyên lý
đánh đổi giữa rủi ro và lợi nhuận.
Ngược lại, ngành BANK cho thấy Mean âm
(-0.559) trong khi Median dương (0.103), chứng
tỏ chịu ảnh hưởng mạnh từ một số giao dịch thua lỗ cực đoan
1. nyse_final_data %>%
2. group_by(investment) %>%
3. summarise(
4. N = n(),
5. Median_LogPE = median(Log_PE_Winsorized, na.rm = TRUE),
6. Median_ROE = median(ROE_Winsorized, na.rm = TRUE),
7. Mean_Leverage = mean(Leverage_Ratio, na.rm = TRUE)
8. ) %>%
9. knitr::kable(caption = "Bảng 1.2.6: Thống kê chỉ số định giá/hiệu suất theo kết quả đầu tư")| investment | N | Median_LogPE | Median_ROE | Mean_Leverage |
|---|---|---|---|---|
| BAD | 229328 | 2.69 | 19.4 | 41.5 |
| GOOD | 127021 | 2.74 | 17.4 | 32.5 |
Nhận xét
Định giá (Median_LogPE): Nhóm GOOD có định giá trung vị cao hơn một chút (2.74 so 2.69), cho thấy cổ phiếu được thị trường định giá cao hơn thường mang lại kết quả đầu tư tốt hơn.
Hiệu suất (Median_ROE): Nhóm BAD lại có ROE trung vị cao hơn (19.4% so với 17.4%), tạo nên nghịch lý “các công ty có hiệu suất tài chính tốt hơn chưa chắc mang lại lợi suất thực tế cao hơn”, có thể được giải thích bằng giả thuyết thị trường hiệu quả.
Đòn bẩy (Mean_Leverage): Nhóm BAD có đòn bẩy trung bình cao hơn (41.5 so với 32.5), cho thấy rủi ro tài chính lớn hơn thường đi kèm với kết quả đầu tư kém hơn.
1. nyse_final_data %>%
2. group_by(sector) %>%
3. summarise(
4. N = n(),
5. Mean_ESG = mean(ESG, na.rm = TRUE),
6. Median_ESG = median(ESG, na.rm = TRUE),
7. SD_ESG = sd(ESG, na.rm = TRUE)
8. ) %>%
9. arrange(desc(Mean_ESG)) %>%
10. knitr::kable(caption = "Bảng 1.2.7: Thống kê xếp hạng ESG theo ngành nghề")| sector | N | Mean_ESG | Median_ESG | SD_ESG |
|---|---|---|---|---|
| AUTO | 53098 | 25.7 | 29.7 | 6.20 |
| BANK | 72525 | 25.4 | 26.3 | 3.19 |
| FMCG | 49273 | 22.6 | 25.1 | 3.50 |
| TECH | 89107 | 20.7 | 16.5 | 7.00 |
| RETAIL | 92346 | 17.4 | 14.5 | 5.65 |
Nhận xét
Ngành AUTO và BANK có điểm ESG cao cụ thể AUTO
(Mean: \(25.7\), Median: \(29.7\)) và BANK (Mean:
\(25.4\), Median: \(26.3\)) điều này phản ánh mức tuân thủ tốt
các quy định về môi trường và quản trị. Ngược lại ngành
RETAIL (Mean: \(17.4\),
Median: \(14.5\)) và
TECH (Mean: \(20.7\),
Median: \(16.5\)) có điểm ESG trung
bình thấp nhất. Tuy nhiên đáng chú ngành TECH có độ
biến động ESG (SD_ESG = \(7.00\)) cao nhất, thể hiện sự chênh lệch
lớn giữa các doanh nghiệp trong ngành trong khi ngành
BANK có độ biến động thấp nhất (SD_ESG =
\(3.19\)).
Giải thích kĩ thuật ba thống kê
| Dòng code | Giải thích ngắn gọn |
|---|---|
| 1–2 | Nhóm dữ liệu nyse_final_data theo chỉ tiêu cần bằng
group_by(). |
| 3–7 | Tính các thống kê mô tả: số lượng quan sát, trung bình, độ lệch chuẩn .. |
| 9 | Sắp xếp kết quả theo lợi suất trung bình giảm dầnở mục 1.2.5.1. và 1.2.5.3 |
1. viz_data_density <- nyse_final_data %>%
2. select(Real_Return_Winsorized, Log_PE_Winsorized, ROE_Winsorized, Leverage_Ratio) %>%
3. pivot_longer(cols = everything(), names_to = "Variable", values_to = "Value") %>%
4. mutate(Variable = factor(Variable, levels = c("Real_Return_Winsorized", "Log_PE_Winsorized", "ROE_Winsorized", "Leverage_Ratio"),
5. labels = c("Lợi suất Thực tế (Winsorized)", "Log(PE) (Winsorized)", "ROE (Winsorized)", "Tỷ lệ Đòn bẩy")))
6. ggplot(viz_data_density, aes(x = Value, fill = Variable)) +
7. geom_density(alpha = 0.6) +
8. facet_wrap(~Variable, scales = "free", ncol = 2) +
9. labs(
10. title = "Hình 1.3.1: Phân bố mật độ của các chỉ số định lượng chính",
11. x = "Giá trị",
12. y = "Mật độ"
13. ) +
14. theme_minimal() +
15. theme(legend.position = "none", plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật:
| Phần / Dòng code | Giải thích |
|---|---|
| Tiền xử lý (dòng 1–5) | chọn dữ liệu, chuyển theo kiểu pivot_longer() và gán
nhãn bằng mutate(). |
| Layer 1 (dòng 6) | ggplot(), ánh xạ (mapping) trục hoành
là Value và màu tô (fill) theo
Variable (tên biến) |
| Layer 2 (dòng 7) | geom_density() để vẽ đường mật độ,
alpha = 0.6 làm màu trong suốt giúp dễ so sánh |
| Layer 3 (dòng 8) | facet_wrap(~Variable) để chia biểu đồ thành các
ô nhỏ và so sánh độc lập bằng
(scales = "free"). |
| Layer 4 (dòng 9–13) | labs(), gồm tiêu đề biểu đồ, tên trục X (“Giá trị”) và
trục Y (“Mật độ”). |
| Layer 5 (dòng 14–15) | theme_minimal() tạo giao diện |
Nhận xét
Lợi suất Thực tế: Phân bố lưỡng cực rõ rệt với
hai đỉnh — một ở vùng thua lỗ (~-2.0) và một ở vùng sinh lời nhẹ
(~0.1–0.3), phản ánh sự phân hóa mạnh giữa các khoản đầu tư tốt và
xấu.
Định giá (Log(PE)): Phân bố lệch phải, tập trung quanh khoảng 2.5–2.8 với đuôi dài sang phải, cho thấy có một số cổ phiếu được định giá rất cao.
Hiệu suất Vốn (ROE): Có dạng đa đỉnh, nổi bật ở khoảng 10–20% và 25–35%, phản ánh sự tồn tại của hai nhóm hiệu suât là ổn định và tăng trưởng.
Tỷ lệ Đòn bẩy: Phân bố rất lệch phải và nhọn, tập trung gần 0, với vài giá trị cực lớn (>1000), cho thấy đa số doanh nghiệp có đòn bẩy thấp nhưng một số ít có rủi ro tài chính rất cao.
1. nyse_final_data %>%
2. ggplot(aes(x = investment, fill = investment)) +
3. geom_bar() +
4. geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5) +
5. labs(
6. title = "Hình 1.3.2: Phân bố kết quả Đầu tư (GOOD/BAD)",
7. x = "Kết quả đầu tư",
8. y = "Số lượng giao dịch"
9. ) +
10. scale_fill_manual(values = c("GOOD" = "#28a745", "BAD" = "#dc3545")) +
11. theme_minimal() +
12. theme(legend.position = "none", plot.title = element_text(face = "bold", size = 10))Giải thích kĩ thuật
| Phần/ Dòng code | Giải thích |
|---|---|
| Layer 1 (dòng 2) | ggplot(), ánh xạ (mapping) trục hoành
là investment (GOOD/BAD) và màu tô (fill) theo
cùng biến này. |
| Layer 2 (dòng 3) | geom_bar() để vẽ biểu đồ cột |
| Layer 3 (dòng 4) | Thêm nhãn số liệu trên cột bằng
geom_text(stat = "count") và căn chỉnh nhãn
(vjust = -0.5). |
| Layer 4 (dòng 5–8) | labs(): tiêu đề, tên trục X và trục Y |
| Layer 5 (dòng 10) | chỉnh màu scale_fill_manual(): xanh lá
(#28a745) cho GOOD và đỏ (#dc3545) cho
BAD. |
| Layer 6 (dòng 11–12) | Áp dụng (theme_minimal)** ẩn chú thích
(legend.position = "none") |
Nhận xét: Số lượng giao dịch BAD là \(229,328\) (Tỷ lệ \(64.3\%\)) Trong khi đó lượng giao dịch GOOD là \(127,021\) (Tỷ lệ \(35.7\%\)). Vậy có thể nói để một khoản đầu tư ngẫu nhiên vào NYSE rơi vào nhóm hiệu suất thấp (BAD) là \(1.8\) lần cao hơn so với rơi vào nhóm hiệu suất cao (GOOD).
1. # Heatmap của Ma trận Tương quan
2. corr_long <- reshape2::melt(corr_matrix)
3. ggplot(corr_long, aes(x = Var1, y = Var2, fill = value)) +
4. geom_tile(color = "white") +
5. scale_fill_gradient2(low = "blue", high = "red", mid = "white", midpoint = 0, limit = c(-1, 1), space = "Lab", name = "Hệ số tương quan") +
6. geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
7. labs(
8. title = "Hình 1.3.3: Ma trận tương quan giữa các chỉ số chính",
9. x = "Biến",
10. y = "Biến"
11. ) +
12. theme_minimal() +
13. theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1), plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật
| Phần / Dòng code | Giải thích |
|---|---|
| Tiền xử lý (dòng 2) | Sử dụng reshape2::melt() để chuyển ma trận tương quan
corr_matrix sang dạng dài (long format) |
| Layer 1 (dòng 3) | ggplot() và ánh xạ (mapping) trục X, Y
là các biến (Var1, Var2) |
| Layer 2 (dòng 4) | Thêm ô màu (heatmap) bằng geom_tile(),
mỗi ô biểu diễn cặp tương quan giữa hai biến;
color = "white" tạo đường viền phân cách rõ ràng. |
| Layer 3 (dòng 5) | Áp dụng thang màu hai chiều với
scale_fill_gradient2(): màu xanh (tương quan âm), trắng
(0), đỏ (tương quan dương). Giới hạn trong khoảng (-1, 1). |
| Layer 4 (dòng 6) | Thêm giá trị số lên ô bằng
geom_text(), làm tròn số |
| Layer 5 (dòng 7–10) | Dùng labs() để đặt tiêu đề biểu đồ và nhãn trục
X/Y**. |
| Layer 6 (dòng 12–13) | (theme_minimal), xoay nhãn trục X 45° để dễ đọc và in
đậm tiêu đề (plot.title). |
Nhận xét
Lưu ý Cường độ tương quan được thể hiện bằng độ đậm của màu: Đỏ (Dương) và Xanh Tím (Âm). Giá trị gần 0 (tương quan yếu) được thể hiện bằng màu trắng hoặc màu nhạt.
Với Lợi suất Thực tế
(Real_Return_Winsorized): tương quan yếu
gần bằng 0 với các biến khác (dao động từ -0.09 đến
-0.001). Điều này nghĩa là hiệu suất đầu tư không bị ảnh hưởng
đáng kể bởi các chỉ số tài chính.
Quan hệ giữa các chỉ số độc lập:
ROE – ESG: Mối tương quan âm mạnh nhất (r = -0.43, màu xanh đậm), phản ánh rằng doanh nghiệp ROE cao thường có điểm ESG thấp.
Leverage – Log(PE): Mối tương quan dương trung bình (r = 0.40, màu đỏ nhạt), gợi ý doanh nghiệp dùng đòn bẩy cao thường được định giá cao hơn.
Các cặp khác như ROE – Log(PE) hay ROE – Leverage có tương quan yếu, hơn yếu hơn so với cặp ROE-ESG (r ≈ -0.2), chỉ thể hiện xu hướng nhẹ chứ không rõ rệt
1. ggplot(nyse_final_data, aes(x = sector, y = Real_Return_Winsorized, fill = sector)) +
2. geom_violin(alpha = 0.7) +
3. geom_boxplot(width = 0.1, color = "black", alpha = 0.8, outlier.shape = NA) +
4. labs(
5. title = "Hình 1.3.5: Phân bố lợi suất thực tế giữa các ngành",
6. x = "Ngành nghề",
7. y = "Lợi suất thực tế (Winsorized)"
8. ) +
9. theme_minimal() +
10. theme(legend.position = "none", plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Vẽ biểu đồ ggplot | Dữ liệu được lấy từ nyse_final_data, ánh xạ biến
sector vào trục X và Real_Return_Winsorized
vào trục Y |
| Layer 1 (dòng 2) | Dùng geom_violin(alpha = 0.7)để vẽ hình dạng phân bố
lợi suất cho từng ngành |
| Layer 2 (dòng 3) | Chồng thêm geom_boxplot() để thể hiện trung vị,
tứ phân vị và khoảng dữ liệu; ẩn outlier
(outlier.shape = NA) |
| Layer 3 (dòng 4–7) | labs() để thêm tiêu đề và nhãn trụccho biểu đồ. |
| Layer 4 (dòng 9–10) | lớp giao diện (theme_minimal)** |
Nhận xét
Lưu ý Chiều rộng của “cây vĩ cầm” biểu thị mật độ quan sát tại giá trị lợi suất đó. Đường kẻ ngang bên trong (từ Box Plot) biểu thị Trung vị (Median).
Ngành TECH và AUTO có phần thân “cây vĩ cầm” phía trên (lợi suất dương) rộng nhất, ngụ ý có một lượng lớn giao dịch đạt được lợi nhuận dương trong phạm vi trung bình.Ngược lại ngành BANK có phần đuôi kéo dài về lợi suất âm dài và mỏng nhất (tương đối), cho thấy mật độ ở các khoản lỗ lớn thấp hơn các ngành khác
Sự khác biệt rõ ràng về vị trí của trung vị và hình dạng mật độ giữa các ngành (đặc biệt là TECH vs BANK) cho thấy lợi suất thực tế bị ảnh hưởng bởi ngành nghề. Sự khác biệt này sẽ được kiểm định chính thức bằng Kiểm định ANOVA/Kruskal-Wallis ở Chương 4 để xác định liệu chúng có ý nghĩa thống kê hay không.
1. sector_indicators_mean <- nyse_final_data %>%
2. group_by(sector) %>%
3. summarise(
4. Mean_ROE = mean(ROE_Winsorized, na.rm = TRUE),
5. Mean_LogPE = mean(Log_PE_Winsorized, na.rm = TRUE)
6. ) %>%
7. pivot_longer(cols = starts_with("Mean"), names_to = "Indicator", values_to = "Mean_Value")
8. ggplot(sector_indicators_mean, aes(x = sector, y = Mean_Value, fill = Indicator)) +
9. geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.7) +
10. labs(
11. title = "Hình 1.3.6: Trung bình ROE và Log(PE) giữa các ngành nghề",
12. x = "Ngành nghề",
13. y = "Giá trị trung bình (Winsorized)",
14. fill = "Chỉ số"
15. ) +
16. scale_fill_manual(values = c("Mean_ROE" = "#007bff", "Mean_LogPE" = "#ffc107")) +
17. theme_minimal() +
18. theme(plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| 1–7 | Tính giá trị trung bình ROE và Log(PE)** cho từng ngành bằng
group_by() và summarise(), và chuyển đổi về
pivot_longer() |
| Layer 1 (dòng 8) | Khởi tạo ggplot() với trục X = sector,
trục Y = Mean_Value, và màu tô (fill) theo
Indicator. |
| Layer 2 (dòng 9) | geom_bar(stat = "identity") để vẽ biểu đồ cột nhóm song
song |
| Layer 3 (dòng 10–14) | labs()thêm tiêu đề |
| Layer 4 (dòng 16–18) | chỉnh màu sắc (ROE: xanh, LogPE: vàng)
bằng scale_fill_manual(), áp dụng `theme_minimal() |
Nhận xét
1. Hiệu suất Vốn ROE:
Ngành FMCG có ROE trung bình cao nhất
(~28%), cho thấy khả năng sinh lời trên vốn chủ sở hữu vượt
trội.
Theo sau là TECH và AUTO (khoảng
22%), trong khi BANK có ROE thấp nhất
(~12%), phản ánh hiệu quả sử dụng vốn yếu hơn do đặc
thù ngành tài chính.
2. Định giá Log(PE):
Ngành TECH và FMCG có Log(PE)
cao nhất (~3.5), nghĩa là được thị trường định giá cao hơn (P/E
cao), thể hiện kỳ vọng tăng trưởng lớn. Ngược lại,
AUTO và BANK có Log(PE) thấp
hơn (~2.5), tương ứng với nhóm cổ phiếu giá trị, ít được định
giá cao.
Tóm lại
Hai ngành FMCG và TECH vừa có ROE cao, vừa được định giá cao (Log(PE) lớn) → nhóm tăng trưởng mạnh.
Ngành BANK có ROE thấp và Log(PE thấp, thuộc nhóm giá trị ổn định.
Kết quả cho thấy thị trường có xu hướng trả giá cao cho các doanh nghiệp có hiệu quả vốn cao và tiềm năng tăng trưởng tốt.
1. ggplot(nyse_final_data, aes(x = investment, y = Log_PE_Winsorized, fill = investment)) +
2. geom_boxplot(notch = TRUE) +
3. labs(
4. title = "Hình 1.3.7: Sự khác biệt của Log(PE) giữa nhóm đầu tư GOOD và BAD",
5. x = "Kết quả đầu tư",
6. y = "Log(PE) (Winsorized)"
7. ) +
8. scale_fill_manual(values = c("GOOD" = "#28a745", "BAD" = "#dc3545")) +
9. theme_minimal() +
10. theme(legend.position = "none", plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Layer 1 (dòng 1) | Khởi tạo ggplot(), ánh xạ trục X = nhóm đầu
tư và trục Y = Log(PE) (đã Winsorized), tô màu
theo investment |
| Layer 2 (dòng 2) | geom_boxplot(notch = TRUE)vẽ biểu đồ hộp |
| Layer 3 (dòng 3–6) | labs() thêm tiêu đề |
| Layer 4 (dòng 8) | scale_fill_manual() để gán màu phân
biệt: nhóm GOOD màu xanh lá #28a745, nhóm BAD màu
đỏ #dc3545. |
| Layer 5 (dòng 9–10) | áp dụng theme (theme_minimal) |
Nhận xét
Lưu ý Đường kẻ dày trong hộp là Trung vị (Median); Rìa trên và dưới của hộp là Q3 và Q1 (phạm vi 50% dữ liệu).
Trung vị: Nhóm GOOD có trung vị Log(PE) cao hơn nhẹ so với nhóm BAD (GOOD ≈ 2.74, BAD ≈ 2.69), tuy nhiên có thể nói các giao dịch sinh lời thường tập trung ở cổ phiếu có định giá cao hơn
Độ phân tán (IQR): Hộp của nhóm
GOOD rộng hơn, phản ánh mức định giá đa dạng
hơn – gồm cả cổ phiếu giá trị thấp và cổ phiếu tăng trưởng
cao.
Đuôi và giá trị ngoại lai: Cả hai nhóm đều có nhiều điểm ngoại lai ở vùng Log(PE) rất cao (≈ 5–6.5).
1. mosaicplot(sector ~ investment, data = nyse_final_data,
2. main = "Hình 1.3.8: Phân bố tỷ lệ kết quả đầu tư theo ngành nghề",
3. xlab = "Ngành nghề (Sector)",
4. ylab = "Kết quả đầu tư (Investment)",
5. color = c("#dc3545", "#28a745"),
6. las = 2)Giải thích kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Dòng 1 | Sử dụng mosaicplot() để vẽ biểu đồ khối mối quan hệ
giữa (ngành nghề) và (kết quả đầu tư GOOD/BAD). |
| Dòng 2–4 | Thêm tiêu đề (main) và nhãn
trục X, Y |
| Dòng 5 | Gán màu sắc cho hai nhóm: BAD (đỏ #dc3545)
và GOOD (xanh lá #28a745) |
| Dòng 6 | las = 2 xoay nhãn trục X theo chiều dọc để tránh chồng
chữ |
Nhận xét
Lưu ý: chiều rộng của mỗi cột (Ngành nghề) tỷ lệ với tổng số lượng giao dịch của ngành đó trong toàn bộ mẫu, chiều cao của mỗi màu biểu thị kết quả(GOOD/BAD).
Các ngành RETAIL, TECH và BANK có quy mô giao dịch lớn hơn so với các ngành khác. Ngược lại, BANK và AUTO có phần màu đỏ (BAD) lớn, cho thấy tỷ lệ giao dịch thua lỗ cao hơn.
Nhóm TECH và FMCG có phần màu xanh (GOOD) chiếm ưu thế hơn, thể hiện khả năng sinh lời cao hơn trung bình.
Nhìn chung, phần lớn các ngành đều có tỷ trọng giao dịch không đồng đều giữa GOOD và BAD.
Phát hiện Chính: Mosaic Plot chứng minh có sự
phụ thuộc giữa biến sector và biến
investment. Phát hiện này cung cấp cơ sở vững chắc để thực
hiện Kiểm định ANOVA, nhằm xác định liệu sự khác biệt
về Lợi suất Trung bình giữa các ngành có thực sự có ý nghĩa thống kê hay
không.
1. ggplot(nyse_final_data, aes(x = sector, y = ESG, fill = sector)) +
2. geom_boxplot(notch = TRUE) +
3. labs(
4. title = "Hình 1.3.9: Mức độ bền vững ESG giữa các ngành nghề",
5. x = "Ngành nghề",
6. y = "Xếp hạng ESG"
7. ) +
8. theme_minimal() +
9. theme(legend.position = "none", plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật: kĩ thuật của biểu đồ này tương tự với các kĩ thuật vẽ biểu đồ hộp bên trên.
Nhận xét
1. nyse_final_data %>%
2. group_by(Buy_Year) %>%
3. summarise(Mean_Return = mean(Real_Return_Winsorized, na.rm = TRUE)) %>%
4. ggplot(aes(x = Buy_Year, y = Mean_Return, group = 1)) +
5. geom_line(color = "blue", linewidth = 1) +
6. geom_point(color = "red", size = 2) +
7. geom_hline(yintercept = 0, linetype = "dashed", color = "grey50") +
8. labs(
9. title = "Hình 1.3.10: Xu hướng lợi suất thực tế trung bình qua các năm",
10. x = "Năm mua",
11. y = "Lợi suất thực tế trung bình (Winsorized)"
12. ) +
13. theme_minimal() +
14. theme(plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| dòng 1–3 | Nhóm dữ liệu theo Buy_Year, tính lợi suất trung bình
bằng summarise(Mean_Return = mean(...)) |
| Layer 1 (dòng 4) | Khởi tạo ggplot() với trục X =
Buy_Year và trục Y = Mean_Return |
| Layer 2 (dòng 5–7) | vẽ biểu đồ đường geom_line() vẽ đường xu hướng (màu
xanh), geom_point() đánh dấu điểm dữ liệu (màu đỏ), và
geom_hline() thêm đường chuẩn ở mức 0 để phân biệt
lời/lỗ. |
| Layer 3 (dòng 8–11) | labs() thêm tiêu đề và nhãn |
| Layer 4 (dòng 13–14) | áp dụng theme theme_minimal() và tiêu đề in đậm
(plot.title). |
Nhận xét
Biểu đồ này thể hiện xu hướng lợi suất thực tế trung bình (đã Winsorized) theo năm giao dịch mua, trong giai đoạn 2013-2018.
1. Pha Tăng trưởng (2013 - 2015): Lợi suất bắt đầu ở mức âm sâu vào năm 2013 (ước tính \(\approx -1.4\)).Sau đó phục hồi vượt mức \(0\) vào năm 2014 (ước tính \(\approx 0.2\)).Đạt đỉnh cao nhất vào năm 2015 (ước tính \(\approx 0.5\)). Điều này phù hợp với giai đoạn phục hồi mạnh mẽ của thị trường chứng khoán Mỹ sau cuộc khủng hoảng tài chính toàn cầu.
2. Pha Suy giảm (2016 - 2017): Lợi suất giảm đáng kể vào năm 2016 (ước tính \(\approx 0.3\)).Đạt đáy của toàn bộ giai đoạn vào năm 2017 (ước tính \(\approx -1.8\)). Mức lợi suất âm sâu này vượt xa cả năm 2013. Có thể các khoản đầu tư ở năm này phải đối diện tiêu cực.
3. Pha Hồi phục Nhẹ (2018):Lợi suất có sự hồi phục nhẹ vào năm 2018 (ước tính \(\approx -1.6\)), nhưng vẫn duy trì ở mức âm sâu.
Tóm lại Biểu đồ chứng minh rằng yếu tố thời gian (năm mua) có ảnh hưởng lớn và mang tính chu kỳ đến lợi suất. Lợi suất trung bình không phải là một đường thẳng mà tuân theo một mô hình lên xuống rõ rệt.
1. nyse_final_data %>%
2. group_by(Buy_Year) %>%
3. summarise(
4. Mean_ROE = mean(ROE_Winsorized, na.rm = TRUE),
5. Mean_ROA = mean(ROA, na.rm = TRUE)
6. ) %>%
7. pivot_longer(cols = starts_with("Mean"), names_to = "Indicator", values_to = "Mean_Value") %>%
8. ggplot(aes(x = Buy_Year, y = Mean_Value, fill = Indicator)) +
9. geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.7) +
10. labs(
11. title = "Hình 1.3.11: Trung bình ROE và ROA theo năm giao dịch",
12. x = "Năm mua",
13. y = "Giá trị trung bình",
14. fill = "Chỉ số"
15. ) +
16. scale_fill_manual(values = c("Mean_ROA" = "#6c757d", "Mean_ROE" = "#20c997")) +
17. theme_minimal() +
18. theme(plot.title = element_text(face = "bold", size = 12))Giải thích kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Tiền xử lý (dòng 2–7) | Nhóm dữ liệu theo Buy_Year, tính trung bình của
ROE_Winsorized và ROA |
| Layer 1 (dòng 8) | Khởi tạo ggplot() với trục X =
Buy_Year, Y = Mean_Value |
| Layer 2 (dòng 9) | geom_bar(stat = "identity") để vẽ biểu đồ cột, với
position_dodge() giúp đặt hai cột cạnh nhau để dễ so
sánh. |
| Layer 3 (dòng 10–14) | labs() để thêm tiêu đề, nhãn vã chú thích |
| Layer 4 (dòng 16) | scale_fill_manual() gán màu riêng cho từng chỉ
số (ROA: xám, ROE: xanh ngọc) |
| Layer 5 (dòng 17–18) | áp dụng theme_minimal() và định dạng tiêu đề in đậm
(plot.title). |
Nhận xét
1. Mối quan hệ Nội tại giữa ROE và ROA: Trong tất cả
các năm từ 2013 đến 2018, cột Mean_ROE (Màu xanh, ước tính
từ \(17.5\) đến \(21\)) luôn cao hơn đáng kể so với cột
Mean_ROA (Màu xám, ước tính từ \(6\) đến \(7.5\)).Khoảng cách lớn giữa ROE và ROA
chứng minh rằng trong bộ dữ liệu này Đòn bẩy Tài chính
để khuếch đại lợi nhuận trên vốn chủ sở hữu (\(\text{ROE} = \text{ROA} \times
\text{Leverage}\)).
2. Phân tích Xu hướng Hiệu suất Qua các Năm: Giá trị ROAtăng trưởng chậm nhưng ổn định, từ mức thấp nhất năm 2013 (ước tính \(\approx 6.5\)) lên mức cao nhất vào năm 2018 (ước tính \(\approx 7.5\)). Tương tự ROE tăng trưởng từ mức thấp nhất năm 2013 (ước tính \(\approx 17.5\)) lên mức cao nhất năm 2018 (ước tính \(\approx 21.5\)).
Phát hiện chính: Mâu thuẫn với lợi suất (Hình 1.3.10). Cụ thể năm 2015 có ROE/ROA chỉ ở mức trung bình nhưng lại đạt đỉnh lợi suất thực tế trung bình, trong khi 2017 có ROE/ROA cao gần đỉnh thì lại rơi vào đáy lợi suất. Điều này gợi ý rằng hiệu suất tài chính không tỷ lệ thuận với lợi suất, có thể lợi suất bị chi phối bởi các yếu tố bên ngoài khác.
1. ggplot(nyse_final_data, aes(x = Log_PE_Winsorized, fill = investment)) +
2. geom_density(alpha = 0.6) +
3. labs(
4. title = "Hình 1.3.12: Phân bố Log(PE) theo Kết quả đầu tư (GOOD/BAD)",
5. x = "Log(PE) (Winsorized)",
6. y = "Mật độ",
7. fill = "Kết quả"
8. ) +
9. scale_fill_manual(values = c("GOOD" = "#28a745", "BAD" = "#dc3545")) +
10. theme_minimal() +
11. theme(plot.title = element_text(face = "bold", size = 12))Nhận xét: Biểu đồ cho thấy hai phân bố (Đỏ - BAD, Xanh lá - GOOD) chồng lấn lên nhau rất nhiều, mật độ phân bố của nhóm GOOD (Xanh lá) lại tập trung và cao hơn ở vùng Log(PE) cao (khoảng từ \(2.8\) đến \(3.5\) và đuôi phải sau \(4.0\)). Ngược lại, mật độ nhóm BAD (Đỏ) lại chiếm ưu thế ở vùng Log(PE) thấp hơn (khoảng \(2.5\) đến \(2.8\)).Điều này trực quan hóa kết luận từ Bảng 1.2.6: Các giao dịch thành công (GOOD) có xu hướng được thực hiện ở mức định giá (P/E) cao hơn một chút.
1. ggplot(nyse_final_data, aes(x = ROE_Winsorized, fill = investment)) +
2. geom_density(alpha = 0.6) +
3. labs(
4. title = "Hình 1.3.13: Phân bố ROE theo kết quả đầu tư (GOOD/BAD)",
5. x = "ROE (Winsorized)",
6. y = "Mật độ",
7. fill = "Kết quả"
8. ) +
9. scale_fill_manual(values = c("GOOD" = "#28a745", "BAD" = "#dc3545")) +
10. theme_minimal() +
11. theme(plot.title = element_text(face = "bold", size = 12))Nhận xét: Nhóm GOOD (Xanh lá) có mật độ cao nhất tập trung ở vùng ROE thấp (khoảng \(10\%\) đến \(18\%\)). Nhóm BAD (Đỏ) lại chiếm ưu thế và có mật độ cao hơn ở vùng ROE cao (khoảng \(25\%\) đến \(35\%\)). Biểu đồ này là sự trực quan hóa mạnh mẽ nhất cho Nghịch lý ROE đã thấy ở Bảng 1.2.3. Mức ROE cao (hiệu suất hiện tại tốt) lại không dẫn đến lợi suất cao. Điều này củng cố luận điểm rằng các công ty có ROE cao đã bị định giá quá cao tại thời điểm giao dịch, khiến lợi suất thực tế của nhà đầu tư bị giảm xuống (rơi vào nhóm BAD).
Nhận xét kĩ thuật hai mục 1.3.5.1 và 1.3.5.2
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Layer 1 (dòng 1) | Khởi tạo ggplot() với dữ liệu
nyse_final_data, ánh xạ theo từng cặp biến |
| Layer 2 (dòng 2) | geom_density(alpha = 0.6) vẽ biểu đồ mật độ phân bố với
mức trong suốt 0.6 để thấy rõ phần chồng lấn giữa hai phân bố |
| Layer 3 (dòng 3–7) | labs() thêm tiêu đề và nhãn |
| Layer 4 (dòng 9) | scale_fill_manual() găns màu ở những nhóm biến riêng
biệt |
| Layer 5 (dòng 10–11) | Áp dụng **theme_minimal() |
1. yearly_investment_ratio <- nyse_final_data %>%
2. group_by(Buy_Year) %>%
3. count(investment) %>%
4. mutate(Proportion = n / sum(n))
5. ggplot(yearly_investment_ratio, aes(x = Buy_Year, y = Proportion, fill = investment)) +
6. geom_bar(stat = "identity", position = "stack") +
7. labs(
8. title = "Hình 1.3.14: Kết quả đầu tư (GOOD/BAD) theo năm",
9. x = "Năm mua",
10. y = "Tỷ lệ phần trăm",
11. fill = "Kết quả"
12. ) +
13. scale_fill_manual(values = c("GOOD" = "#28a745", "BAD" = "#dc3545")) +
14. scale_y_continuous(labels = scales::percent) +
15. theme_minimal() +
16. theme(plot.title = element_text(face = "bold", size = 12))Nhận xét kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Tiền xử lý (dòng 1–4) | Sử dụng các hàm group_by() và count() để
nhóm dữ liệu theo Buy_Year và investment, sau
đó tính tỷ lệ phần trăm (Proportion = n / sum(n)) trong
từng năm bằng mutate(). |
| Layer 1 (dòng 5) | ggplot() và gắn giá trị các trục |
| Layer 2 (dòng 6) | Dùng geom_bar(stat = "identity", position = "stack")để
**vẽ biểu đồ cột chồng |
| Layer 3 (dòng 7–11) | Hàm labs() thêm tiêu đề, nhãn trục và chú thích
(legend) |
| Layer 4 (dòng 13) | Hàm scale_fill_manual()** gán màu cho hai nhóm:
GOOD = xanh lá (#28a745), BAD = đỏ
(#dc3545) |
| Layer 5 (dòng 14) | scale_y_continuous(labels = scales::percent) để hiển
thị trục Y dưới dạng phần trăm (%) |
| Layer 6 (dòng 15–16) | Áp dụng (theme_minimal()) |
Nhận xét: Năm 2016 có tỷ lệ GOOD cao nhất (ước tính \(\approx 70\%\)). Đây là năm có lợi suất trung bình dương cao. Năm 2017 và 2018 có tỷ lệ BAD cao nhất (ước tính \(\approx 95\%\)). Điều này đồng bộ với hình 1.3.10, từ đó có thể thấy tính thời vụ (năm mua) là một yếu tố rủi ro hệ thống cực kỳ mạnh mẽ.
1. ggplot(nyse_final_data, aes(x = Log_PE_Winsorized, y = ROE_Winsorized)) +
2. geom_point(alpha = 0.05, color = "#007bff") +
3. geom_smooth(method = "lm", color = "red", se = FALSE) + # Dùng lm vì cor là tuyến tính
4. labs(
5. title = "Hình 1.3.15: Mối quan hệ giữa định giá (Log(PE)) và hiệu suất (ROE)",
6. x = "Log(PE) (Winsorized)",
7. y = "ROE (Winsorized)"
8. ) +
9. theme_minimal() +
10. theme(plot.title = element_text(face = "bold", size = 12))Nhận xét kĩ thuật
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Layer 1 (dòng 1) | Khởi tạo ggplot() với dữ liệu
nyse_final_data, ánh xạ trục X =
Log_PE_Winsorized và trục Y =
ROE_Winsorized |
| Layer 2 (dòng 2) | geom_point(alpha = 0.05, color = "#007bff") để vẽ biểu
đồ tán xạ, alpha = 0.05 giúp giảm độ đậm màu khi dữ liệu
dày, gắn quan sát là xanh xanh #007bff |
| Layer 3 (dòng 3) | geom_smooth(method = "lm", color = "red", se = FALSE)
để vẽ đường hồi quy tuyến tính (màu đỏ),se = FALSE tắt hiển
thị dải tin cậy. |
| Layer 4 (dòng 4–7) | labs()thêm tiêu đề và nhãn |
| Layer 5 (dòng 9–10) | Áp dụng theme_minimal() như các biểu đồ trên |
Nhận xét: Sự phân tán rộng của các điểm (Dữ liệu không tập trung gần đường hồi quy) khẳng định mối quan hệ tuyến tính này là yếu. Điều này cho thấy rằng mối quan hệ nghịch nhẹ giữa Log(PE) và ROE — các công ty có ROE cao thường có Log(PE) thấp hơn, trong khi những công ty có Log(PE) cao (được kỳ vọng tăng trưởng mạnh) lại có ROE thấp hơn.
Mục tiêu là kiểm định sự khác biệt về Lợi suất thực tế Trung bình
(Real_Return_Winsorized) giữa hai nhóm
investment (GOOD/BAD).
Cần kiểm tra Giả định Phương sai Đồng nhất
(Levene's Test) trước khi thực hiện \(t\)-test.
Kiểm định phương sai lợi suất bằng bartlett
1. levene_test_result <- stats::bartlett.test(Real_Return_Winsorized ~ investment, data = nyse_final_data)
2. print(broom::tidy(levene_test_result))# A tibble: 1 × 4
statistic p.value parameter method
<dbl> <dbl> <dbl> <chr>
1 199571. 0 1 Bartlett test of homogeneity of variances
Nhận xét:
| statistic | p.value |
|---|---|
| \(\approx 199,571\) | \(\approx 0\) |
Giá trị p - value = 0 < 0.05 nên giả thuyết \(H_0\) (Phương sai đồng nhất) bị bác bỏ. Điều này cho thấy phương sai lợi suất thực tế giữa nhóm GOOD và BAD là **không đồng nhất
Kiểm định T- test cho lợi suất
1. t_test_result <- t.test(Real_Return_Winsorized ~ investment, data = nyse_final_data, var.equal = FALSE)
2. print(broom::tidy(t_test_result))# A tibble: 1 × 10
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 -1.44 -1.02 0.426 -678. 0 280623. -1.45 -1.44
# ℹ 2 more variables: method <chr>, alternative <chr>
Nhận xét:
| estimate (Difference) | estimate1 (\(\mu_{\text{BAD}}\)) | estimate2 (\(\mu_{\text{GOOD}}\)) | statistic (\(t\)) | p.value | conf.low | conf.high |
|---|---|---|---|---|---|---|
| -1.44 | -1.02 | 0.426 | -678 | \(\approx 0\) | -1.45 | -1.44 |
Lợi suất trung bình của nhóm \(\text{BAD}\) (\(\mu_{\text{BAD}}\)) là \(-1.02\). Lợi suất trung bình của nhóm \(\text{GOOD}\) (\(\mu_{\text{GOOD}}\)) là \(0.426\). Cùng với đó là ự khác biệt (\(\mu_{\text{BAD}} - \mu_{\text{GOOD}}\)) là \(-1.44\), giá trị p - value ~ 0 nên kết luận rằng có sự khác biệt giữa lợi suất thực tế trung bình của nhóm đầu tư GOOD và BAD.
Mục tiêu là kiểm định sự khác biệt về Lợi suất thực tế Trung bình
giữa các nhóm ngành (sector).
Kiểm định phương sai lợi suất giữa các ngành
1. current_scipen <- options(scipen = 0)
2. levene_test_sector <- stats::bartlett.test(Real_Return_Winsorized ~ sector, data = nyse_final_data)
3. broom::tidy(levene_test_sector) %>%
4. mutate(
5. statistic = round(statistic, 0),
6. p.value = format(p.value, scientific = TRUE, digits = 3)
7. ) %>%
8. print()# A tibble: 1 × 4
statistic p.value parameter method
<dbl> <chr> <dbl> <chr>
1 576 2.61e-123 4 Bartlett test of homogeneity of variances
*Nhận xét kĩ thuật**
| Phần / Dòng code | Giải thích ngắn gọn |
|---|---|
| Dòng 1 | options(scipen = 0)thiết lạp số chế dộ khoa học |
| Dòng 2 | Thực hiện kiểm định Bartlett (bartlett.test()) |
| Dòng 3 | Dùng broom::tidy() để chuyển kết quả kiểm định sang
dạng bảng dữ liệu |
| Dòng 4–6 | Sử dụng mutate() để làm tròn (statistic)**
và định dạng giá trị p-value theo dạng khoa học với
format(..., scientific = TRUE)) |
Nhận xét
| statistic | p.value |
|---|---|
| \(576\) | \(\approx 0\) |
Với \(p\)-value xấp xỉ \(0\), giả thuyết \(H_0\) (Phương sai lợi suất đồng nhất giữa các ngành) bị bác bỏ mạnh mẽ.
Kiểm định ANOVA
1. anova_result <- aov(Real_Return_Winsorized ~ sector, data = nyse_final_data)
2. broom::tidy(anova_result) %>%
3. mutate(
4. sumsq = round(sumsq, 0),
5. meansq = round(meansq, 2),
6. statistic = round(statistic, 0),
7. p.value = format(p.value, scientific = TRUE, digits = 3)
8. ) %>%
9. knitr::kable(caption = "Kết quả kiểm định ANOVA (Lợi suất ~ sector)")| term | df | sumsq | meansq | statistic | p.value |
|---|---|---|---|---|---|
| sector | 4 | 710 | 177.43 | 162 | 6.29e-139 |
| Residuals | 356344 | 389936 | 1.09 | NA | NA |
Nhận xét: Giá trị \(F\) quan sát được là \(\approx 162\). Giá trị \(p\)-value (\(\approx 0\) thấp hơn ngưỡng anphal nên có thể kết luận rằng có tồn tại sự khác biệt lợi suất thực tế trung bình giữa ít nhất một cặp ngành nghề. Điều này chứng minh rằng ngành nghề (sector) là một yếu tố quyết định có tính hệ thống đối với hiệu suất đầu tư, xác nhận những quan sát đã thấy ở Hình 3.3.1 và Bảng 2.3.1 (ví dụ: TECH vs BANK).
Phân tích Post-hoc Tukey’s HSD được thực hiện sau khi kiểm định ANOVA cho kết quả có ý nghĩa thống kê (p < 0.05). Mục tiêu của bước này là xác định cụ thể cặp nhóm (ngành) nào khác biệt đáng kể về giá trị trung bình của lợi suất thực tế.
Kết quả của Tukey’s HSD cho biết:
Phân tích này giúp làm rõ kết quả của ANOVA, chỉ ra nhóm ngành nào có hiệu suất đầu tư cao hơn hoặc thấp hơn so với các nhóm còn lại, đồng thời đảm bảo độ tin cậy bằng cách kiểm soát sai số thống kê khi so sánh nhiều cặp giá trị.
1. if (exists("anova_result")) {
2. tukey_hsd_result <- TukeyHSD(anova_result)
3. print(broom::tidy(tukey_hsd_result))
4. }# A tibble: 10 × 7
term contrast null.value estimate conf.low conf.high adj.p.value
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 sector BANK-AUTO 0 -0.0859 -0.102 -0.0696 0
2 sector FMCG-AUTO 0 -0.0732 -0.0910 -0.0553 1.33e-14
3 sector RETAIL-AUTO 0 -0.0377 -0.0532 -0.0221 3.81e-10
4 sector TECH-AUTO 0 0.0316 0.0160 0.0473 3.51e- 7
5 sector FMCG-BANK 0 0.0127 -0.00392 0.0294 2.26e- 1
6 sector RETAIL-BANK 0 0.0482 0.0341 0.0624 5.24e-14
7 sector TECH-BANK 0 0.118 0.103 0.132 0
8 sector RETAIL-FMCG 0 0.0355 0.0196 0.0514 1.19e- 8
9 sector TECH-FMCG 0 0.105 0.0888 0.121 0
10 sector TECH-RETAIL 0 0.0693 0.0559 0.0827 0
Giải thích kĩ thuật
| Phần / Dòng code | Giải thích chi tiết |
|---|---|
| Dòng 1 | Kiểm tra anova_result có tồn tại chưa . Nếu có, code
bên trong khối if sẽ được thực thi |
| Dòng 2 | Thực hiện kiểm định hậu định Tukey HSD trên kết quả ANOVA để |
| Dòng 3 | Dùng broom::tidy()để chuyển kết quả (data frame), |
| Dòng 4 | In bảng kết |
Nhận xét
| Contrast | estimate (Difference) | adj.p.value | Ý nghĩa (Difference) |
|---|---|---|---|
| TECH - BANK | \(0.118\) | \(\approx 0\) | TECH > BANK (Sự khác biệt lớn nhất) |
| TECH - FMCG | \(0.1048\) | \(\approx 0\) | TECH > FMCG |
| TECH - RETAIL | \(0.0693\) | \(\approx 0\) | TECH > RETAIL |
| BANK - AUTO | \(-0.0859\) | \(\approx 0\) | BANK < AUTO |
| FMCG - AUTO | \(-0.0732\) | \(\approx 0\) | FMCG < AUTO |
| RETAIL - BANK | \(0.0482\) | \(\approx 0\) | RETAIL > BANK |
Kết luận: Ngoại trừ cặp FMCG - BANK
(adj.p.value \(\approx
0.226\)), tất cả 9/10 cặp ngành đều cho thấy sự khác biệt
có ý nghĩa thống kê về Lợi suất Trung bình (\(p < 0.001\)). Điều này xác nhận lại sự
khác biệt đã thấy trong Violin Plot (Hình 3.3.1). Đồng thời qua hệ số
ước ượng cũng có thể thấy ngành TECH có hiệu suất sinh lời cao nhất, còn
BANK là ngành yếu nhất về lợi suất đầu tư.
Thứ hạng Lợi suất Trung bình (Dựa trên Tukey’s HSD):
\[\text{BANK} \approx \text{FMCG} < \text{RETAIL} \approx \text{AUTO} < \text{TECH}\]
Luận điểm I: Sự Ngắt Kết Nối Giữa Hiệu suất Cơ bản và Lợi suất Thực tế
Bằng chứng Định lượng (mục 1.2, 1.4) cho thấy các chỉ số tài chính
như ROE, Log_PE, Leverage, và
ESG hầu như không có tương quan với lợi
suất thực tế (|ρ| < 0.1).
⇒ Điều này ủng hộ Giả thuyết Thị trường Hiệu quả (EMH - Weak Form): lợi suất không thể dự đoán dựa trên thông tin công khai, mà chủ yếu chịu tác động từ rủi ro hệ thống và biến động thị trường.
Luận điểm II: Nghịch lý ROE - Bằng chứng về Định giá Quá Cao
Bằng chứng Định lượng (1.2, 1.3) cho thấy các cổ phiếu có ROE cao lại cho lợi suất đầu tư thấp hơn, vì đã bị định giá quá cao tại thời điểm mua.
⇒ Hiệu suất hoạt động tốt không đồng nghĩa với lợi nhuận cao nếu giá cổ phiếu đã phản ánh toàn bộ kỳ vọng thị trường.
Luận điểm III: Sức mạnh Tuyệt đối của Yếu tố Hệ thống (Ngành và Thời gian)
Kết quả ANOVA khẳng định yếu tố
ngành có ảnh hưởng đáng kể đến lợi suất
(p ≈ 0).Ngành TECH vượt trội nhất, trong
khi BANK có lợi suất thấp nhất (Bằng chứng Định lượng
(1.3, 1.4): *)
Yếu tố thời gian cũng quan trọng: năm 2017 ghi nhận tỷ lệ giao dịch thua lỗ (BAD) gần 95%, dù ROE/ROA tăng ( Hình 1.3.14 là bằng chứng định lượng)
⇒ Điều này cho thấy yếu tố ngành và chu kỳ thị trường có sức ảnh hưởng lớn hơn nhiều so với các chỉ số tài chính nội tại.
Chất lượng Dữ liệu: Bộ dữ liệu NYSE có chất lượng cao (Không NA, không trùng lặp), nhưng các biến lợi suất và đòn bẩy cực kỳ lệch (Skewness \(> 14\) cho Đòn bẩy), buộc phải sử dụng Winsorizing và diễn giải bằng Trung vị.
Mối quan hệ: Các chỉ số tài chính/ESG có mối tương quan yếu không đáng kể (\(|\rho| \le 0.09\)) với lợi suất thực tế. ROE và ESG có mối tương quan âm trung bình (\(\rho = -0.427\)), cho thấy sự đánh đổi giữa hiệu suất vốn và tuân thủ ESG.
Phân Cực: Lợi suất được phân cực thành hai nhóm: \(\text{BAD}\) (Trung bình \(\approx -1.02\)) và \(\text{GOOD}\) (Trung bình \(\approx 0.426\)), khác biệt nhau có ý nghĩa thống kê (\(p \approx 0\)).
Tác động của Nhóm:
Ngành nghề: Có sự khác biệt có ý nghĩa thống kê về Lợi suất Trung bình giữa các ngành (ANOVA \(p \approx 0\)). TECH là ngành vượt trội, BANK là ngành có lợi suất thấp nhất.
Nghịch lý Hiệu suất: Các khoản đầu tư thất bại (\(\text{BAD}\)) có xu hướng được thực hiện vào các công ty có ROE cao hơn và Đòn bẩy cao hơn, chứng minh rằng các cổ phiếu hiệu suất cao có thể đã bị định giá quá cao, biến rủi ro thành thua lỗ.
Hạn chế Dữ liệu:
Bộ dữ liệu được sử dụng trong nghiên cứu là giả lập ngẫu nhiên (random investments), nên có thể chưa phản ánh hoàn toàn hành vi và chiến lược đầu tư thực tế của các nhà đầu tư chuyên nghiệp.
Ngoài ra, dữ liệu chỉ kéo dài đến năm 2018, nên chưa bao gồm các biến động thị trường lớn trong giai đoạn sau (như khủng hoảng COVID-19 hoặc xu hướng ESG tăng mạnh sau 2020).
Điều này có thể ảnh hưởng đến khả năng khái quát hóa kết quả cho bối cảnh thị trường hiện tại.
Hạn chế Phương pháp:
Phân tích chỉ dừng ở thống kê mô tả, tương quan và kiểm định
so sánh nhóm (ANOVA, Tukey HSD), nên mới dừng ở mức
phát hiện sự khác biệt chứ chưa đi sâu vào đo
lường mức độ ảnh hưởng định lượng của từng biến tài chính (ví
dụ: thông qua mô hình hồi quy).
Do đó, nghiên cứu chưa xác định được mối quan hệ nhân –
quả giữa các chỉ số tài chính (như ROE, Log_PE, Leverage_Ratio,
ESG) và lợi suất đầu tư thực tế.
Hạn chế về Phạm vi và Tổng quát hóa:
Mẫu nghiên cứu chỉ bao gồm một số nhóm ngành tiêu biểu (AUTO, BANK, FMCG, RETAIL, TECH) niêm yết trên thị trường NYSE, nên không đại diện cho toàn bộ ngành nghề hoặc các thị trường khác.
Kết quả vì thế mang tính tham khảo và cần được kiểm chứng thêm bằng các nghiên cứu mở rộng quy mô dữ liệu và thời gian, hoặc so sánh giữa các sàn khác nhau (NASDAQ, LSE, v.v.) để tăng tính khái quát.
Từ kết quả hiện có, có thể rút ra một số hướng đề xuất sau:
Mở rộng mô hình nghiên cứu:
Ứng dụng cho quản trị doanh nghiệp:
Hàm ý cho nhà đầu tư:
Tóm lại, bộ dữ liệu này là nền tảng tốt để phát triển các mô hình định lượng, giúp đánh giá hiệu quả tài chính và chiến lược đầu tư trong ngành năng lượng.
Mục tiêu chính của toàn bộ Phân tích Dữ liệu Tài chính và Thị trường của mã chứng khoán GAS là cung cấp một cái nhìn toàn diện và định lượng về Sức khỏe tài chính, Hiệu suất hoạt động và Phản ứng của thị trường đối với Tổng Công ty Khí Việt Nam (GAS).
Cụ thể, đối với Nhóm biến Hiệu suất & Tăng trưởng (Nhóm 1), mục tiêu tập trung vào:
Đánh giá năng lực sinh lời: Phân tích nguồn gốc của khả năng sinh lời (ROE, ROA), xác định vai trò của Biên lợi nhuận, Vòng quay tài sản và Đòn bẩy tài chính thông qua mô hình Du Pont.
Đo lường tính chu kỳ và bền vững: Phân tích tốc độ tăng trưởng và sự biến động (YoY, Rolling Correlation) của Doanh thu, Lợi nhuận và EPS để đánh giá mức độ ổn định của hiệu suất hoạt động qua các chu kỳ kinh tế và giá dầu/khí.
Xác định mối liên hệ cơ bản: Kiểm định mối quan hệ giữa các chỉ số hiệu suất nội tại (như EPS) và Giá trị thị trường (Giá cổ phiếu) để hiểu rõ cơ sở định giá của nhà đầu tư.
Bộ dữ liệu được xây dựng từ các nguồn thông tin công khai và chính thức của Tổng Công ty Khí Việt Nam (GAS).
Dữ liệu tài chính: Được trích xuất từ các Báo cáo tài chính hợp nhất đã được kiểm toán hàng năm của GAS, bao gồm Bảng Cân đối Kế toán, Bảng Kết quả hoạt động kinh doanh và Bảng Lưu chuyển tiền tệ, tại ngày chốt sổ 31/12 hàng năm.
Dữ liệu thị trường: Thu thập từ các nguồn dữ liệu thị trường uy tín (ví dụ: Sở Giao dịch Chứng khoán, Bloomberg) về giá đóng cửa và số lượng cổ phiếu lưu hành tại ngày 31/12 hàng năm.
Đơn vị quan sát: Dữ liệu được tổng hợp theo năm.
Phạm vi thời gian: Giai đoạn 11 năm, từ 2014 đến 2024.
Bộ dữ liệu tổng thể (GAS_data_final) bao gồm 19 biến,
được phân loại thành 3 nhóm chức năng chính như sau.
(A). Biến Định danh
| Tên Biến | Mô tả | Loại dữ liệu |
|---|---|---|
| Nam | Năm quan sát (2014-2024) | Numeric |
(B). Biến Tài chính cơ bản và Thị trường
| Tên Biến | Mô tả | Nguồn gốc |
|---|---|---|
| DoanhThu | Doanh thu thuần hàng năm | Bảng KQKD |
| LoiNhuanSauThue | Lợi nhuận sau thuế của cổ đông công ty mẹ | Bảng KQKD |
| TongTaiSan | Tổng cộng tài sản cuối kỳ | Bảng CĐKT |
| VonChuSoHuu | Tổng vốn chủ sở hữu cuối kỳ | Bảng CĐKT |
| NoPhaiTra | Tổng nợ phải trả cuối kỳ | Bảng CĐKT |
| CFO | Dòng tiền thuần từ hoạt động kinh doanh | Bảng LCTT |
| EPS | Lợi nhuận trên mỗi cổ phiếu | Bảng KQKD |
| Gia_DongCua_CuoiNam | Giá đóng cửa cổ phiếu GAS tại 31/12 | Dữ liệu thị trường |
| SL_CoPhieu_LuuHanh | Số lượng cổ phiếu đang lưu hành | Dữ liệu thị trường |
(C). Biến Phái sinh
Các biến này được tính toán để phục vụ trực tiếp cho việc đánh giá hiệu suất, cấu trúc vốn và định giá.
| Tên Biến | Công thức Tính toán | Mục đích Phân tích |
|---|---|---|
| ROE_Nam | \(\text{LNST} / \text{VCSH}\) | Tỷ suất sinh lời cho cổ đông |
| ROA_Nam | \(\text{LNST} / \text{Tổng Tài sản}\) | Tỷ suất sinh lời từ tài sản |
| BienLoiNhuanRong_Nam | \(\text{LNST} / \text{DoanhThu}\) | Hiệu quả kiểm soát chi phí |
| TySoNo_Tren_VCSH | \(\text{Nợ Phải Trả} / \text{VCSH}\) | Thước đo đòn bẩy tài chính |
| DoanhThu_TangTruong_YoY | \(\%\Delta \text{Doanh Thu}\) | Tốc độ tăng trưởng quy mô |
| LoiNhuan_TangTruong_YoY | \(\%\Delta \text{LNST}\) | Tốc độ tăng trưởng lợi nhuận |
| TyLe_CFO_Tren_LNST | \(\text{CFO} / \text{LNST}\) | Chất lượng lợi nhuận (khả năng chuyển thành tiền mặt) |
| VonHoa_TyVND | \(\text{Giá Đóng Cửa} \times \text{SL Cổ Phiếu}\) | Quy mô thị trường |
| P_E_CuoiNam | \(\text{Giá Đóng Cửa} / \text{EPS}\) | Hệ số định giá |
Lưu ý: Mục 2.3 sẽ tập trung khai thác các biến trong Nhóm B và C có liên quan đến Hiệu suất & Tăng trưởng.
1. library(readxl)
2. library(dplyr)
3. library(stringr)
4. bctc_path <- "C:/Users/Admin/Documents/NGÔN NGỮ R/PV GAS.xlsx"
5. bckt_raw <- read_excel(bctc_path, sheet = 1) # Bảng Cân đối kế toán
6. kqkd_raw <- read_excel(bctc_path, sheet = 2) # Bảng Kết quả kinh doanh
7. if ("TÀI SẢN" %in% names(bckt_raw)) bckt_raw <- bckt_raw %>% rename(ChiTieu = `TÀI SẢN`)
8. if ("CHỈ TIÊU" %in% names(kqkd_raw)) kqkd_raw <- kqkd_raw %>% rename(ChiTieu = `CHỈ TIÊU`)
9. normalize_vn <- function(x) {
10. x %>%
11. stringi::stri_trans_general("Latin-ASCII") %>%
12. stringr::str_to_lower() %>%
13. stringr::str_squish()}
14. print("Đã chuẩn hóa tên cột thành 'ChiTieu'.")[1] "Đã chuẩn hóa tên cột thành 'ChiTieu'."
Gọi các thư viện cần thiết:
readxl (đọc dữ liệu từ file Excel) ,dplyr(thao
tác, làm sạch dữ liệu)
stringr(xử lý văn bản dữ liệu ). sau khi đưa vào ta thu
được hai bảng dữ liệu đã được làm sạch và chuẩn hoá tên cột, cụ thể “TÀI
SẢN”, “CHỈ TIÊU” đã được chuyển thành ChiTieu
1. library(dplyr); library(stringr); library(lubridate); library(tidyr)
2. year_cols_names <- names(kqkd_raw)[str_detect(names(kqkd_raw), "^\\d{2}/\\d{2}/\\d{4}$")]
3. nam_vec <- as.numeric(str_sub(year_cols_names, -4)) # 2014, 2015, ...
4. extract_row_data <- function(df, chi_tieu_patterns, scale_factor = 1e9) {
5. df <- df %>% mutate(ChiTieu_norm = normalize_vn(ChiTieu))
6. date_cols <- names(df)[stringr::str_detect(names(df), "^\\d{2}/\\d{2}/\\d{4}$")]
7. found <- NULL
8. for (pat in chi_tieu_patterns) {
9. pat_norm <- normalize_vn(pat)
10. cand <- df %>% dplyr::filter(stringr::str_detect(ChiTieu_norm, pat_norm))
11. if (nrow(cand) >= 1) { found <- cand; break }
12. }
13.
14. if (is.null(found)) {
15. warning(sprintf("Không tìm thấy chỉ tiêu: %s", paste(chi_tieu_patterns, collapse = " | ")))
16. return(rep(NA_real_, length(nam_vec)))
17. }
18. if (nrow(found) > 1) {
19. warning(sprintf("Có >1 dòng khớp: %s. Lấy dòng đầu tiên.", paste(chi_tieu_patterns, collapse = " | ")))
20. found <- found %>% dplyr::slice(1)
21. }
22. tmp <- found %>%
23. dplyr::select(dplyr::all_of(date_cols)) %>%
24. tidyr::pivot_longer(everything(), names_to = "Ngay", values_to = "val") %>%
25. dplyr::mutate(
26. Nam = lubridate::year(lubridate::dmy(Ngay)),
27. val_chr = as.character(val),
28. val_num = suppressWarnings(as.numeric(stringr::str_remove_all(val_chr, "[\\.,]")))
29. ) %>%
30. dplyr::arrange(Nam) %>%
31. dplyr::mutate(val_scaled = val_num / scale_factor)
32. tibble::tibble(Nam = nam_vec) %>%
33. dplyr::left_join(tmp %>% dplyr::select(Nam, val_scaled), by = "Nam") %>%
34. dplyr::pull(val_scaled)}
35. print("Đã định nghĩa hàm 'extract_row_data'.")[1] "Đã định nghĩa hàm 'extract_row_data'."
Đoạn code này định nghĩa hàm extract_row_data() để tự động trích xuất, làm sạch và chuẩn hóa dữ liệu tài chính theo năm từ bảng báo cáo gốc. Cụ thể, hàm tìm dòng chứa chỉ tiêu cần lấy ( doanh thu, lợi nhuận), chuyển các cột ngày tháng thành dạng giá trị, chuyển năm, rồi chuyển đổi đơn vị (chia 1 tỷ).
1. GAS_data_final <- data.frame(Nam = nam_vec)
2. scale_vnd_to_ty <- 1e9 # Chia cho 1 Tỷ
3. lctt_raw <- try(read_excel(bctc_path, sheet = 3), silent = TRUE)
4. if (!inherits(lctt_raw, "try-error")) {
5. if ("LƯU CHUYỂN TIỀN TỆ" %in% names(lctt_raw))
6. lctt_raw <- lctt_raw %>% rename(ChiTieu = `LƯU CHUYỂN TIỀN TỆ`)
7. else if (!"ChiTieu" %in% names(lctt_raw))
8. lctt_raw <- lctt_raw %>% rename(ChiTieu = names(lctt_raw)[1])
9. # A. Trích xuất CFO (SỬ DỤNG LCTTT_RAW ĐÃ CHUẨN HÓA)
10. GAS_data_final$CFO <- extract_row_data(lctt_raw,
11. c("lưu chuyển tiền thuần từ hoạt động kinh doanh",
12. "luu chuyen tien thuan tu hoat dong kinh doanh"),
13. scale_factor = scale_vnd_to_ty)
14. } else {
15. warning("Không đọc được sheet 3 (LCTT). Cột CFO sẽ là NA.")
16. GAS_data_final$CFO <- NA_real_}
17. # A. Trích xuất nhóm 1 (Tài chính cơ bản)
18. # 1. Từ Bảng KQKD (Đơn vị: Tỷ VND)
19. GAS_data_final$DoanhThu <- extract_row_data(
20. kqkd_raw,
21. c("doanh thu thuần về bán hàng và cung cấp dịch vụ",
22. "doanh thu thuần"),
23. scale_factor = scale_vnd_to_ty # Giữ nguyên scale_factor
24. )
25. GAS_data_final$LoiNhuanSauThue <- extract_row_data(
26. kqkd_raw,
27. c("lợi nhuận sau thuế thu nhập doanh nghiệp",
28. "lợi nhuận sau thuế của cổ đông công ty mẹ",
29. "lợi nhuận sau thuế"),
30. scale_factor = scale_vnd_to_ty # Giữ nguyên scale_factor
31. )
32. # 2. Từ Bảng Cân đối Kế toán (Đơn vị: Tỷ VND)
33. GAS_data_final$TongTaiSan <- extract_row_data(
34. bckt_raw,
35. c("tổng cộng tài sản", "tong cong tai san"),
36. scale_factor = scale_vnd_to_ty # Giữ nguyên scale_factor
37. )
38. GAS_data_final$VonChuSoHuu <- extract_row_data(
39. bckt_raw,
40. c("vốn chủ sở hữu", "von chu so huu", "d. von chu so huu"),
41. scale_factor = scale_vnd_to_ty # Giữ nguyên scale_factor
42. )
43. GAS_data_final$NoPhaiTra <- extract_row_data(
44. bckt_raw,
45. c("nợ phải trả", "no phai tra"),
46. scale_factor = scale_vnd_to_ty # Giữ nguyên scale_factor
47. )
48. # B. Trích xuất nhóm 2
49. # 1. Trích xuất EPS (Đơn vị: VND/cp - không scale)
50. GAS_data_final$EPS <- extract_row_data(
51. kqkd_raw,
52. c("lãi cơ bản trên cổ phiếu", "eps"),
53. scale_factor = 1
54. )
55. # 2. Bỏ qua khối code CFO bị lỗi lặp lại ở đây
56. # 3. Giá
57. GAS_data_final$Gia_DongCua_CuoiNam <- c(34154, 18129, 33089, 56311, 52232, 58210, 56436, 64672, 70096, 64830, 64160)
58. # 4. Tính toán SLCP
59. GAS_data_final$SL_CoPhieu_LuuHanh <- round((GAS_data_final$LoiNhuanSauThue * 1e9) / GAS_data_final$EPS)
60. # C. Tính toán các biến Phái sinh
61. data <- GAS_data_final
62. data$ROE_Nam <- (data$LoiNhuanSauThue / data$VonChuSoHuu) * 100
63. data$ROA_Nam <- (data$LoiNhuanSauThue / data$TongTaiSan) * 100
64. data <- data %>%
65. dplyr::mutate(
66. BienLoiNhuanRong_Nam = (LoiNhuanSauThue / DoanhThu) * 100,
67. FL_Nam = TongTaiSan / VonChuSoHuu,
68. TAT_Nam = DoanhThu / TongTaiSan,
69. DoanhThu_TangTruong_YoY = (DoanhThu / dplyr::lag(DoanhThu) - 1) * 100,
70. LoiNhuan_TangTruong_YoY = (LoiNhuanSauThue / dplyr::lag(LoiNhuanSauThue) - 1) * 100,
71. TySoNo_Tren_VCSH = NoPhaiTra / VonChuSoHuu,
72. # SỬA LỖI: Dùng ifelse để xử lý NA/Inf nếu CFO/LNST là NA/0
73. TyLe_CFO_Tren_LNST = ifelse(LoiNhuanSauThue != 0, CFO / LoiNhuanSauThue, NA_real_),
74. VonHoa_TyVND = (Gia_DongCua_CuoiNam * SL_CoPhieu_LuuHanh) / 1e9,
75. flag_roa_abnormal = dplyr::case_when(ROA_Nam > 100 ~ TRUE, TRUE ~ FALSE)
76. )
77. data$DoanhThu_TangTruong_YoY[is.na(data$DoanhThu_TangTruong_YoY)] <- 0
78. data$LoiNhuan_TangTruong_YoY[is.na(data$LoiNhuan_TangTruong_YoY)] <- 0
79. GAS_data_final <- data %>% dplyr::filter(flag_roa_abnormal == FALSE)
80. print(head(GAS_data_final)) Nam CFO DoanhThu LoiNhuanSauThue TongTaiSan VonChuSoHuu NoPhaiTra EPS
1 2014 16701 73393 14370 53791 37679 16112 7140
2 2015 9127 64300 8832 56715 42889 13826 4400
3 2016 4942 59076 7172 56754 40844 15910 6748
4 2017 14386 64522 9938 61889 43272 18618 4994
5 2018 12422 75612 11709 62614 46867 15747 5911
6 2020 7331 64135 797 63208 49500 13709 4028
Gia_DongCua_CuoiNam SL_CoPhieu_LuuHanh ROE_Nam ROA_Nam BienLoiNhuanRong_Nam
1 34154 2012580185 38.14 26.71 19.58
2 18129 2007301345 20.59 15.57 13.74
3 33089 1062894151 17.56 12.64 12.14
4 56311 1989946445 22.97 16.06 15.40
5 52232 1980809589 24.98 18.70 15.49
6 56436 197909415 1.61 1.26 1.24
FL_Nam TAT_Nam DoanhThu_TangTruong_YoY LoiNhuan_TangTruong_YoY
1 1.43 1.36 0.00 0.0
2 1.32 1.13 -12.39 -38.5
3 1.39 1.04 -8.12 -18.8
4 1.43 1.04 9.22 38.6
5 1.34 1.21 17.19 17.8
6 1.28 1.01 -14.49 -93.4
TySoNo_Tren_VCSH TyLe_CFO_Tren_LNST VonHoa_TyVND flag_roa_abnormal
1 0.428 1.162 68738 FALSE
2 0.322 1.033 36390 FALSE
3 0.390 0.689 35170 FALSE
4 0.430 1.448 112056 FALSE
5 0.336 1.061 103462 FALSE
6 0.277 9.196 11169 FALSE
Nhận xét:
Bảng dữ liệu đã được trích xuất và chuẩn hóa thành công phản ánh đầy đủ hiệu quả hoạt động, cấu trúc tài chính và tăng trưởng của PVGas trong giai đoạn 2014–2024. Sáu dòng đầu tiên minh họa cho cấu trúc dữ liệu, với ba nhóm biến chính:
Nhóm biến gốc (hoạt động & quy mô):
DoanhThu, LoiNhuanSauThue,
TongTaiSan, VonChuSoHuu,
NoPhaiTra, CFO, EPS,
Gia_DongCua_CuoiNam, SL_CoPhieu_LuuHanh
→ Cung cấp nền tảng cho việc tính toán tỷ suất sinh lời và định
giá.
Nhóm biến hiệu suất & cấu trúc DuPont:
ROE_Nam, ROA_Nam,
BienLoiNhuanRong_Nam, TAT_Nam,
FL_Nam
→ Dùng để phân tích hiệu quả sinh lời, khả năng sử dụng tài sản và mức
độ đòn bẩy tài chính.
Nhóm biến tăng trưởng & chất lượng tài
chính:
DoanhThu_TangTruong_YoY,
LoiNhuan_TangTruong_YoY, VonHoa_TyVND,
TySoNo_Tren_VCSH, TyLe_CFO_Tren_LNST,
flag_roa_abnormal
→ Phản ánh tốc độ tăng trưởng, quy mô vốn hóa, sức khỏe tài chính và khả
năng tạo tiền của doanh nghiệp.
Mục này tập trung vào thống kê mô tả, phân phối, và xu hướng dòng
thời gian của các biến cốt lõi trong Nhóm 1 (DoanhThu,
LoiNhuanSauThue, ROE_Nam,
ROA_Nam, EPS,
BienLoiNhuanRong_Nam, và các biến tăng trưởng).
1. library(dplyr); library(moments); library(ggplot2)
2. library(tidyr); library(scales); library(zoo)
3. stats_group1_full <- data %>%
4. dplyr::rename(ROE = ROE_Nam, ROA = ROA_Nam, BienLoiNhuanRong = BienLoiNhuanRong_Nam) %>%
5. dplyr::summarise(
6. dplyr::across(
7. c(DoanhThu, LoiNhuanSauThue, EPS, ROE, ROA, BienLoiNhuanRong),
8. list(
9. Mean = ~mean(., na.rm = TRUE),
10. Median = ~median(., na.rm = TRUE),
11. SD = ~sd(., na.rm = TRUE),
12. Min = ~min(., na.rm = TRUE),
13. Max = ~max(., na.rm = TRUE),
14. CV = ~sd(., na.rm = TRUE)/mean(., na.rm = TRUE)
15. ),
16. .names = "{.col}_{.fn}"
17. )
18. ) %>%
19. tidyr::pivot_longer(dplyr::everything(), names_to = "Tên_Biến_và_Hàm", values_to = "Giá_Trị") %>%
20. tidyr::separate(Tên_Biến_và_Hàm, into = c("Biến", "Hàm"), sep = "_", extra = "merge") %>%
21. tidyr::pivot_wider(names_from = Hàm, values_from = Giá_Trị) %>%
22. dplyr::rename(Hệ_số_biến_thiên_CV = CV)
23. stats_group1_display <- stats_group1_full
24. knitr::kable(stats_group1_display, digits = 3, caption = "Bảng thống kê mô tả các biến tài chính")| Biến | Mean | Median | SD | Min | Max | Hệ_số_biến_thiên_CV |
|---|---|---|---|---|---|---|
| DoanhThu | 77207.1 | 75005.3 | 15041.35 | 59076.19 | 103564.1 | 0.195 |
| LoiNhuanSauThue | 10109.5 | 10590.1 | 3883.78 | 797.18 | 15066.4 | 0.384 |
| EPS | 5517.6 | 4994.0 | 1263.99 | 4028.00 | 7649.0 | 0.229 |
| ROE | 20.6 | 20.6 | 8.74 | 1.61 | 38.1 | 0.423 |
| ROA | 190.0 | 15.6 | 581.65 | 1.26 | 1943.7 | 3.061 |
| BienLoiNhuanRong | 13.0 | 13.7 | 4.68 | 1.24 | 19.6 | 0.360 |
Nhận xét:
Phần này không giải thích kĩ thuật vì tương tự thống kê mô tả ở bộ dữ liệu 1, ta đi sâu vào bàn luận kết quả sơ bộ:
PVGas duy trì doanh thu ổn định và quy mô lớn, với hệ số biến thiên CV < 0.2, thể hiện nhu cầu thị trường ổn định và vị thế vững chắc trong chuỗi cung ứng khí.
Lợi nhuận sau thuế trung bình đạt ~10.1 nghìn tỷ VND, ROE trung bình ~20.6%, và biên lợi nhuận ròng ~13%, đều có CV thấp (<0.4) → cho thấy khả năng sinh lời cao, ổn định và kiểm soát chi phí tốt.
Chỉ số ROA có Mean = 190% nhưng Median = 15.6%, cho thấy tồn tại giá trị ngoại lệ (outlier), tuy nhiên ROA trung vị 15.6% vẫn phản ánh hiệu quả sử dụng tài sản mạnh. Khoảng cách nhỏ giữa ROE và ROA chứng minh đòn bẩy tài chính thấp, doanh nghiệp vận hành an toàn.
EPS trung bình ≈ 5,518 VND/cổ phiếu với CV = 0.229, khẳng định khả năng tạo giá trị ổn định cho cổ đông.
Kết luận:
PVGas là doanh nghiệp có nền tảng tài chính vững chắc, sinh lời
bền vững và rủi ro thấp, thể hiện qua:
- ROE ≈ 20.6% → Hiệu quả sinh lời cao trên vốn
chủ.
- ROA ≈ 15.6% → Sử dụng tài sản hiệu quả.
- Biên lợi nhuận ròng ≈ 13% → Hiệu quả kinh doanh cốt
lõi ổn định.
1. # Hình dạng phân phối
2. skew_kurt_group1 <- data %>%
3. dplyr::select(LoiNhuanSauThue, ROE_Nam, BienLoiNhuanRong_Nam, DoanhThu_TangTruong_YoY) %>%
4. dplyr::summarise(
5. dplyr::across(
6. dplyr::everything(),
7. list(
8. Skewness = ~moments::skewness(., na.rm = TRUE),
9. Kurtosis = ~moments::kurtosis(., na.rm = TRUE)),
10. .names = "{.col}_{.fn}"))
11. print(skew_kurt_group1) LoiNhuanSauThue_Skewness LoiNhuanSauThue_Kurtosis ROE_Nam_Skewness
1 -1.11 4.14 -0.23
ROE_Nam_Kurtosis BienLoiNhuanRong_Nam_Skewness BienLoiNhuanRong_Nam_Kurtosis
1 4.26 -1.34 4.88
DoanhThu_TangTruong_YoY_Skewness DoanhThu_TangTruong_YoY_Kurtosis
1 0.215 1.6
Nhận xét
| Biến | Skewness (Độ lệch) | Kurtosis (Độ nhọn) | Hình dạng Phân phối |
|---|---|---|---|
| LoiNhuanSauThue | -1.11 | 4.14 | Lệch âm (trái), Nhọn hơn Chuẩn |
| ROE_Nam | -0.23 | 4.26 | Gần đối xứng, Nhọn hơn Chuẩn |
| BienLoiNhuanRong_Nam | -1.34 | 4.88 | Lệch âm (trái) mạnh, Rất nhọn |
| DoanhThu_TangTruong_YoY | 0.215 | 1.6 | Gần đối xứng, Bẹt hơn Chuẩn |
Nhìn chung:
Tính lệch (Skewness):
Lợi nhuận và Biên lợi nhuận ròng (LNR) có độ lệch âm
mạnh (–1.11 đến –1.34), cho thấy dữ liệu bị kéo về phía
giá trị thấp, đđiều này khớp với giai đoạn khủng hoảng
giá dầu (2015-2016), nơi lợi nhuận và biên lợi nhuận bị sụt giảm cực
sâu. Chỉ tiêu ROE gần như đối xứng (–0.23), nghĩa là
biến động giữa các năm tốt và xấu được cân bằng.
Độ nhọn (Kurtosis):
LNST, ROE và Biên LNR có Kurtosis >
4, tức là phân phối rất nhọn, dữ liệu tập trung quanh trung
bình nhưng có một số giá trị cực đoan. Doanh thu tăng trưởng
YoY có Kurtosis ≈ 1.6, biểu hiện phân phối
bẹt, cho thấy doanh thu ổn định hơn các chỉ tiêu lợi nhuận.
Tóm lại: Dữ liệu cho thấy hiệu suất tài chính của GAS nhìn chung ổn định, nhưng vẫn tồn tại một vài năm biến động cực đoan do ảnh hưởng của chu kỳ giá dầu.
1. cagr_dt <- ((data$DoanhThu[data$Nam == 2024] / data$DoanhThu[data$Nam == 2014])^(1/10) - 1) * 100
2. cagr_lnst_full <- ((data$LoiNhuanSauThue[data$Nam == 2024] / data$LoiNhuanSauThue[data$Nam == 2014])^(1/10) - 1) * 100
3. cagr_lnst_recovery <- ((data$LoiNhuanSauThue[data$Nam == 2024] / data$LoiNhuanSauThue[data$Nam == 2016])^(1/8) - 1) * 100
4. cagr_table <- data.frame(
5. Chỉ_tiêu = c("CAGR Doanh thu (2014–2024)",
6. "CAGR Lợi nhuận ST (2014–2024)",
7. "CAGR Lợi nhuận ST (2016–2024, phục hồi)"),
8. Tỷ_lệ_Tăng_Trưởng = c(cagr_dt, cagr_lnst_full, cagr_lnst_recovery)
9. )
10. kable(cagr_table,
11. caption = "Bảng: Tốc độ tăng trưởng kép của doanh thu và lợi nhuận sau thuế",
12. digits = 2)| Chỉ_tiêu | Tỷ_lệ_Tăng_Trưởng |
|---|---|
| CAGR Doanh thu (2014–2024) | 3.50 |
| CAGR Lợi nhuận ST (2014–2024) | -3.01 |
| CAGR Lợi nhuận ST (2016–2024, phục hồi) | 4.99 |
Giải thích kĩ thuật
| Phần / Dòng code | Giải thích chi tiết |
|---|---|
| Dòng 1 | Tính CAGR của Doanh thu giai đoạn 2014–2024 bằng công thức \((Giá\ trị\ cuối / Giá\ trị\ đầu)^{1/10} - 1\), sau đó nhân 100 để ra % tăng trưởng/năm. |
| Dòng 2 | Tính CAGR của Lợi nhuận sau thuế trong cùng giai đoạn 2014–2024. |
| Dòng 3 | Tính CAGR Lợi nhuận sau thuế giai đoạn phục hồi (2016–2024) |
| Dòng 4–9 | Tạo bảng dữ liệu cagr_table |
Dòng 10–12 (kable(...)) |
in bảng |
Nhận xét:
Tăng trưởng doanh thu bền vững: CAGR Doanh thu \(3.50\%\) là một mức tăng trưởng ổn định, thể hiện sự mở rộng quy mô hợp lý và khả năng chống chịu tốt.
Ảnh hưởng của Năm Gốc: CAGR Lợi nhuận toàn giai đoạn là âm (-3.01%). Điều này là hệ quả trực tiếp của việc sử dụng năm 2014 (năm có lợi nhuận cực đỉnh) làm năm gốc, tạo ra hiệu ứng nền cao giả.
Tốc độ Phục hồi Hợp lý: CAGR Lợi nhuận giai đoạn phục hồi (2016-2024) là \(4.99\%\). Tốc độ này tuy thấp hơn mức \(63.80\%\) tính toán trước đó (điều chỉnh do ngoại lai 2016), nhưng \(4.99\%\) là một mức tăng trưởng lợi nhuận ổn định và hợp lý hơn so với mức tăng trưởng doanh thu. Nó chứng minh rằng GAS đã thoát khỏi khủng hoảng và duy trì được đà tăng trưởng lợi nhuận dương trong suốt 8 năm sau đó.
1. ggplot(data, aes(x = BienLoiNhuanRong_Nam)) +
2. geom_histogram(aes(y = after_stat(density)), bins = 10, fill = "#0072B2", color = "white", alpha = 0.7) +
3. geom_density(color = "#D55E00", linewidth = 1) +
4. geom_vline(aes(xintercept = mean(BienLoiNhuanRong_Nam)), linetype = "dashed", color = "red") +
5. labs(title = "Phân phối của biên lợi nhuận ròng (2014-2024)",
6. x = "Biên lợi nhuận ròng (%)", y = "Mật độ") +
7. theme_minimal()Nhận xét
Biểu đồ cho thấy phân phối của Biên lợi nhuận ròng (LNR) có dạng hai đỉnh, thể hiện sự biến động theo chu kỳ hoạt động của GAS:
Cụm thấp (0–5%) xuất hiện ở giai đoạn 2015–2016, khi doanh nghiệp chịu ảnh hưởng tiêu cực từ suy giảm giá dầu và chi phí đầu vào cao, khiến lợi nhuận gần như chạm đáy.
Cụm cao (10–18%) là vùng tập trung chính của dữ liệu, thể hiện giai đoạn phục hồi và ổn định trong hầu hết các năm, khi biên lợi nhuận của GAS duy trì ở mức cao và bền vững.
Đường trung bình (đỏ đứt đoạn) nằm khoảng 13%, phản ánh hiệu suất sinh lời ổn định trong dài hạn. Đây là mức cao đối với một doanh nghiệp có quy mô lớn và ổn định như GAS
Từ đó biểu đồ minh họa rõ hai giai đoạn đối lập trong hoạt động của GAS: Giai đoạn suy giảm ngắn hạn (2015–2016) với lợi nhuận co hẹp. và giai đoạn ổn định và tăng trưởng (từ 2017 trở đi) với Biên LNR dao động quanh 13–15%, chứng tỏ khả năng duy trì hiệu quả chi phí và năng lực sinh lời vững chắc của doanh nghiệp.
1. q <- quantile(data$ROE_Nam, probs = c(0.25, 0.75), na.rm = TRUE)
2. iqr <- q[2] - q[1]
3. upper <- q[2] + 1.5*iqr
4. lower <- q[1] - 1.5*iqr
5. ggplot(data, aes(x = factor(0), y = ROE_Nam)) +
6. geom_boxplot(fill = "#009E73", alpha = 0.7, outlier.colour = "red") +
7. geom_text(data = dplyr::filter(data, ROE_Nam > upper | ROE_Nam < lower),
8. aes(label = Nam), vjust = -0.5) +
9. labs(title = "Giá trị ngoại lai của ROE",
10. x = "", y = "ROE (%)") +
11. theme_minimal() +
12. scale_y_continuous(labels = label_number(suffix = "%")) +
13. theme(legend.position = "none")Nhận xét biểu đồ
Biểu đồ boxplot cho thấy ROE của GAS chủ yếu nằm trong khoảng 18–25%, với trung vị khoảng 20%, phản ánh hiệu suất sinh lời cao và ổn định trong giai đoạn 2014–2024.
Tuy nhiên vẫn có sự xuất hiện ngoại lệ đáng chú ý:
Năm 2014 (Outlier cao):** ROE vượt quá 30–35%, vượt xa phạm vi bình thường. → Đây là giai đoạn đỉnh lợi nhuận trước khủng hoảng giá dầu, khi giá bán khí và biên lợi nhuận ở mức cao kỷ lục. ROE cao phản ánh hiệu quả sử dụng vốn vượt trội, nhưng cũng là giá trị “đỉnh chu kỳ”
Năm 2020 (Outlier thấp): ROE gần 0%, rơi xuống mức cực tiểu. → Đây là năm chịu tác động kép của đại dịch COVID-19 và giá dầu âm, khiến lợi nhuận sau thuế sụt giảm nghiêm trọng, dù doanh thu không giảm mạnh. ROE gần 0 cho thấy gần như toàn bộ lợi nhuận bị xóa bởi chi phí và dự phòng.
1. library(ggplot2)
2. library(dplyr)
3. library(scales)
4. data_long_rev_profit <- data %>%
5. select(Nam, DoanhThu, LoiNhuanSauThue) %>%
6. mutate(
7. DoanhThu = DoanhThu / 1000,
8. LoiNhuanSauThue = LoiNhuanSauThue / 1000
9. ) %>%
10. pivot_longer(-Nam, names_to = "ChiTieu", values_to = "GiaTri")
11. highlight_years <- c(2016, 2020, 2022)
12. highlight_points <- data_long_rev_profit %>% filter(Nam %in% highlight_years)
13. ggplot(data_long_rev_profit, aes(x = Nam, y = GiaTri, group = ChiTieu, color = ChiTieu)) +
14. geom_line(linewidth = 1.3, alpha = 0.9) +
15. geom_point(size = 3) +
16. geom_point(
17. data = highlight_points,
18. aes(x = Nam, y = GiaTri),
19. size = 5,
20. shape = 21,
21. fill = "white",
22. color = "black",
23. stroke = 1.2
24. ) +
25. geom_text(
26. data = highlight_points,
27. aes(
28. label = case_when(
29. Nam == 2016 ~ "Đáy chu kỳ\n(giá dầu giảm)",
30. Nam == 2020 ~ "Khủng hoảng COVID &\ngiá dầu âm",
31. Nam == 2022 ~ "Phục hồi mạnh\nBiên lợi nhuận cao"
32. )
33. ),
34. vjust = -1.2, hjust = 0.5, size = 3.5, fontface = "italic", color = "black"
35. ) +
36. geom_hline(
37. yintercept = mean(data_long_rev_profit$GiaTri[data_long_rev_profit$ChiTieu == "DoanhThu"]),
38. linetype = "dashed", color = "#0072B2", linewidth = 0.7, alpha = 0.7
39. ) +
40. geom_hline(
41. yintercept = mean(data_long_rev_profit$GiaTri[data_long_rev_profit$ChiTieu == "LoiNhuanSauThue"]),
42. linetype = "dashed", color = "#D55E00", linewidth = 0.7, alpha = 0.7
43. ) +
44. annotate("text", x = 2014.5,
45. y = mean(data_long_rev_profit$GiaTri[data_long_rev_profit$ChiTieu == "DoanhThu"]) + 2,
46. label = "Trung bình Doanh thu", color = "#0072B2", size = 2, hjust = 0) +
47. annotate("text", x = 2014.5,
48. y = mean(data_long_rev_profit$GiaTri[data_long_rev_profit$ChiTieu == "LoiNhuanSauThue"]) + 1,
49. label = "Trung bình LNST", color = "#D55E00", size = 2, hjust = 0) +
50. scale_y_continuous(labels = label_number(big.mark = ",", suffix = " Nghìn Tỷ VND")) +
51. scale_color_manual(
52. values = c("DoanhThu" = "#0072B2", "LoiNhuanSauThue" = "#D55E00"),
53. labels = c("DoanhThu" = "Doanh thu thuần", "LoiNhuanSauThue" = "Lợi nhuận Sau Thuế")
54. ) +
55. labs(
56. title = "Xu hướng doanh thu và lợi nhuận sau thuế",
57. subtitle = "Các năm đặc biệt được chú thích: 2016 (đáy), 2020 (khủng hoảng), 2022 (phục hồi mạnh)",
58. x = "Năm",
59. y = "Giá trị (Nghìn tỷ VND)",
60. color = "Chỉ tiêu"
61. ) +
62. theme_minimal(base_size = 12) +
63. theme(
64. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
65. plot.subtitle = element_text(size = 7, hjust = 0.5),
66. legend.position = "bottom",
67. panel.grid.minor = element_blank(),
68. panel.grid.major.x = element_blank()
69. )Nhận xét kĩ thuật
| Phần / Dòng code | Giải thích chi tiết |
|---|---|
| Dòng 1–3 | Nạp các thư viện cần thiết: ggplot2 để vẽ biểu đồ,
dplyr để xử lý dữ liệu, và scales để định dạng
trục số. |
| Dòng 4–10 | dùng select(), mutate() chọn các cột
Nam, DoanhThu, LoiNhuanSauThue,
sau đó chuyển đổi đơn vị về nghìn tỷ VND |
| Dòng 11–12 | Xác định và lọc ra các năm (2016, 2020, 2022) để hiển thị nhãn riêng
bằng filter() |
| Dòng 13–15 | Khởi tạo ggplot(), vẽ hai đường xu hướng
(geom_line()) và các điểm dữ liệu
(geom_point()), với màu khác nhau cho từng chỉ tiêu. |
| Dòng 16–24 | geom_point() ánh xạ hiệu ứng nổi bật (highlight) cho
các năm đặc biệt bằng vòng tròn trắng viền đen
(shape = 21) |
| Dòng 25–35 | Dùng geom_text() để chú thích các năm nổi bật trực tiếp
trên biểu đồ |
| Dòng 36–43 | Dùng geom_hline() vẽ hai đường trung bình cho Doanh thu
và Lợi nhuận sau thuế bằng |
| Dòng 44–49 | scale_color_manual() gán màu cụ thể:
#0072B2 (xanh dương – Doanh thu), #D55E00 (cam
– Lợi nhuận) |
| Dòng 50 | Định dạng trục Y bằng scale_y_continuous() và
label_number() để hiển thị rõ ràng đơn vị “Nghìn tỷ
VND”. |
| Dòng 51–54 | Tùy chỉnh lại màu cho từng biến (scale_color_manual()):
xanh (#0072B2) cho Doanh thu, cam
(#D55E00) cho Lợi nhuận, và đổi tên chú thích trong
Legend. |
| Dòng 55–61 | (labs()) thêm tiêu đề, nhãn |
| Dòng 62–69 | Áp dụng theme_minimal() và đưa chú thích xuống phía
dưới (legend.position = "bottom"). |
Nhận xét
Biểu đồ thể hiện rõ chu kỳ hoạt động gồm hai pha chính của Tổng Công ty Khí Việt Nam (GAS):
Giai đoạn 2014–2016: Khủng hoảng và suy giảm: Doanh thu giảm từ khoảng 75 nghìn tỷ VND xuống dưới 60 nghìn tỷ VND, đồng thời lợi nhuận sau thuế giảm mạnh hơn, rơi từ mức trên 10 nghìn tỷ VND xuống gần 3 nghìn tỷ VND → Đây là giai đoạn “đáy chu kỳ”, doanh nghiệp chịu ảnh hưởng kép từ giá dầu thấp và chi phí cố định cao.
Giai đoạn 2017–2024 – Phục hồi và mở rộng: Doanh thu phục hồi rõ rệt, đạt đỉnh mới trên 100 nghìn tỷ VND vào năm 2024. Lợi nhuận cũng phục hồi, nhưng có dao động mạnh, đặc biệt giảm sâu vào năm 2020 (COVID-19, giá dầu âm) sau đó bật tăng mạnh vào 2022, rồi ổn định hơn giai đoạn sau.
Điều này cho thấy khi doanh thu tăng, lợi nhuận cũng tăng, nhưng biên độ biến động lợi nhuận lớn hơn → Điều này phản ánh rằng biên lợi nhuận ròng (LNST/Doanh thu) là yếu tố quyết định hiệu suất: chỉ cần biến động nhẹ về giá bán hoặc chi phí đầu vào cũng khiến lợi nhuận thay đổi mạnh.
1. data_long_yoy <- data %>%
2. select(Nam, DoanhThu_TangTruong_YoY, LoiNhuan_TangTruong_YoY) %>%
3. filter(Nam != 2014) %>% # Loại bỏ năm gốc (NA/0)
4. pivot_longer(-Nam, names_to = "ChiTieu", values_to = "YoY")
5. ggplot(data_long_yoy, aes(x = factor(Nam), y = YoY, fill = ChiTieu)) +
6. geom_bar(stat = "identity", position = "dodge") +
7. scale_y_continuous(labels = label_number(suffix = "%")) +
8. scale_fill_manual(values = c("DoanhThu_TangTruong_YoY" = "#0072B2", "LoiNhuan_TangTruong_YoY" = "#D55E00"),
9. labels = c("DoanhThu_TangTruong_YoY" = "Doanh thu YoY", "LoiNhuan_TangTruong_YoY" = "Lợi nhuận YoY")) +
10. labs(title = "Biến động tăng trưởng YoY: Doanh thu vs lợi nhuận (2015-2024)",
11. x = "Năm", y = "Tốc độ tăng trưởng (%)", fill = "Chỉ tiêu") +
12. theme_minimal()Nhận xét
Xét theo từng giai đoạn
Giai đoạn 2015–2016: Cả doanh thu và lợi nhuận đều tăng trưởng âm, trong đó lợi nhuận giảm mạnh hơn doanh thu. Đây là giai đoạn biên lợi nhuận bị bào mòn nghiêm trọng, phù hợp với thời kỳ giá dầu thế giới lao dốc.
Giai đoạn 2017–2019: Cả hai chỉ tiêu tăng trưởng nhẹ quanh mức dương → GAS đã vượt qua giai đoạn khủng hoảng và bước vào chu kỳ tăng trưởng bền vững, nhờ giá dầu phục hồi và chi phí được kiểm soát tốt hơn.
Năm 2020: Giá trị lợi nhuận YoY giảm sâu hơn, trong khi doanh thu chỉ giảm nhẹ → Minh chứng cho tác động mạnh của đại dịch COVID-19 và giá dầu âm
Năm 2021: Lợi nhuận YoY tăng vọt ~1000% → Đây không phải là tăng trưởng thực chất, mà có thể lầ mức phản ánh sự phục hồi vượt trội sau khủng khoảng
Giai đoạn 2022–2024: Mức tăng trưởng lợi nhuận trở về mức dương vừa phải
Từ đó biểu đồ khẳng định:
1. data_long_roe_roa <- data %>%
2. select(Nam, ROE_Nam, ROA_Nam) %>%
3. pivot_longer(-Nam, names_to = "ChiTieu", values_to = "GiaTri")
4. ggplot(data_long_roe_roa, aes(x = Nam, y = GiaTri, group = ChiTieu, color = ChiTieu)) +
5. geom_line(linewidth = 1.2) +
6. geom_point(size = 3) +
7. scale_y_continuous(labels = label_number(suffix = "%")) +
8. scale_color_manual(values = c("ROE_Nam" = "#009E73", "ROA_Nam" = "#F0E442"),
9. labels = c("ROE_Nam" = "ROE", "ROA_Nam" = "ROA")) +
10. labs(title = "Quỹ đạo hiệu suất sinh lời: ROE vs ROA (2014-2024)",
11. x = "Năm", y = "Tỷ suất sinh lời (%)", color = "Chỉ tiêu") +
12. theme_minimal()Nhận xét
1. scale_factor_eps <- max(data$BienLoiNhuanRong_Nam) / max(data$EPS)
2. median_eps <- median(data$EPS)
3. median_margin <- median(data$BienLoiNhuanRong_Nam)
4. ggplot(data, aes(x = Nam)) +
5. geom_line(aes(y = EPS), color = "#0072B2", linewidth = 1.2) +
6. geom_point(aes(y = EPS), color = "#0072B2", size = 3) +
7. geom_line(aes(y = BienLoiNhuanRong_Nam / scale_factor_eps), color = "#D55E00", linewidth = 1.2, linetype = "dashed") +
8. scale_y_continuous(
9. name = "EPS (VND)",
10. labels = comma,
11. sec.axis = sec_axis(~ . * scale_factor_eps, name = "Biên Lợi nhuận Ròng (%)", labels = label_number(suffix = "%"))
12. ) +
13. labs(title = "Xu hướng EPS và biên lợi nhuận ròng (2014-2024)",
14. x = "Năm") +
15. theme_minimal()Nhận xét
Giai đoạn 2014–2016: Biên LNR giảm mạnh từ ~18% xuống gần 10%, tương tự EPS sụt tương ứng từ ~7.000 VND/cp xuống còn ~4.500 VND/cp → Thể hiện tác động kép của khủng hoảng giá dầu khiến hiệu suất sinh lời và giá đều giảm
Giai đoạn 2017–2019: Biên LNR duy trì quanh 13–15%, EPS dao động ổn định ~6.000–7.000 VND/cp, đây được xem là giai đoạn ổn định.
Năm 2020: Biên LNR giảm sâu chỉ còn khoảng 5%, đồng thời EPS rơi về ~4.000 VND/cp, mức thấp nhất kể từ 2014 → Cho thấy tác động tiêu cực mạnh mẽ của COVID-19 và giá dầu âm, khi chi phí vận hành và tài chính không thể co giãn theo doanh thu.
Năm 2021–2022: Biên LNR tăng nhanh trở lại lên 15–16%, đồng thời EPS vọt lên 7.800 VND/cp, phản ánh kết quả tái cơ cấu và giá dầu được phục hồi.
Năm 2023–2024: có sự điều chỉnh nhẹ n hưng không nhiều, biên LNR về ~11–12%, EPS về ~5.000–5.500 VND/cp.
Qua đó có thể khẳng định “Biên lợi nhuận ròng là biến dẫn dắt chính của hiệu suất cổ phiếu GAS.” Khi biên lợi nhuận tăng ổn định trên 12–15%, EPS duy trì ở mức ≥6.000 VND/cp, ngược lại mỗi khi biên lợi nhuận suy giảm đột ngột** (như 2015–2016, 2020), **EPS lập tức giảm mạnh, phản ánh độ nhạy cao của lợi nhuận với biến động thị trường dầu khí.
Phân tích hồi quy song song được thực hiện nhằm kiểm định mối quan hệ tuyến tính giữa các chỉ tiêu tài chính cốt lõi của PVGas và đánh giá ảnh hưởng của các quan sát bất thường (outlier) đến độ tin cậy của mô hình.
Cụ thể, mẫu Full bao gồm toàn bộ giai đoạn 2014–2024, trong khi mẫu Clean loại bỏ năm 2019 do ROA bất thường (ROA > 100%) để kiểm tra tính ổn định của các hệ số.
Mục tiêu của phân tích là xác định hướng và độ mạnh của mối quan hệ giữa các biến (qua Slope và R²), so sánh sự khác biệt giữa hai mẫu để đánh giá độ nhạy của mô hình, đồng thời làm cơ sở định lượng cho việc phân tích hiệu quả sinh lời (ROE, ROA) và định giá cổ phiếu (Giá–EPS)
1. library(dplyr)
2. library(purrr)
3. library(broom)
4. library(tibble)
5. library(scales)
6. library(knitr)
7. library(kableExtra)
8. data_full <- data
9. data_clean <- data %>% filter(Nam != 2019) # Chia dữ liệu làm hai tập full và clean
10. fm_list <- list(
11. `LNST ~ DT` = LoiNhuanSauThue ~ DoanhThu, # tạo danh sách hồi quy song song 3 cặp
12. `ROE ~ ROA` = ROE_Nam ~ ROA_Nam,
13. `Giá ~ EPS` = Gia_DongCua_CuoiNam ~ EPS
14. )
15. fit_and_summarise <- function(df, name_suffix){
16. map_df(names(fm_list), function(lbl){
17. fit <- lm(fm_list[[lbl]], data = df) # thực hiện hồi quy
18. g <- glance(fit) # in kết quả r.squared, adj.r.squared, nobs, ...
19. t <- tidy(fit) # in hệ số & p-value
20. slope_row <- t %>% filter(term != "(Intercept)") %>% slice(1)
21. tibble(
22. Model = lbl,
23. Mẫu = name_suffix,
24. n = g$nobs,
25. R2 = g$r.squared,
26. Adj_R2 = g$adj.r.squared,
27. Slope = slope_row$estimate,
28. `p-value` = slope_row$p.value,
29. Intercept = t$estimate[t$term == "(Intercept)"]
30. )
31. })
32. }
33. summary_models <- bind_rows(
34. fit_and_summarise(data_full, "Full"),
35. fit_and_summarise(data_clean, "Clean")
36. ) %>%
37. mutate(
38. R2 = round(R2, 5),
39. Adj_R2 = round(Adj_R2, 5),
40. Slope = round(Slope, 5),
41. Intercept = round(Intercept, 3),
42. `p-value` = ifelse(`p-value` < 1e-6,
43. format(`p-value`, scientific = TRUE, digits = 2),
44. round(`p-value`, 3))
45. ) %>% # đoạn code làm tròn số
46. mutate(Model = factor(Model, levels = c("LNST ~ DT", "ROE ~ ROA", "Giá ~ EPS"))) %>%
47. arrange(Model, desc(Mẫu))
48. kable(summary_models,
49. caption = "Bảng 2.3.4.1 – Tóm tắt hồi quy song song (Full vs Clean)",
50. align = c("l","l","r","r","r","r","r","r"),
51. digits = 3) %>%
52. kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover","condensed")) %>%
53. column_spec(1, bold = TRUE) %>%
54. row_spec(which(summary_models$Mẫu == "Clean"), background = "#f7f7f7")| Model | Mẫu | n | R2 | Adj_R2 | Slope | p-value | Intercept |
|---|---|---|---|---|---|---|---|
| LNST ~ DT | Full | 11 | 0.298 | 0.220 | 0.141 | 0.082 | -774.923 |
| LNST ~ DT | Clean | 10 | 0.317 | 0.231 | 0.143 | 0.09 | -1193.544 |
| ROE ~ ROA | Full | 11 | 0.023 | -0.086 | 0.002 | 0.657 | 20.209 |
| ROE ~ ROA | Clean | 10 | 0.991 | 0.990 | 1.403 | 1.7e-09 | -0.325 |
| Giá ~ EPS | Full | 11 | 0.006 | -0.104 | -1.037 | 0.816 | 57749.126 |
| Giá ~ EPS | Clean | 10 | 0.010 | -0.113 | -1.338 | 0.778 | 58711.741 |
Nhận xét đánh giá từng cặp biến:
1. ROE ~ ROA (Clean)
R² ≈ 0.991, Adj-R² ≈ 0.990, Slope ≈ 1.403, và p-value ≈ 1.7e-09 → mối quan hệ rất chặt chẽ và có ý nghĩa thống kê cao.Với mức R² gần như tuyệt đối, có thể kết luận rằng ROA là biến giải thích gần như hoàn toàn cho ROE trong giai đoạn phân tích.
Hệ số góc ≈ 1.4 cho thấy ROE ≈ 1.4 × ROA, nghĩa là đòn bẩy tài chính (FL) của PVGas chỉ ở mức 1.3–1.4, phản ánh cấu trúc vốn an toàn, ít phụ thuộc nợ vay
Mối quan hệ này thể hiện hiệu suất sinh lời của PVGas chủ yếu đến từ hoạt động kinh doanh cốt lõi (ROA) chứ không đến từ khuếch đại vốn bằng nợ.
2. LNST ~ Doanh thu (Clean)
R² ≈ 0.317 cho thấy rằng doanh thu chỉ giải thích khoảng 30% biến động lợi nhuận, phần còn lại đến từ hiệu suất hoạt động (ROA), biến động giá khí, tỷ giá, và chi phí tài chính. Đồng thời Adj-R² ≈ 0.231, Slope ≈ 0.143, và p-value ≈ 0.09 → mô hình có ý nghĩa trung bình, mối quan hệ tuyến tính vừa phải giữa doanh thu và lợi nhuận sau thuế.
Mỗi 1 tỷ đồng doanh thu tăng thêm chỉ giúp lợi nhuận tăng khoảng 0.14 tỷ đồng, cho thấy lợi nhuận bị ảnh hưởng mạnh bởi biên lợi nhuận ròng và chi phí biến đổi.
→ Nhìn chung, LNST chịu ảnh hưởng đáng kể từ cấu trúc chi phí và biến động biên lợi nhuận hơn là quy mô doanh thu thuần.
3. Giá ~ EPS (Clean)
1. library(ggplot2)
2. library(dplyr)
3. library(scales)
4. pt_2019 <- data %>% filter(Nam == 2019)
5. r2_full <- summary(lm(ROE_Nam ~ ROA_Nam, data = data))$r.squared
6. r2_clean <- summary(lm(ROE_Nam ~ ROA_Nam, data = filter(data, Nam != 2019)))$r.squared
7. ggplot(data, aes(x = ROA_Nam, y = ROE_Nam)) +
8. annotate("rect", xmin = 0, xmax = 40, ymin = 0, ymax = 40,
9. fill = "grey95", alpha = 0.6) +
10. geom_point(aes(color = "Full sample"), size = 3, alpha = 0.9) +
11. geom_point(data = pt_2019, color = "red", size = 4, shape = 8) +
12. geom_text(data = pt_2019,
13. aes(label = "2019"),
14. vjust = -1, color = "red", fontface = "bold", size = 3.5) +
15. geom_smooth(method = "lm", se = TRUE, color = "#1f77b4",
16. fill = alpha("#1f77b4", 0.15)) +
17. geom_smooth(data = filter(data, Nam != 2019),
18. aes(x = ROA_Nam, y = ROE_Nam),
19. method = "lm", se = TRUE,
20. color = "#d62728", linetype = "dashed",
21. fill = alpha("#d62728", 0.12)) +
22. geom_abline(slope = 1, intercept = 0,
23. linetype = "dotdash", color = "grey40") +
24. annotate("text", x = 6, y = 37,
25. label = sprintf("R² Full = %.3f", r2_full),
26. color = "#1f77b4", hjust = 0, size = 3.3) +
27. annotate("text", x = 6, y = 33,
28. label = sprintf("R² Clean = %.3f", r2_clean),
29. color = "#d62728", hjust = 0, size = 3.3) +
30. coord_cartesian(xlim = c(0, 40), ylim = c(0, 40)) +
31. scale_x_continuous(labels = label_number(suffix = "%")) +
32. scale_y_continuous(labels = label_number(suffix = "%")) +
33. labs(title = "Biểu đồ: Tương quan: ROE ~ ROA (Full vs Clean)",
34. subtitle = "Đường nét liền: Full | Đường gạch: Clean (loại 2019) | Đường chấm: ROE = ROA",
35. x = "ROA (%)", y = "ROE (%)", color = "Mẫu dữ liệu") +
36. scale_color_manual(values = c("Full sample" = "#1f77b4")) +
37. theme_minimal(base_size = 12) +
38. theme(
39. legend.position = "bottom",
40. panel.grid.minor = element_blank(),
41. panel.grid.major.x = element_blank()
42. )Nhận xét kĩ thuật:
| Dòng | Giải thích kĩ thuật |
|---|---|
| Dòng 1–3 | Nạp các thư viện chính: ggplot2 (vẽ biểu đồ),
dplyr (lọc dữ liệu), scales (định dạng phần
trăm). |
| Dòng 4 | Dùng filter() để tách riêng dữ liệu năm
2019 |
| Dòng 5–6 | Sử dụng lm() để hồi quy tuyến tính ROE ~
ROA cho hai mẫu (Full và Clean), sau đó trích
xuất R² bằng $r.squared. |
| Dòng 7–14 | Vẽ điểm dữ liệu tán xạ bằng geom_point(), tô nền xám
bằng annotate("rect") |
| Dòng 15–21 | Vẽ hai đường hồi quy tuyến tính cụ thể liền xanh (#1f77b4): Mẫu Full và đứt đỏ (#d62728): Mẫu Clean (loại 2019). |
| Dòng 22 | tham chiếu ROE = ROAbằng
geom_abline() |
| Dòng 24–29 | Dùng annotate("text") để hiển thị trực tiếp R²
Full và R² Clean trên biểu đồ |
| (30–32) | Giới hạn trục X, Y trong khoảng 0–40%, đồng thời
định dạng nhãn phần trăm bằng
label_number(suffix="%"). |
| Dòng 33–35 | Gán tiêu đề, phụ đề, nhãn trục và chú thích |
| Dòng 36–42 | Tùy chỉnh giao diện bằng scale_color_manual() và
theme_minimal(), ẩn bớt lưới phụ |
Nhận xét
Biểu đồ thể hiện mối quan hệ giữa ROE và ROA, hai chỉ tiêu cốt lõi phản ánh hiệu quả sinh lời và mức đòn bẩy tài chính của GAS.
Ở mô hình Full (màu xanh), hệ số tương quan rất thấp (R² ≈ 0.02), do bị làm nhiễu bởi năm 2019, năm ROA tăng đột biến (~2000%) như nhận định bước trên. Khi loại bỏ năm này mô hình Clean (màu đỏ gạch), mối quan hệ trở nên gần tuyến tính (R² ≈ 0.99), với độ dốc ≈ 1.4, thể hiện đòn bẩy tài chính chỉ khoảng 1.4 lần.
Đường chấm ROE = ROA cho thấy toàn bộ các điểm dữ liệu nằm phía trên, khẳng định ROE luôn cao hơn ROA, tức doanh nghiệp PV GAS có sử dụng đòn bẩy nhưng ở mức thấp và kiểm soát tốt, mối quan hệ ROE–ROA thể hiện hiệu quả vận hành ổn định.
Xây dựng mô hình tuyến tính giữa giá và EPS
1. library(dplyr)
2. library(ggplot2)
3. library(broom)
4. library(scales)
5. if ("conflicted" %in% rownames(installed.packages())) {
6. conflicted::conflict_prefer("select", "dplyr", quiet = TRUE)
7. conflicted::conflict_prefer("filter", "dplyr", quiet = TRUE)
8. conflicted::conflict_prefer("rename", "dplyr", quiet = TRUE)
9. conflicted::conflict_prefer("summarise","dplyr", quiet = TRUE)
10. }
11. d_price <- data %>%
12. dplyr::select(Nam, Gia_DongCua_CuoiNam, EPS) %>%
13. dplyr::filter(!is.na(EPS), !is.na(Gia_DongCua_CuoiNam))
14. d_clean <- d_price %>% dplyr::filter(Nam != 2019) # loại outlier nếu muốn
15. m_full <- lm(Gia_DongCua_CuoiNam ~ EPS, data = d_price)
16. m_clean <- lm(Gia_DongCua_CuoiNam ~ EPS, data = d_clean)
17. r2_full <- summary(m_full)$r.squared
18. r2_clean <- summary(m_clean)$r.squared
19. summary_models_price_eps <- dplyr::bind_rows(
20. broom::tidy(m_full) %>% mutate(Model = "Giá ~ EPS", Mẫu = "Full"),
21. broom::tidy(m_clean) %>% mutate(Model = "Giá ~ EPS", Mẫu = "Clean")
22. ) %>%
23. dplyr::filter(term != "(Intercept)") %>%
24. dplyr::select(Model, Mẫu,
25. Slope = estimate,
26. `Std.Err` = std.error,
27. `t` = statistic,
28. `p-value` = p.value) %>%
29. dplyr::mutate(across(c(Slope, `Std.Err`, `t`), ~round(., 4)),
30. `p-value` = signif(`p-value`, 3))
31. print(summary_models_price_eps)# A tibble: 2 × 6
Model Mẫu Slope Std.Err t `p-value`
<chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 Giá ~ EPS Full -1.04 4.32 -0.24 0.816
2 Giá ~ EPS Clean -1.34 4.60 -0.291 0.778
Nhận xét kĩ thuật
| Dòng | Giải thích kĩ thuật |
|---|---|
| 1–4 | Gọi các thư
việndplyr,ggplot2, broom(tóm tắt
mô hình hồi quy), scales(định dạng số liệu). |
| 5–10 | dùng conflict_prefer() để thực hiện
select, filter, rename,
summarise |
| 11–13 | Tạo tập dữ liệu mới d_price gồm ba biến
chính: Nam, Gia_DongCua_CuoiNam và
EPS. Sau đó (NA) bằng
filter(!is.na()) |
| 14 | Tạo tập dữ liệu d_clean bằng cách loại bỏ
năm 2019 |
| 15–16 | Xây dựng hai mô hình hồi quy tuyến tính bằng
lm()mẫu full và clean |
| 17–18 | Tính R²
summary(model)$r.squared |
| 19–21 | Dùng broom::tidy()để trích xuất kết quả
hồi quy (slope, std.error, p-value), gắn nhãn Model và
Mẫu (Full/Clean) bằng mutate(), thực hiện kết
hợp bảng bằng bind_rows(). |
| 22–28 | Lọc bỏ hệ số chặn (Intercept) |
| 29–30 | Làm tròn các giá trị số bằng
mutate(across()) và chuẩn hóa định dạng p-value với
signif() |
| 31 | In ra bảng kết quả |
Nhận xét
| Mẫu | Hệ số dốc (β) | R² | p-value | Diễn giải |
|---|---|---|---|---|
| Full (11 năm) | -1.04 | 0.006 | 0.816 | Không có ý nghĩa thống kê. Mối quan hệ gần như ngẫu nhiên. |
| Clean (10 năm) | -1.34 | 0.010 | 0.778 | Kết quả tương tự; loại bỏ 2019 không cải thiện đáng kể. |
Cả hai mô hình đều có R² rất thấp (<1%) và p-value > 0.7, chứng minh rằng biến động giá cổ phiếu GAS không phụ thuộc tuyến tính vào EPS kế toán
Biểu đồ tương quan giá và EPS
1. ggplot(d_price, aes(x = EPS, y = Gia_DongCua_CuoiNam)) +
2. annotate("rect", xmin = 3000, xmax = 8000, ymin = 20000, ymax = 75000,
3. fill = "grey95", alpha = 0.7) +
4. geom_point(aes(color = "Full"), size = 3, alpha = 0.9) +
5. geom_smooth(method = "lm", se = TRUE, color = "#1f77b4",
6. fill = alpha("#1f77b4", 0.15)) +
7. geom_smooth(data = d_clean, aes(x = EPS, y = Gia_DongCua_CuoiNam, color = "Clean"),
8. method = "lm", se = TRUE, linetype = "dashed",
9. fill = alpha("#d62728", 0.12)) +
10. annotate("text", x = min(d_price$EPS, na.rm=TRUE), y = max(d_price$Gia_DongCua_CuoiNam, na.rm=TRUE),
11. hjust = 0, vjust = 1.2, size = 3.5, color = "#1f77b4",
12. label = sprintf("R² Full = %.3f", r2_full)) +
13. annotate("text", x = min(d_price$EPS, na.rm=TRUE), y = max(d_price$Gia_DongCua_CuoiNam, na.rm=TRUE) - 3000,
14. hjust = 0, vjust = 1.2, size = 3.5, color = "#d62728",
15. label = sprintf("R² Clean = %.3f", r2_clean)) +
16. scale_x_continuous(labels = comma) +
17. scale_y_continuous(labels = comma) +
18. scale_color_manual(values = c("Full" = "#1f77b4", "Clean" = "#d62728"),
19. name = "Mẫu dữ liệu") +
20. labs(title = "Biểu đồ: Tương quan: Giá cổ phiếu ~ EPS (Full vs Clean)",
21. subtitle = "Đường liền: Full | Đường gạch: Clean (loại 2019)",
22. x = "EPS (VND/cp)", y = "Giá đóng cửa cuối năm (VND)") +
23. theme_minimal(base_size = 12) +
24. theme(legend.position = "bottom",
25. panel.grid.minor = element_blank(),
26. panel.grid.major.x = element_blank())
Nhận xét
Biểu đồ cho thấy mối tương quan giữa EPS và giá cổ phiếu của GAS gần
như không có, với hệ số xác định rất thấp (R² Full =
0.006, R² Clean = 0.010).
Cả hai đường hồi quy (Full – xanh, Clean – đỏ gạch)
đều gần như nằm ngang,
cho thấy EPS tăng không kéo theo giá cổ phiếu tăng.
Việc loại bỏ năm 2019 (outlier) không cải thiện đáng kể mô hình, chứng
minh rằng giá cổ phiếu GAS không bị chi phối bởi lợi nhuận kế
toán, mà có thể chịu ảnh hưởng mạnh từ yếu tố vĩ mô và
kỳ vọng thị trường.
1. library(dplyr)
2. library(ggplot2)
3. library(broom)
4. library(scales)
5. d_oper <- data %>%
6. dplyr::select(Nam, DoanhThu, LoiNhuanSauThue) %>%
7. dplyr::filter(!is.na(DoanhThu), !is.na(LoiNhuanSauThue))
8. d_oper_clean <- d_oper %>% dplyr::filter(Nam != 2019)
9. m_full <- lm(LoiNhuanSauThue ~ DoanhThu, data = d_oper)
10. m_clean <- lm(LoiNhuanSauThue ~ DoanhThu, data = d_oper_clean)
11. r2_full <- summary(m_full)$r.squared
12. r2_clean <- summary(m_clean)$r.squared
13. # Biểu đồ 2.3.4.d: Tương quan LNST ~ Doanh thu
14. ggplot(d_oper, aes(x = DoanhThu, y = LoiNhuanSauThue)) +
15. annotate("rect", xmin = 50000, xmax = 100000, ymin = 5000, ymax = 15000,
16. fill = "grey95", alpha = 0.6) +
17. geom_point(aes(color = "Full"), size = 3, alpha = 0.9) +
18. geom_smooth(method = "lm", se = TRUE, color = "#0072B2", fill = alpha("#0072B2", 0.15)) +
19. geom_smooth(data = d_oper_clean,
20. aes(x = DoanhThu, y = LoiNhuanSauThue, color = "Clean"),
21. method = "lm", se = TRUE, linetype = "dashed",
22. fill = alpha("#D55E00", 0.12)) +
23. annotate("text", x = 55000, y = 14500, label = sprintf("R² Full = %.3f", r2_full),
24. hjust = 0, size = 3.5, color = "#0072B2") +
25. annotate("text", x = 55000, y = 13500, label = sprintf("R² Clean = %.3f", r2_clean),
26. hjust = 0, size = 3.5, color = "#D55E00") +
27. scale_x_continuous(labels = label_number(big.mark = ",", suffix = " tỷ VND")) +
28. scale_y_continuous(labels = label_number(big.mark = ",", suffix = " tỷ VND")) +
29. scale_color_manual(values = c("Full" = "#0072B2", "Clean" = "#D55E00"),
30. name = "Mẫu dữ liệu") +
31. labs(title = "Biểu đồ: Tương quan: Lợi nhuận sau thuế ~ Doanh thu (Full vs Clean)",
32. subtitle = "Đường liền: Full | Đường gạch: Clean (loại 2019)",
33. x = "Doanh thu thuần (tỷ VND)",
34. y = "Lợi nhuận sau thuế (tỷ VND)") +
35. theme_minimal(base_size = 12) +
36. theme(legend.position = "bottom",
37. panel.grid.minor = element_blank(),
38. panel.grid.major.x = element_blank())Nhận xét kĩ thuật
Nhận xét
Quan sát cho thấy cả hai mô hình Full và Clen đều có độ dốc dương, nghĩa là khi doanh thu tăng thì lợi nhuận cũng tăng , tuy nhiên mức tương quan chỉ trung bình yếu, với R² Full = 0.298 và R² Clean = 0.317. Điều này chỉ ra rằng doanh thu chỉ giải thích được khoảng 30% biến động lợi nhuận, phần còn lại đến từ các yếu tố khác như giá dầu, chi phí vận hành, và chênh lệch tỷ giá. Mặc dù có xu hướng cùng chiều, LNST của GAS không tỷ lệ tuyến tính hoàn toàn với doanh thu, phản ánh đặc trưng của ngành khí - biên lợi nhuận phụ thuộc mạnh vào điều kiện thị trường hơn là quy mô doanh thu.
Kết quả củng cố nhận định rằng tăng trưởng quy mô (doanh thu) là động lực chính, còn biên lợi nhuận và đòn bẩy sẽ được giải thích sâu hơn trong phần 2.4 Phân tích DuPont.
Tổng hợp các phát hiện định lượng và trực quan hóa từ toàn bộ nhóm biến Hiệu suất & Tăng trưởng, bao gồm Doanh thu, Lợi nhuận, ROE, ROA, Biên lợi nhuận ròng, EPS và Tốc độ tăng trưởng YoY, nhằm khái quát hóa đặc trưng vận hành và năng lực sinh lời của Tổng công ty Khí Việt Nam (GAS) trong giai đoạn 2014–2024.
1. Nền tảng quy mô ổn định và sức chống chịu chu kỳ mạnh
→ Kết luận: Quy mô hoạt động của GAS có tính ổn định cấu trúc, đóng vai trò “vành đai hấp thụ rủi ro” trong chu kỳ giá năng lượng.
2. Biên lợi nhuận ròng cao và duy trì ổn định
Biên lợi nhuận ròng trung bình ≈ 13.0%, dao động chủ yếu trong khoảng 10–18%.
Phân phối có Skewness âm (-1.34) và Kurtosis cao (4.88), nghĩa là:
→ Kết luận: GAS duy trì khả năng kiểm soát chi phí và biên lợi nhuận hiệu quả; chỉ biến động mạnh trong các cú sốc dầu khí toàn cầu.
3. ROE duy trì mức cao, ROA ổn định – đòn bẩy tài chính an toàn
4. Mối quan hệ giữa Doanh thu và Lợi nhuận: tăng trưởng thực chất
→ Kết luận: Tăng trưởng doanh thu của GAS thực sự chuyển hóa thành lợi nhuận, nhưng biên lợi nhuận là nhân tố quyết định hiệu suất ròng.
5. Mối liên hệ Giá cổ phiếu – EPS yếu: thị trường phản ứng chậm
6. Tổng hợp
Tóm tắt phân tích
| Giai đoạn | Đặc trưng chính | Tác động tài chính |
|---|---|---|
| 2014–2016 | Suy giảm mạnh do khủng hoảng dầu khí | Biên LNR < 5%, ROE giảm, EPS thấp |
| 2017–2019 | Phục hồi và ổn định | Biên LNR ~13–15%, ROE ~20% |
| 2020 | Cú sốc COVID và giá dầu âm | Lợi nhuận gần 0, ROE thấp nhất |
| 2021–2024 | Phục hồi mạnh và tái ổn định | ROE, EPS và Biên LNR tăng trở lại |
Bảng tóm tắt ngắn gọn:
| Chỉ tiêu | Trung bình | Độ biến động | Xu hướng chính |
|---|---|---|---|
| Doanh thu | ~77 nghìn tỷ VND | Thấp | Ổn định, tăng chậm |
| LNST | ~10 nghìn tỷ VND | Trung bình | Nhạy với chu kỳ giá dầu |
| Biên LNR | ~13% | Thấp | Duy trì bền vững |
| ROE | ~20.6% | Thấp | Ổn định, đòn bẩy thấp |
| ROA | ~15.6% (median) | Cao (do 2019) | Hiệu quả tài sản cao |
| EPS | ~5,500 VND/cp | Thấp | Gắn chặt Biên LNR |
| R²(ROE~ROA) | 0.991 (clean) | – | Quan hệ tuyến tính mạnh |
| R²(LNST~DT) | 0.30 | – | Quan hệ dương, ổn định |
| R²(Giá~EPS) | 0.01 | – | Thị trường phản ứng yếu |
Mục tiêu của phần này là tách tỷ suất sinh lời trên vốn chủ sở hữu (ROE) thành ba yếu tố chính để xác định nguồn gốc tạo ra lợi nhuận của doanh nghiệp PV GAS:
\[ ROE = \text{NPM} \times \text{TAT} \times \text{FL} \]
Trong đó:
NPM: Biên lợi nhuận ròng (Net Profit Margin) dùng để đo hiệu quả kiểm soát chi phí và khả năng chuyển hóa doanh thu thành lợi nhuận ròng.
TAT: Hiệu suất sử dụng tài sản (Total Asset Turnover) sẽ phản ánh tốc độ quay vòng tài sản
FL: Đòn bẩy tài chính (Financial Leverage) cho biết mức khuếch đại lợi nhuận từ vốn chủ sở hữu.
Tóm tắt trung bình DuPont trung bình (2014–2024
1. library(dplyr)
2. library(tidyr)
3. library(ggplot2)
4. library(scales)
5. dupont_df <- data %>%
6. mutate(
7. BienLoiNhuanRong = BienLoiNhuanRong_Nam / 100,
8. TAT = TAT_Nam,
9. FL = FL_Nam,
10. ROE_DuPont = BienLoiNhuanRong * TAT * FL * 100
11. ) %>%
12. select(Nam, BienLoiNhuanRong, TAT, FL, ROE_DuPont, ROE_Nam)
13. dupont_summary <- dupont_df %>%
14. summarise(
15. Mean_NPM = mean(BienLoiNhuanRong, na.rm = TRUE) * 100,
16. Mean_TAT = mean(TAT, na.rm = TRUE),
17. Mean_FL = mean(FL, na.rm = TRUE),
18. Mean_ROE_ThucTe = mean(ROE_Nam, na.rm = TRUE),
19. Mean_ROE_DuPont = mean(ROE_DuPont, na.rm = TRUE)
20. )
21. print(dupont_summary) Mean_NPM Mean_TAT Mean_FL Mean_ROE_ThucTe Mean_ROE_DuPont
1 13 12 1.25 20.6 20.6
Nhận xét
| Chỉ tiêu | Giá trị trung bình | Ý nghĩa |
|---|---|---|
| Biên lợi nhuận ròng (NPM) | 13% | Doanh nghiệp duy trì biên lợi nhuận ổn định và cao trong ngành năng lượng. |
| Hiệu suất sử dụng tài sản (TAT) | 12% | Mỗi đồng tài sản tạo ra 0.12 đồng doanh thu, phản ánh hiệu quả tài sản ở mức khá. |
| Đòn bẩy tài chính (FL) | 1.25 lần | Mức đòn bẩy thấp, cấu trúc vốn an toàn, rủi ro tài chính nhỏ. |
| ROE thực tế (Mean) | 20.6% | Mức sinh lời cao, ổn định qua nhiều năm. |
| ROE tính theo DuPont | 20.6% | Khớp hoàn toàn với ROE thực tế → mô hình phản ánh đúng cấu trúc sinh lời. |
Biểu đồ 2.4.1.1: Cấu trúc ROE theo thời gian
1. dupont_long <- dupont_df %>%
2. select(Nam, BienLoiNhuanRong, TAT, FL) %>%
3. pivot_longer(cols = c(BienLoiNhuanRong, TAT, FL),
4. names_to = "ThànhPhan", values_to = "GiáTrị")
5. ggplot(dupont_long, aes(x = Nam, y = GiáTrị, fill = ThànhPhan)) +
6. geom_area(alpha = 0.8, color = "white", size = 0.4) +
7. scale_fill_manual(
8. values = c("BienLoiNhuanRong" = "#0072B2",
9. "TAT" = "#E69F00",
10. "FL" = "#56B4E9"),
11. labels = c("BienLoiNhuanRong" = "Biên lợi nhuận ròng (NPM)",
12. "TAT" = "Hiệu suất tài sản (TAT)",
13. "FL" = "Đòn bẩy tài chính (FL)")
14. ) +
15. labs(
16. title = "Cấu trúc ROE theo thời gian (2014–2024)",
17. subtitle = "ROE = Biên lợi nhuận ròng × Hiệu suất sử dụng tài sản × Đòn bẩy tài chính",
18. x = "Năm",
19. y = "Giá trị (hệ số)",
20. fill = "Thành phần"
21. ) +
22. theme_minimal(base_size = 10) +
23. theme(legend.position = "bottom",
24. plot.title = element_text(face = "bold", hjust = 0.5),
25. plot.subtitle = element_text(size = 9, hjust = 0.5))
Nhận xét
→ Có thể khẳng định: TAT và NPM là hai yếu tố chi phối ROE, trong khi FL giữ vai trò khuếch đại nhẹ
1. ggplot(dupont_df, aes(x = Nam)) +
2. geom_line(aes(y = ROE_Nam, color = "ROE thực tế"), linewidth = 1.2) +
3. geom_point(aes(y = ROE_Nam, color = "ROE thực tế"), size = 3) +
4. geom_line(aes(y = ROE_DuPont, color = "ROE tính theo DuPont"), linewidth = 1.2, linetype = "dashed") +
5. geom_point(aes(y = ROE_DuPont, color = "ROE tính theo DuPont"), size = 2) +
6. scale_color_manual(values = c("ROE thực tế" = "#D55E00", "ROE tính theo DuPont" = "#0072B2")) +
7. scale_y_continuous(labels = label_number(suffix = "%")) +
8. labs(
9. title = "So sánh ROE thực tế và ROE theo mô hình DuPont",
10. x = "Năm",
11. y = "Tỷ suất sinh lời (%)",
12. color = "Loại ROE"
13. ) +
14. theme_minimal(base_size = 12) +
15. theme(legend.position = "bottom",
16. plot.title = element_text(face = "bold", hjust = 0.5),
17. panel.grid.minor = element_blank())Nhận xét
Tổng hợp cấu trúc sinh lời của doanh nghiệp PV GAS
| Thành phần | Vai trò trong ROE | Đặc điểm tại GAS |
|---|---|---|
| NPM | Quyết định chất lượng lợi nhuận | Ổn định quanh 13%, cao so với trung bình ngành. |
| TAT | Phản ánh hiệu quả khai thác tài sản | Duy trì 0.12–0.15, cải thiện giai đoạn sau 2021. |
| FL | Khuếch đại lợi nhuận vốn chủ | Thấp (1.2–1.3) → GAS gần như không vay nợ nhiều. |
Cơ sở lý thuyết
Theo mô hình DuPont:
\[ ROE = NPM \times TAT \times FL \]
Ta có vi phân tương đối (độ nhạy tuyến tính):
\[ \frac{\Delta ROE}{ROE} = \frac{\Delta NPM}{NPM} + \frac{\Delta TAT}{TAT} + \frac{\Delta FL}{FL} \]
Suy ra, hệ số co giãn của ROE theo từng biến được tính bằng:
\[ E_{ROE,x} = \frac{\partial (ROE) / ROE}{\partial x / x} = \frac{x}{ROE} \times \frac{\partial (ROE)}{\partial x} \]
Do \(\frac{\partial ROE}{\partial NPM} = TAT \times FL\), ta có:
| Thành phần | Hệ số co giãn |
|---|---|
| \(E_{ROE,NPM} = \frac{NPM \times TAT \times FL}{ROE}\) | ≈ 1 |
| \(E_{ROE,TAT} = \frac{NPM \times TAT \times FL}{ROE}\) | ≈ 1 |
| \(E_{ROE,FL} = \frac{NPM \times TAT \times FL}{ROE}\) | ≈ 1 |
Trong mô hình tuyến tính hoàn hảo, tất cả các hệ số co giãn
đều bằng 1.
Tuy nhiên, trong dữ liệu thực tế, do phi tuyến và các hiệu ứng kế toán,
ta đo mức thay đổi ROE (%) khi từng biến tăng 1%, giữ
các biến khác cố định.
Mục tiêu
Phân tích độ nhạy nhằm xác định ROE của GAS nhạy cảm nhất với yếu tố nào trong ba thành phần của mô hình DuPont:
Từ đó, xác định nguồn gốc động lực sinh lời chủ yếu và mức độ bền vững của ROE.
1. library(dplyr)
2. library(ggplot2)
3. library(scales)
4. dupont_sens <- dupont_df %>%
5. mutate(
6. dNPM = (BienLoiNhuanRong * 1.01) * TAT * FL * 100,
7. dTAT = BienLoiNhuanRong * (TAT * 1.01) * FL * 100,
8. dFL = BienLoiNhuanRong * TAT * (FL * 1.01) * 100,
9. Sens_NPM = (dNPM - ROE_DuPont) / ROE_DuPont * 100,
10. Sens_TAT = (dTAT - ROE_DuPont) / ROE_DuPont * 100,
11. Sens_FL = (dFL - ROE_DuPont) / ROE_DuPont * 100
12. ) %>%
13. select(Nam, Sens_NPM, Sens_TAT, Sens_FL) %>%
14. pivot_longer(cols = starts_with("Sens_"),
15. names_to = "ThànhPhan", values_to = "ĐộNhạy") %>%
16. mutate(ThànhPhan = recode(ThànhPhan,
17. "Sens_NPM" = "Biên lợi nhuận ròng (NPM)",
18. "Sens_TAT" = "Hiệu suất tài sản (TAT)",
19. "Sens_FL" = "Đòn bẩy tài chính (FL)"))
20. ggplot(dupont_sens, aes(x = Nam, y = ĐộNhạy, color = ThànhPhan, group = ThànhPhan)) +
21. geom_line(linewidth = 1.2) +
22. geom_point(size = 2) +
23. geom_hline(yintercept = 1, color = "grey40", linetype = "dotted") +
24. scale_color_manual(values = c("#0072B2", "#E69F00", "#56B4E9")) +
25. scale_y_continuous(labels = label_percent(scale = 1)) +
26. labs(
27. title = "Độ nhạy của ROE theo mô hình DuPont",
28. subtitle = "Biểu diễn mức thay đổi (%) của ROE khi từng thành phần tăng 1%",
29. x = "Năm", y = "Độ nhạy (%)",
30. color = "Thành phần ảnh hưởng"
31. ) +
32. theme_minimal(base_size = 12) +
33. theme(legend.position = "bottom",
34. plot.title = element_text(face = "bold", hjust = 0.5))Nhận xét kĩ thuật
Dòng 4–12: dùng mutate() tạo hàm
tính các giá trị ROE giả định (dNPM, dTAT,
dFL) khi từng yếu tố tăng 1%, rồi tính độ nhạy
(%) bằng công thức
(dX - ROE_DuPont) / ROE_DuPont * 100.
Dòng 13–19: chọn các cột cần thiết bằng
select(), chuyển dữ liệu sang dạng dài
pivot_longer() , và đổi tên biến
recode().
Dòng 20–25 (ggplot(),
geom_line(), geom_point(),
geom_hline()): vẽ biểu đồ đường biểu diễn độ nhạy
của từng yếu tố qua các năm, thêm đường tham chiếu 1%
để dễ so sánh.
Dòng 24 (scale_color_manual()) & 25
(scale_y_continuous()): thiết lập màu sắc cho từng
yếu tố và định dạng trục Y hiển thị phần trăm
(label_percent).
Dòng 26–34 (labs(),
theme_minimal(), theme()): đặt tiêu
đề, nhãn và tùy chỉnh bố cục hiển thị của biểu đồ.
Kết quả mô phỏng độ nhạy
| Thành phần | Độ nhạy trung bình (E) | Diễn giải |
|---|---|---|
| NPM (Biên lợi nhuận ròng) | ≈ 1.00 | Tăng 1% NPM → ROE tăng 1% |
| TAT (Hiệu suất tài sản) | ≈ 1.00 | Tăng 1% TAT → ROE tăng 1% |
| FL (Đòn bẩy tài chính) | ≈ 1.00 | Tăng 1% FL → ROE tăng 1% |
Kết quả cho thấy ba đường (NPM, TAT, FL) trùng nhau ở mức 1%, chứng tỏ ROE của GAS biến động tuyến tính hoàn hảo theo từng yếu tố trong mô hình DuPont. Mặc dù độ nhạy tương đối bằng nhau (1:1), tác động thực tế khác nhau do giá trị nền của từng yếu tố khác nhau:
NPM (~13%) có ảnh hưởng lớn nhất đến ROE, phản ánh hiệu quả kiểm soát chi phí và biến động giá dầu/khí.
TAT (~0.12) có tác động nhỏ hơn do vòng quay tài sản chậm
FL (~1.25) ổn định, cho thấy GAS ít sử dụng nợ vay và duy trì cấu trúc vốn an toàn.
1. Mục tiêu
Phân tích và trực quan hóa tác động kết hợp giữa Biên lợi nhuận ròng (NPM) và Hiệu suất sử dụng tài sản (TAT) đến tỷ suất sinh lời trên vốn chủ (ROE) theo mô hình DuPont. Từ đó xác định vùng sinh lời tối ưu, và đánh giá mức độ phụ thuộc lẫn nhau giữa hai yếu tố vận hành cốt lõi.
2. Cơ sở lý thuyết
Theo mô hình DuPont rút gọn (vì FL gần như ổn định):
\[ ROE = NPM \times TAT \times FL \]
Với giá trị trung bình \(FL = 1.25\) (giai đoạn 2014–2024), công thức trở thành:
\[ ROE = 1.25 \times NPM \times TAT \]
Từ đó, mô phỏng ROE theo các mức kết hợp khác nhau của NPM và TAT nhằm đánh giá:
1. library(ggplot2)
2. library(dplyr)
3. library(scales)
4. npm_seq <- seq(0.05, 0.25, by = 0.005) # 5% → 25%
5. tat_seq <- seq(0.05, 0.25, by = 0.005) # 0.05 → 0.25
6. fl_fixed <- 1.25
7. heat_df <- expand.grid(NPM = npm_seq, TAT = tat_seq) %>%
8. mutate(ROE = NPM * TAT * fl_fixed)
9. ggplot(heat_df, aes(x = NPM, y = TAT, fill = ROE)) +
10. geom_tile() +
11. geom_contour(aes(z = ROE), color = "white", linewidth = 0.3) +
12. scale_fill_gradient(low = "#f7fbff", high = "#08306b", labels = label_percent(accuracy = 1)) +
13. labs(
14. title = "Mô phỏng tác động đồng thời của NPM và TAT lên ROE",
15. subtitle = "Mô hình DuPont (FL cố định = 1.25) | ROE = NPM × TAT × FL",
16. x = "Biên lợi nhuận ròng (NPM)",
17. y = "Hiệu suất sử dụng tài sản (TAT)",
18. fill = "ROE (%)"
19. ) +
20. theme_minimal(base_size = 9) +
21. theme(
22. legend.position = "right",
23. plot.title = element_text(face = "bold", hjust = 0.5),
24. plot.subtitle = element_text(size = 7)
25. )Nhận xét kĩ thuật
Dòng 1-3: tải các gói dữ liệu cần thiết cho biểu đồ ( đã phân tích trên)
Dòng 4–6: dùng seq() & gán biến
tạo dãy giá trị cho NPM và TAT trong khoảng 0.05–0.25 (tức 5–25%), và cố
định FL = 1.25.
Dòng 7–8: tạo kết hợp giữa NPM và TAT bằng
expand.grid(), rồidùng mutate()tính
ROE = NPM × TAT × FL cho từng điểm.
Dòng 9–11: dùng geom_tile() tạo bản
đồ nhiệt (heatmap) thể hiện cường độ ROE theo màu sắc,
geom_contour() thêm các đường đồng mức ROE
Dòng 12 (): chỉnh thang màu từ nhạt (ROE thấp)
đến đậm (ROE cao) bằng scale_fill_gradient()
Dòng 13–19: dùng labs() đặt tiêu
đề, phụ đề, nhãn trục và ghi chú thang màu, nêu công thức chú
thích.
Dòng 20–25: dùng theme_minimal()làm
gọn giao diện, căn giữa tiêu đề và bố trí chú thích ở bên phải.
Nhận xét
| Thành phần | Ảnh hưởng đến ROE | Giải thích chi tiết |
|---|---|---|
| NPM – Biên lợi nhuận ròng | Tác động mạnh nhất | Khi NPM tăng, mỗi đồng doanh thu tạo ra nhiều lợi nhuận hơn → ROE tăng nhanh. |
| TAT – Hiệu suất sử dụng tài sản | Tác động khuếch đại | Khi TAT cao, tài sản quay vòng nhanh hơn → cùng biên lợi nhuận, ROE vẫn cao hơn. |
| FL – Đòn bẩy tài chính | Ổn định, đóng vai trò cố định | FL cố định 1.25 giúp ROE phản ánh đúng hiệu quả nội tại thay vì bị khuếch đại bởi nợ vay. |
Tóm lại: Mô hình mô phỏng xác nhận ROE của GAS phụ thuộc đồng thời và tuyến tính vào NPM và TAT.Vùng hiệu quả cao (ROE > 6%) đạt được khi NPM > 20% và TAT > 0.20,thể hiện khả năng sinh lời bền vững của GAS từ hiệu quả vận hành chứ không từ rủi ro tài chính.
Kiểm định và đánh giá mối quan hệ tuyến tính giữa Biên lợi nhuận ròng (NPM) và Tỷ suất sinh lời trên tài sản (ROA). Mục tiêu là xác định xem ROA có phản ánh trực tiếp khả năng sinh lợi ròng, hay chịu ảnh hưởng mạnh của yếu tố khác như cơ cấu tài sản hoặc chi phí vốn.
1. library(dplyr)
2. library(ggplot2)
3. library(broom)
4. library(scales)
5. dupont_df <- data %>%
6. transmute(
7. Nam,
8. NPM = BienLoiNhuanRong_Nam / 100,
9. TAT = TAT_Nam,
10. FL = FL_Nam,
11. ROA = ROA_Nam / 100,
12. ROE_ThucTe = ROE_Nam / 100
13. ) %>%
14. mutate(
15. ROE_DuPont = NPM * TAT * FL
16. )1. d_profit <- dupont_df %>% dplyr::select(Nam, NPM, ROA)
2. d_profit_clean <- d_profit %>% filter(Nam != 2019)
3. lm_full <- lm(NPM ~ ROA, data = d_profit)
4. lm_clean <- lm(NPM ~ ROA, data = d_profit_clean)
5. res_full <- summary(lm_full)
6. res_clean <- summary(lm_clean)
7. result_table_242 <- tibble::tibble(
8. Mẫu = c("Full", "Clean"),
9. n = c(nrow(d_profit), nrow(d_profit_clean)),
10. R2 = c(res_full$r.squared, res_clean$r.squared),
11. Adj_R2 = c(res_full$adj.r.squared, res_clean$adj.r.squared),
12. Slope = c(coef(lm_full)[2], coef(lm_clean)[2]),
13. `p-value(Slope)` = c(res_full$coefficients[2,4], res_clean$coefficients[2,4]),
14. Intercept= c(coef(lm_full)[1], coef(lm_clean)[1])
15. )
16. print(result_table_242)# A tibble: 2 × 7
Mẫu n R2 Adj_R2 Slope `p-value(Slope)` Intercept
<chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Full 11 0.0525 -0.0528 0.00184 0.498 0.127
2 Clean 10 0.930 0.921 0.718 0.00000670 0.0218
Nhận xét kĩ thuật
Dòng 1–2 : dùng select() chọn
NPM và ROA từ bộ dupont_dftạo ở
bước chuẩn hóa dữ liệu, dùng filter() 2019 khỏi mẫu
“Clean”
Dòng 3–4 (lm()): xây dựng hai mô
hình hồi quy tuyến tính NPM ~ ROA cho mẫu Full và
Clean
Dòng 5–6: dùng summary() để tổng
hợp R², Adj R², hệ số góc
(Slope) và p-value.
Dòng 7–15: tính các giá trị và tổng hợp kết quả
của hai mô hình vào bảng result_table_242
Dòng 16 (print()): in bảng kết quả
so sánh giữa hai mô hình.
Kết quả mô hình:
| Mẫu | n | R² | Adj-R² | Slope | p-value(Slope) | Intercept |
|---|---|---|---|---|---|---|
| Full | 11 | 0.0525 | -0.0528 | 0.00184 | 0.4979 | 0.1267 |
| Clean | 10 | 0.9302 | 0.9214 | 0.7176 | 0.000067 | 0.0218 |
Nhận xét chi tiết
Bảng tổng kết
| Nhận xét | Diễn giải |
|---|---|
| Mối quan hệ | Tuyến tính, chặt chẽ và có ý nghĩa thống kê cao trong mẫu Clean |
| Hệ số dốc (Slope) | 0.72 → ROA tăng 1% → NPM tăng 0.72% |
| Ý nghĩa | NPM phản ánh gần như trực tiếp hiệu quả hoạt động (ROA) của doanh nghiệp |
| Kết luận | Sau khi loại bỏ năm 2019, mô hình trở nên ổn định và phù hợp, khẳng định ROA là yếu tố quyết định biên lợi nhuận ròng của PVGas |
1. ggplot() +
2. geom_point(data = d_profit,
3. aes(x = ROA, y = NPM),
4. size = 3, alpha = 0.85, color = "#264C99") +
5. geom_smooth(data = d_profit,
6. aes(x = ROA, y = NPM),
7. method = "lm", se = TRUE,
8. color = "#264C99", fill = "#264C99",
9. alpha = 0.15, linewidth = 1) +
10. geom_smooth(data = d_profit_clean,
11. aes(x = ROA, y = NPM),
12. method = "lm", se = TRUE,
13. linetype = "dashed",
14. color = "#D55E00", fill = "#D55E00",
15. alpha = 0.15, linewidth = 1) +
16. geom_abline(slope = 1, intercept = 0, linetype = "dotted", color = "grey40") +
17. annotate("text", x = min(d_profit$ROA, na.rm=TRUE),
18. y = max(d_profit$NPM, na.rm=TRUE),
19. hjust = 0, vjust = 1.2,
20. label = paste0("R² Full = ", round(res_full$r.squared, 3)),
21. color = "#264C99", fontface = "bold") +
22. annotate("text", x = min(d_profit$ROA, na.rm=TRUE),
23. y = max(d_profit$NPM, na.rm=TRUE) - 0.03,
24. hjust = 0, vjust = 1.2,
25. label = paste0("R² Clean = ", round(res_clean$r.squared, 3)),
26. color = "#D55E00", fontface = "bold") +
27. {
28. if (any(d_profit$Nam == 2019)) {
29. annotate("text",
30. x = d_profit$ROA[d_profit$Nam == 2019],
31. y = d_profit$NPM[d_profit$Nam == 2019] + 0.02,
32. label = "2019", color = "red", fontface = "bold")
33. }
34. } +
35. scale_x_continuous(labels = label_percent(accuracy = 1)) +
36. scale_y_continuous(labels = label_percent(accuracy = 1)) +
37. labs(
38. title = "Tương quan biên lợi nhuận ròng (NPM) ~ ROA (Full vs Clean)",
39. subtitle = "Đường liền: Full | Đường gạch: Clean (loại 2019) | Đường chấm: y = x",
40. x = "ROA (%)", y = "Biên lợi nhuận ròng (NPM, %)"
41. ) +
42. theme_minimal(base_size = 10) +
43. theme(plot.title = element_text(face = "bold", hjust = 0.5),
44. panel.grid.minor = element_blank())Kết luận từ biểu đồ:
Biểu đồ cho thấy mối liên hệ tăng đồng giữa biên lợi nhuận ròng (NPM) và hiệu suất sử dụng tài sản (ROA), nghĩa là sau khi đã loại bỏ năm có giá trị bất thường (2019) thì khi ROA tăng sẽ kéo NPM tăng tương ứng (đường màu xanh trên hình), điều đó phản ánh hiệu quả hoạt động được duy trì ổn định.
| Mẫu | Đặc điểm | Ý nghĩa |
|---|---|---|
| Full | Đường phẳng, R² = 0.05 | Mối quan hệ yếu, bị nhiễu bởi outlier (2019) |
| Clean | Đường dốc tăng mạnh, R² = 0.93 | Mối quan hệ chặt chẽ, phản ánh đúng hiệu quả hoạt động nội tại |
| Điểm 2019 | Lệch xa cụm chính | Biểu hiện của biến động bất thường (không thuộc xu hướng chung) |
1. df_temp <- data %>%
2. mutate(
3. P_E_CuoiNam = Gia_DongCua_CuoiNam / EPS,
4. VonHoa_TyVND = (Gia_DongCua_CuoiNam * SL_CoPhieu_LuuHanh) / 1e9,
5. ROE_Nam = (LoiNhuanSauThue / VonChuSoHuu) * 100,
6. ROA_Nam = (LoiNhuanSauThue / TongTaiSan) * 100,
7. BienLoiNhuanRong_Nam = (LoiNhuanSauThue / DoanhThu) * 100,
8. FL_Nam = TongTaiSan / VonChuSoHuu,
9. TAT_Nam = DoanhThu / TongTaiSan,
10. flag_roa_abnormal = dplyr::case_when(ROA_Nam > 100 ~ TRUE, TRUE ~ FALSE)
11. )
12. df_clean <- df_temp %>%
13. dplyr::filter(flag_roa_abnormal == FALSE)
14. # A. Chọn các biến cần thiết cho ma trận tương quan (Hiệu suất & Định giá)
15. vars_raw <- df_clean %>%
16. select(ROE_Nam, ROA_Nam, BienLoiNhuanRong_Nam, TAT_Nam, FL_Nam, EPS, P_E_CuoiNam)
17. vars_corr <- vars_raw %>%
18. rename(
19. ROE = ROE_Nam,
20. ROA = ROA_Nam,
21. `Biên LNR` = BienLoiNhuanRong_Nam,
22. `Hiệu suất TS` = TAT_Nam,
23. `Đòn bẩy TC` = FL_Nam,
24. PE = P_E_CuoiNam
25. )
26. vars_short_names <- vars_corr %>%
27. rename(
28. NPM = `Biên LNR`,
29. TAT = `Hiệu suất TS`,
30. FL = `Đòn bẩy TC`
31. )
32. corr_matrix_short <- round(cor(vars_short_names, use = "pairwise.complete.obs"), 3)
33. corr_long <- reshape2::melt(corr_matrix_short)
34. ggplot(corr_long, aes(x = Var1, y = Var2, fill = value)) +
35. geom_tile(color = "white") +
36. geom_text(aes(label = sprintf("%.2f", value)), size = 3.5, color = "black") +
37. scale_fill_gradient2(low = "#B2182B", mid = "white", high = "#2166AC",
38. midpoint = 0, limit = c(-1, 1),
39. name = "Hệ số\nTương quan") +
40. labs(
41. title = "Ma trận tương quan giữa các chỉ tiêu tài chính",
42. subtitle = "Mẫu đã lọc Outlier (n=10)",
43. x = NULL, y = NULL
44. ) +
45. theme_minimal(base_size = 10) +
46. theme(
47. axis.text.x = element_text(angle = 45, hjust = 1, size = 10),
48. axis.text.y = element_text(size = 10),
49. plot.title = element_text(face = "bold", hjust = 0.5),
50. legend.position = "right"
51. )Giải thích kĩ thuật
Dòng 1–11: Sử dụng mutate() để tính
toán P_E_CuoiNam, ROE_Nam,
ROA_Nam, BienLoiNhuanRong_Nam,
FL_Nam, TAT_Nam và dùng
flag_roa_abnormal đánh dấu các giá trị ROA bất thường (ROA
> 100%).
Dòng 12–13: Dùng filter() loại bỏ
các dòng bị gắn cờ, tạo bộ dữ liệu df_clean
Dòng 15–16: dùng seclect() chọn các
biến (ROE, ROA, Biên LNR,
TAT, FL, EPS,
P/E).
Dòng 17–31: dùngrename() để biến
đổi tên các biến
Dòng 32–33: Tính ma trận tương quan Pearson bằng
cor() (sử dụng pairwise.complete.obs để bỏ qua
NA) và chuyển kết quả sang dạng dài (melt())
Dòng 34–51: Dùng ggplot() để vẽ
biểu đồ ma trận tương quan, geom_tile() tô
màu theo mức độ tương quan, geom_text() hiển thị hệ số
tương quan trực tiếp, scale_fill_gradient2() thiết lập
thang đo màu
Nhận xét
ROA, ROE và NPM có mức tương quan gần
như tuyệt đối (r ≈ 0.96–1.00) → cho thấy hiệu quả hoạt
động nội tại là nhân tố quyết định trực tiếp lợi nhuận ròng và tỷ suất
sinh lời vốn chủ.
→ Điều này củng cố kết quả các hồi quy trước (ROE ~ ROA, NPM ~ ROA) rằng
cấu trúc sinh lời của PVGas chủ yếu đến từ hoạt động kinh doanh
cốt lõi, không phụ thuộc vào đòn bẩy.
TAT (Hiệu suất tài sản) có tương quan
trung bình đến mạnh với ROA và ROE (r ≈
0.71–0.73), nghĩa là khả năng quay vòng tài sản
đóng vai trò tích cực trong việc nâng cao lợi nhuận.
→ Tuy nhiên, hệ số < 1 cho thấy ngoài hiệu suất tài sản, biên
lợi nhuận ròng (NPM) vẫn là yếu tố chi phối chính của
ROA.
FL (Đòn bẩy tài chính) có tương quan yếu – trung bình (r ≈ 0.34–0.42) với ROA và ROE, chứng tỏ đòn bẩy không phải yếu tố chính tạo ra lợi nhuận, phù hợp với đặc điểm của PVGas – doanh nghiệp có vốn chủ sở hữu lớn và nợ vay thấp.
1. GGally::ggpairs(
2. vars_corr,
3. title = "Biểu đồ 2.4.3b: Ma trận giữa các biến hiệu suất và định giá",
4. upper = list(continuous = GGally::wrap("cor", size = 3.5, color = "darkred")),
5. lower = list(continuous = GGally::wrap("points", alpha = 0.6, size = 1.5, color = "#0072B2")),
6. diag = list(continuous = GGally::wrap("densityDiag", fill = "#56B4E9", alpha = 0.6))
7. ) +
8. theme_bw(base_size = 8) +
9. theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 12))Nhận xét kĩ thuật
Dòng 1–2: Gọi hàm GGally::ggpairs()
trên bộ dữ liệu vars_corr. Sủ dụng hàm
GGally vì đây là hàm mở rộng của ggplot2 tạo biểu đồ ma
trận nhìn thấy được phân tán
Dòng 4: Phần upper quy định vùng
tam giác trên của ma trận hiển thị giá trị
tương quan (correlation) bằng GGally::wrap("cor"),
với kích thước chữ (size = 3.5) và màu chữ đỏ
(color = "darkred").
Dòng 5: Phần lower hiển thị biểu đồ
phân tán giữa các cặp biến. Các điểm được làm mờ
(alpha = 0.6), kích thước nhỏ (size = 1.5) và
có màu xanh dương nhẹ (#0072B2)
Dòng 6: Dùng diag hiển thị
phân phối mật độ (density plot) của từng biến
Nhận xét
EPS có tương quan tương đối cao với nhóm hiệu suất (r ≈ 0.66–0.67 với ROA, ROE, TAT) → phản ánh lợi nhuận kế toán di chuyển cùng chiều với hiệu quả hoạt động. Tuy nhiên, mức tương quan chưa quá mạnh, cho thấy thị trường chưa phản ánh đầy đủ hiệu quả hoạt động vào EPS.
P/E có tương quan âm khá rõ với ROA, ROE, EPS (r ≈ -0.57 đến -0.59) → khi hiệu quả sinh lời tăng, P/E có xu hướng giảm, nghĩa là cổ phiếu được định giá rẻ hơn tương đối so với lợi nhuận tạo ra
Bảng tổng hợp nhận xét ma trận tương quan qua hai biểu đồ
| Nhóm chỉ tiêu | Tương quan nội bộ | Tương quan với P/E | Nhận định chính |
|---|---|---|---|
| ROA – ROE – NPM | R ≈ 0.96–1.00 | Âm (≈ -0.57) | Hiệu suất nội tại cao, phản ánh cùng chiều với nhau; P/E giảm khi hiệu quả tăng. |
| TAT (Hiệu suất tài sản) | Trung bình – mạnh (≈ 0.7) | Âm nhẹ (≈ -0.38) | Quay vòng tài sản cao giúp tăng sinh lời, nhưng không ảnh hưởng trực tiếp đến định giá. |
| FL (Đòn bẩy tài chính) | Yếu (≈ 0.34- 0.42) | Gần như không đáng kể | Đòn bẩy thấp, không đóng vai trò chính trong sinh lời hay định giá. |
| EPS | Dương với hiệu suất (≈ 0.66–0.67) | Âm với P/E (≈ -0.59) | Lợi nhuận kế toán tăng cùng hiệu quả hoạt động, nhưng thị trường chưa phản ánh tương xứng. |
1. library(tidyverse)
2. library(ggplot2)
3. library(broom)
4. library(scales)
5. analysis_data <- data %>%
6. arrange(Nam) %>%
7. mutate(
8. P_E_CuoiNam = Gia_DongCua_CuoiNam / EPS,
9. ROE_Nam = (LoiNhuanSauThue / VonChuSoHuu) * 100,
10. LNST_YoY = (LoiNhuanSauThue / dplyr::lag(LoiNhuanSauThue) - 1) * 100,
11. Gia = Gia_DongCua_CuoiNam,
12. ROE = ROE_Nam,
13. PE = P_E_CuoiNam
14. )
15. ggplot(analysis_data, aes(x = Nam, y = EPS)) +
16. geom_line(linewidth = 1.2, color = "#0072B2") +
17. geom_point(size = 3, color = "#0072B2") +
18. geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = "grey40") +
19. labs(
20. title = "Xu hướng EPS qua các năm",
21. x = "Năm", y = "EPS (đồng/cp)"
22. ) +
23. theme_minimal(base_size = 13) +
24. theme(plot.title = element_text(face = "bold", hjust = 0.5))Nhận xét
Xây dựng tuyến tính Giá cổ phiếu ~ EPS (Full & Clean)
1. lm_eps_full <- lm(Gia ~ EPS, data = analysis_data)
2. analysis_data_clean <- analysis_data %>% filter(Nam != 2019)
3. lm_eps_clean <- lm(Gia ~ EPS, data = analysis_data_clean)
4. result_eps <- tibble(
5. Mẫu = c("Full", "Clean"),
6. R2 = c(summary(lm_eps_full)$r.squared, summary(lm_eps_clean)$r.squared),
7. Adj_R2 = c(summary(lm_eps_full)$adj.r.squared, summary(lm_eps_clean)$adj.r.squared),
8. Slope = c(coef(lm_eps_full)[2], coef(lm_eps_clean)[2]),
9. p_value = c(summary(lm_eps_full)$coefficients[2,4], summary(lm_eps_clean)$coefficients[2,4]),
10. Intercept = c(coef(lm_eps_full)[1], coef(lm_eps_clean)[1])
11. )
12. print(result_eps)# A tibble: 2 × 6
Mẫu R2 Adj_R2 Slope p_value Intercept
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Full 0.00636 -0.104 -1.04 0.816 57749.
2 Clean 0.0105 -0.113 -1.34 0.778 58712.
Nhận xét kĩ thuật
dòng 1 xây dựng hai mô hình hồi quy đầy đủ có
năm 2019 của Gia ~ EPS bằng lm()
(dòng 2): dùng filter() loại bỏ năm
2019 khỏi dữ liệu (analysis_data_clean) để tạo bộ mẫu
“Clean”.
dòng 3 xây dựng hai mô hình hồi quy mẫu Clean
của Gia ~ EPS bằng `lm()
(dòng 6–10): dùng summary() để tổng
quan các chỉ số thống kê của mô hình như r.squared,
adj.r.squared, coefficients và
p-value, đồng thời coef()lấy hệ số góc (Slope)
và hệ số chặn (Intercept) từ mô hình
Phần này 2.4.4. sẽ không thực hiện lại giải thích kĩ thuật ở các biểu đồ vì đã được thực hiện tương tự như các biểu hồi quy tuyên tính được thực hiện các phần trên
Trực quan mối quan hệ giá cổ phiếu ~ EPS
1. ggplot() +
2. geom_point(data = analysis_data, aes(x = EPS, y = Gia), color = "#0072B2", size = 3, alpha = 0.8) +
3. geom_smooth(data = analysis_data, aes(x = EPS, y = Gia), method = "lm", color = "#0072B2", se = TRUE, fill = "#0072B2", alpha = 0.15) +
4. geom_smooth(data = analysis_data_clean, aes(x = EPS, y = Gia), method = "lm", color = "#D55E00", se = TRUE, fill = "#D55E00", alpha = 0.15, linetype = "dashed") +
5. labs(
6. title = "Mối quan hệ giá cổ phiếu ~ EPS (Full vs Clean)",
7. x = "EPS (đồng/cp)",
8. y = "Giá cổ phiếu (đồng)"
9. ) +
10. theme_minimal(base_size = 13) +
11. theme(plot.title = element_text(face = "bold", hjust = 0.5))Nhận xét
Đường hồi quy Full và Clean gần như nằm ngang, với hệ số R² rất thấp (< 0.01), cho thấy không tồn tại mối quan hệ tuyến tính đáng kể giữa giá cổ phiếu và EPS
Độ dốc (Slope) âm nhẹ → khi EPS tăng, giá cổ phiếu không tăng tương ứng, thậm chí có xu hướng giảm nhẹ.
→ Giá cổ phiếu GAS không phản ứng với biến động EPS ngắn hạn, mà phản ánh kỳ vọng thị trường dài hạn, cổ tức và yếu tố vĩ mô.
Xây dựng tuyến tính ROE ~ P/E
Call:
lm(formula = ROE ~ PE, data = analysis_data)
Residuals:
Min 1Q Median 3Q Max
-13.99 -2.98 2.49 3.10 11.15
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 32.888 6.315 5.21 0.00056 ***
PE -1.234 0.593 -2.08 0.06730 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 7.57 on 9 degrees of freedom
Multiple R-squared: 0.325, Adjusted R-squared: 0.25
F-statistic: 4.33 on 1 and 9 DF, p-value: 0.0673
Trực quan mối quan hệ ROE ~ P/E
1. ggplot(analysis_data, aes(x = PE, y = ROE)) +
2. geom_point(size = 3, color = "#009E73", alpha = 0.8) +
3. geom_smooth(method = "lm", se = TRUE, color = "#009E73", fill = "#009E73", alpha = 0.2) +
4. scale_y_continuous(labels = label_percent(scale = 1)) +
5. labs(
6. title = "Mối quan hệ ROE ~ P/E",
7. x = "Hệ số P/E",
8. y = "ROE (%)"
9. ) +
10. theme_minimal(base_size = 13) +
11. theme(plot.title = element_text(face = "bold", hjust = 0.5))Nhận xét
Biểu đồ cho thấy mối tương quan âm giữa ROE và P/E, Khi ROE (tỷ suất sinh lời vốn chủ) cao, P/E có xu hướng thấp hơn, và ngược lại. Điều này có thể là: nhà đầu tư có xu hướng định giá thấp hơn (P/E thấp) với các doanh nghiệp đã đạt mức sinh lời cao, vì tốc độ tăng trưởng tương lai dự kiến chậm lại. Ngược lại, doanh nghiệp có ROE thấp thường được kỳ vọng tăng trưởng cao hơn, nên được định giá P/E cao hơn.
Xây dựng tuyến tính giữa PE ~ LNST_YoY
Call:
lm(formula = PE ~ LNST_YoY, data = analysis_data)
Residuals:
Min 1Q Median 3Q Max
-5.714 -1.230 -0.135 2.620 4.773
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 10.00864 1.25286 7.99 0.000044 ***
LNST_YoY 0.00452 0.00389 1.16 0.28
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 3.78 on 8 degrees of freedom
(1 observation deleted due to missingness)
Multiple R-squared: 0.144, Adjusted R-squared: 0.0373
F-statistic: 1.35 on 1 and 8 DF, p-value: 0.279
Trực quan mối quan hệ P/E ~ Tăng trưởng LNST (YoY)
1. ggplot(analysis_data, aes(x = LNST_YoY, y = PE)) +
2. geom_point(size = 3, color = "#E69F00", alpha = 0.8) +
3. geom_smooth(method = "lm", se = TRUE, color = "#E69F00", fill = "#E69F00", alpha = 0.2) +
4. labs(
5. title = "Mối quan hệ P/E ~ Tăng trưởng LNST (YoY)",
6. x = "Tăng trưởng LNST YoY (%)",
7. y = "Hệ số P/E"
8. ) +
9. theme_minimal(base_size = 13) +
10. theme(plot.title = element_text(face = "bold", hjust = 0.5))*Nhận xét**
Mối quan hệ giữa P/E và tăng trưởng lợi nhuận (YoY) có sự cùng chiều nhẹ, với R²= 0.144 (≈ 14.4), nghĩa là biến Tăng trưởng LNST (YoY) chỉ giải thích được khoảng 14.4% sự biến động của chỉ số P/E.
Mối quan hệ này cho thấy thị trường phản ứng chọn lọc với tăng trưởng, tức là chỉ định giá cao hơn khi tăng trưởng được xem là bền vững, còn các năm đột biến ngắn hạn ít ảnh hưởng đến P/E.
→ Như vậy, tác động của tăng trưởng LNST tới định giá P/E là có, nhưng không ổn định và mang tính kỳ vọng.
Tổng kết nhóm biểu đồ 2.4.4
| Biểu đồ | Mối quan hệ | Kết luận chính |
|---|---|---|
| 2.4.4.1– EPS theo năm | Biến động chu kỳ, xu hướng giảm nhẹ | EPS không ổn định, chịu ảnh hưởng yếu tố bên ngoài |
| 2.4.4.2– Giá ~ EPS | Gần như không có (Slope âm nhẹ) | Giá cổ phiếu không phản ứng với EPS ngắn hạn |
| 2.4.4.3– ROE ~ P/E | Tương quan âm | P/E thấp khi ROE cao → thị trường định giá ngược chu kỳ |
| 2.4.4.4– P/E ~ Tăng trưởng LNST (YoY) | Tương quan dương yếu | P/E tăng khi tăng trưởng lợi nhuận cao, nhưng không ổn định |
1. Hiệu suất sinh lời (ROE, ROA, NPM, TAT, FL)
2. Quan hệ giữa ROA và NPM
3. Tương quan đa biến (Hiệu suất & Định giá)
4. EPS, tăng trưởng và định giá thị trường
1. library(tidyverse)
2. library(ggplot2)
3. library(zoo)
4. library(scales)
5. df_roll <- data %>%
6. rename(
7. LNST = LoiNhuanSauThue,
8. Gia = Gia_DongCua_CuoiNam,
9. ROE = ROE_Nam
10. ) %>%
11. arrange(Nam)
12. roll_corr_LNST_DT <- df_roll %>%
13. mutate(Roll_Corr_LNST_DT = rollapplyr(
14. data = cbind(LNST, DoanhThu),
15. width = 3,
16. FUN = function(x) cor(x[,1], x[,2], use = "complete.obs"),
17. by.column = FALSE,
18. fill = NA
19. ))
20. roll_corr_ROE_Gia <- df_roll %>%
21. mutate(Roll_Corr_ROE_Gia = rollapplyr(
22. data = cbind(ROE, Gia),
23. width = 3,
24. FUN = function(x) cor(x[,1], x[,2], use = "complete.obs"),
25. by.column = FALSE,
26. fill = NA
27. ))
28. roll_corr_all <- df_roll %>%
29. select(Nam) %>%
30. left_join(roll_corr_LNST_DT %>% select(Nam, Roll_Corr_LNST_DT), by = "Nam") %>%
31. left_join(roll_corr_ROE_Gia %>% select(Nam, Roll_Corr_ROE_Gia), by = "Nam") %>%
32. pivot_longer(cols = starts_with("Roll_Corr"), names_to = "MốiQuanHe", values_to = "Corr") %>%
33. mutate(
34. MốiQuanHe = recode(MốiQuanHe,
35. "Roll_Corr_LNST_DT" = "LNST ~ Doanh thu",
36. "Roll_Corr_ROE_Gia" = "ROE ~ Giá cổ phiếu")
37. )
38. ggplot(roll_corr_all, aes(x = Nam, y = Corr, color = MốiQuanHe, group = MốiQuanHe)) +
39. geom_line(linewidth = 1.2) +
40. geom_point(size = 2.5) +
41. geom_hline(yintercept = 0, linetype = "dashed", color = "grey40") +
42. scale_color_manual(values = c("#0072B2", "#D55E00")) +
43. scale_y_continuous(labels = label_number(accuracy = 0.1), limits = c(-1, 1)) +
44. labs(
45. title = "So sánh mối quan hệ LNST~Doanh thu và ROE~Giá cổ phiếu",
46. subtitle = "Cửa sổ trượt 3 năm",
47. x = "Năm",
48. y = "Hệ số tương quan (r)",
49. color = "Mối quan hệ"
50. ) +
51. theme_minimal(base_size = 10) +
52. theme(
53. plot.title = element_text(face = "bold", hjust = 0.5),
54. legend.position = "bottom"
55. )Giải thích kĩ thuật
Dòng 1–4 (library()): Nạp các gói
tidyverse, ggplot2, zoo,
scales phục vụ cho xử lý dữ liệu, tính toán cửa sổ trượt và
trực quan hóa.
Dòng 5–11 dùng rename() đổi tên các
biến (LNST, ROE, Gia) trong bộ
(df_roll) và hàm arrange()sắp xếp giá trị theo
năm
Dòng 12–19: Tạo biến
Roll_Corr_LNST_DT bằng hàm rollapplyr()(thuộc
gói zoo), ghép 2 biến vào cùng ma trận bằng
cbind, tính tương quan dựa trên 3 năm
width = 3,
FUN = function(x) cor(x[,1], x[,2], use = "complete.obs")dùng
định nghĩa hàm con để tính hệ số tương quan 2 cột,
fill = NA để chèn NA vào dữ liệu trống.
Dòng 20 - 27 làm tương tự câu lệnh trên cho biến ROE
Dòng 28–37: Gộp hai chuỗi kết quả vào cùng bảng
left_join(), chuyển sang dạng long bằng
pivot_longer() và gán theo recode()
Dòng 38–55 (ggplot()): dùng
geom_line() và geom_point() minh họa xu hướng
tương quan theo năm, geom_hline(yintercept = 0) tạo đường
trung tính và giới hạn giá trị tương quan
scale_y_continuous(limits = c(-1, 1))
Nhận xét
Giai đoạn 2015–2018:
Hệ số tương quan của LNST–Doanh thu duy trì r ≈
0.95–1.0, phản ánh sự ổn định gần như tuyệt
đối giữa tăng trưởng doanh thu và lợi nhuận.
ROE–Giá cổ phiếu tăng dần từ r ≈ 0.4 lên
0.9, cho thấy niềm tin thị trường dần cải
thiện đối với hiệu quả sinh lời của doanh nghiệp.
Năm 2019:
Xuất hiện biến động mạnh – hệ số ROE–Giá cổ
phiếu chuyển sang âm (-0.5), trong khi LNST–Doanh thu
vẫn cao (~1.0).
Đây là hiện tượng nhiễu do outlier 2019 (ROA >
100%), khiến thị trường mất tương quan tạm thời với
hiệu quả kế toán.
Giai đoạn 2020–2023:
Mối quan hệ ROE–Giá cổ phiếu phục hồi mạnh mẽ, đạt lại
r ≈ 0.8–1.0, phản ánh niềm tin nhà đầu tư quay
trở lại.
LNST–Doanh thu vẫn ổn định đến 2022, nhưng giảm
nhẹ ở 2023 (r ~0.2–0.3) – dấu hiệu cho thấy biên lợi
nhuận đang chịu áp lực từ chi phí và yếu tố thị
trường.
Tổng kết ý nghĩa
| Mối quan hệ | Giai đoạn ổn định | Giai đoạn biến động | Nhận định |
|---|---|---|---|
| LNST ~ Doanh thu | 2014–2022 (r ≈ 0.95–1.0) | 2023 (r ~0.2) | Hoạt động kinh doanh ổn định, chỉ suy yếu nhẹ do biến động chu kỳ. |
| ROE ~ Giá cổ phiếu | 2015–2018, 2021–2023 (r ≈ 0.8–1.0) | 2019–2020 (r âm) | Thị trường định giá lệch do outlier 2019, sau đó phục hồi mạnh. |
Kết luận
1. library(tidyverse)
2. library(ggplot2)
3. library(reshape2)
4. library(scales)
5. df_analysis <- data %>%
6. rename(
7. ROE = ROE_Nam,
8. ROA = ROA_Nam,
9. `Biên LNR` = BienLoiNhuanRong_Nam,
10. `Hiệu suất TS` = TAT_Nam,
11. EPS = EPS,
12. Gia = Gia_DongCua_CuoiNam
13. )
14. phase_pre2016 <- df_analysis %>% filter(Nam <= 2016)
15. phase_post2016 <- df_analysis %>% filter(Nam > 2016)
16. vars_eff <- c("ROE", "ROA", "Biên LNR", "Hiệu suất TS", "EPS", "Gia")
17. corr_pre <- cor(phase_pre2016[vars_eff], use = "pairwise.complete.obs", method = "pearson")
18. corr_post <- cor(phase_post2016[vars_eff], use = "pairwise.complete.obs", method = "pearson")
19. corr_pre_long <- melt(corr_pre) %>%
20. mutate(Pha = "Trước 2016 (2014–2016)")
21. corr_post_long <- melt(corr_post) %>%
22. mutate(Pha = "Sau 2016 (2017–2024)")
23. corr_all_long <- bind_rows(corr_pre_long, corr_post_long)
24. ggplot(corr_all_long, aes(x = Var1, y = Var2, fill = value)) +
25. geom_tile(color = "white") +
26. geom_text(aes(label = sprintf("%.2f", value)), size = 3, color = "black") +
27. scale_fill_gradient2(
28. low = "#D55E00", mid = "white", high = "#0072B2",
29. midpoint = 0, limits = c(-1, 1),
30. name = "Hệ số\nTương quan (r)"
31. ) +
32. facet_wrap(~ Pha) +
33. labs(
34. title = "Tương quan mối quan hệ theo pha chu kỳ (trước & sau 2016)",
35. subtitle = "So sánh độ mạnh yếu của mối quan hệ giữa các biến hiệu suất và định giá",
36. x = "Biến 1",
37. y = "Biến 2"
38. ) +
39. theme_minimal(base_size = 10) +
40. theme(
41. plot.title = element_text(face = "bold", hjust = 0.5),
42. strip.text = element_text(face = "bold", size = 12),
43. axis.text.x = element_text(angle = 45, hjust = 1),
44. plot.margin = unit(c(1, 1, 1, 1), "cm")
45. )Nhận xét kĩ thuật
Dòng 1–4 Nạp các gói tidyverse,
ggplot2, reshape2, scales phù hợp
tạo tương quan
Dòng 5–13: Chuẩn hóa tên biến trong
df_analysis bằng rename()
Dòng 14–15: dùng filter()để chọn
lọc và tách dữ liệu thành 2 pha (phase_pre2016: trước 2016)
và (phase_post2016: sau 2016 )
Dòng 16–18: Tính ma trận tương quan bằng
cor() cho từng pha chu kỳ đồng thời sử dụng
use = "pairwise.complete.obs" để bỏ qua giá trị thiếu khi
tính
Dòng 19–22: dùng hàm tạo mutate()
để thực hiện chuyển ma trận sang dạng long bằng
melt()
Dòng 23: gộp hai bảng tương quan thành bằng
bind_rows()
Dòng 24–45: vẽ biểu đồ ggp như các bước trước
Nhận xét
Pha chu kì trước 2016 (2014–2016)
Pha chu kì sau 2016 (2017–2024)
Kết luận
Phân tích toàn bộ giai đoạn 2014–2024 cho thấy hiệu suất tài chính, cấu trúc sinh lời và cơ chế định giá của PVGas (GAS) có sự ổn định nội tại cao, nhưng mối liên hệ với thị trường đã biến đổi đáng kể theo chu kỳ năng lượng.Kết luận được chia thành những nhận định chung sau đây:
1. Hiệu suất sinh lời và cấu trúc nội tại
2. Quan hệ giữa Hiệu quả hoạt động và Định giá
3. Tính ổn định và kiểm định độ bền mô hình
4. Nhận xét tính bền vững của doanh nghiệp