Trong bối cảnh nền kinh tế toàn cầu ngày càng vận hành dựa trên dữ liệu, năng lực phân tích và khai thác thông tin từ dữ liệu tài chính đóng vai trò then chốt đối với các nhà phân tích, nhà đầu tư và các tổ chức tài chính. Ngôn ngữ lập trình R, với hệ sinh thái thư viện phong phú và khả năng xử lý thống kê mạnh mẽ, đã trở thành một công cụ phân tích dữ liệu hàng đầu, cho phép thực hiện các thao tác từ làm sạch, biến đổi, trực quan hóa đến mô hình hóa phức tạp.
Nghiên cứu này tập trung vào việc áp dụng ngôn ngữ R để thực hiện:
“Phân tích dữ liệu đầu tư và chỉ số tài chính của các công ty niêm yết trên sàn NYSE”
Bộ dữ liệu nền tảng cho nghiên cứu là “400K NYSE Random Investments + Financial Ratios” thu thập từ nền tảng Kaggle. Đây là một bộ dữ liệu giả lập quy mô lớn, mô phỏng 405.258 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. Dữ liệu kết hợp thông tin về giao dịch (ngày mua/bán, giá, số tiền), hiệu suất đầu tư (lợi suất, rủi ro), và các chỉ số tài chính cơ bản của doanh nghiệp tại thời điểm đầu tư.
Mục tiêu chính của nghiên cứu bao gồm:
Áp dụng quy trình phân tích dữ liệu bằng R: Thực hiện tuần tự các bước từ làm sạch, chuẩn bị dữ liệu, thống kê mô tả, đến trực quan hóa đa chiều.
Khám phá đặc điểm dữ liệu đầu tư NYSE: Phân tích cấu trúc, phân bố của các biến số chính (lợi suất, rủi ro, định giá, hiệu quả hoạt động) trong bộ dữ liệu mẫu.
Xác định các yếu tố ảnh hưởng đến hiệu suất đầu
tư: Sử dụng các phương pháp thống kê và trực quan hóa để khám
phá mối quan hệ giữa các chỉ số tài chính, đặc điểm giao dịch (thời gian
nắm giữ, ngành nghề), rủi ro và kết quả đầu tư thực tế
(Real_Return, investment GOOD/BAD).
Đánh giá sự khác biệt giữa các nhóm: So sánh
hiệu suất, rủi ro, và đặc điểm tài chính giữa các ngành
(sector), các chiến lược nắm giữ
(Holding_Period), và các nhóm kết quả đầu tư
(investment).
Tên: 400K NYSE Random Investments + Financial Ratios Dataset.
Nguồn: Kaggle (Dữ liệu giả lập dựa trên hoạt động thực tế tại NYSE).
Kích thước: 405.258 quan sát (giao dịch) x 25 biến (cột).
Loại dữ liệu: Hỗn hợp gồm biến định tính
(Factor: company, sector,
investment, ngày tháng dạng text) và biến định lượng
(Numeric: giá, lợi suất, chỉ số tài chính).
Phạm vi thời gian: Giao dịch mua được thực hiện từ năm 2013 đến 2018.
Mô tả chi tiết các biến:
| Nhóm Biến | Tên Biến Gốc | Mô tả |
|---|---|---|
| Định danh | X | ID tự tăng của dòng dữ liệu |
| Định danh | company | Mã cổ phiếu (Factor) |
| Định danh | sector | Ngành nghề (Factor) |
| Giao dịch | horizon..days. | Số ngày nắm giữ (Integer) |
| Giao dịch | amount | Số tiền đầu tư (Integer) |
| Giao dịch | date_BUY_fix | Ngày mua (Factor, YYYY-MM-DD) |
| Giao dịch | date_SELL_fix | Ngày bán (Factor, YYYY-MM-DD) |
| Giao dịch | price_BUY | Giá mua (Numeric) |
| Giao dịch | price_SELL | Giá bán (Numeric) |
| Hiệu suất & Rủi ro | nominal_return | Lợi suất danh nghĩa (Numeric, %) |
| Hiệu suất & Rủi ro | expected_return..yearly. | Lợi suất kỳ vọng hàng năm (Numeric, %) |
| Hiệu suất & Rủi ro | Volatility_Buy | Độ biến động giá khi mua (Numeric) |
| Hiệu suất & Rủi ro | Volatility_sell | Độ biến động giá khi bán (Numeric) |
| Hiệu suất & Rủi ro | Sharpe.Ratio | Tỷ suất Sharpe (Numeric) |
| Hiệu suất & Rủi ro | inflation | Tỷ lệ lạm phát tại thời điểm bán (Numeric, %) |
| Chỉ số Tài chính | PE_ratio | Tỷ số Giá/Thu nhập (Numeric) |
| Chỉ số Tài chính | EPS_ratio | Thu nhập trên mỗi cổ phiếu (Numeric) |
| Chỉ số Tài chính | PS_ratio | Tỷ số Giá/Doanh thu (Numeric) |
| Chỉ số Tài chính | PB_ratio | Tỷ số Giá/Giá trị sổ sách (Numeric) |
| Chỉ số Tài chính | current_ratio | Tỷ lệ Thanh khoản hiện hành (Numeric) |
| Chỉ số Tài chính | roa_ratio | Tỷ suất Sinh lời trên Tài sản (Numeric, %) |
| Chỉ số Tài chính | roe_ratio | Tỷ suất Sinh lời trên Vốn CSH (Numeric, %) |
| Chỉ số Tài chính | NetProfitMargin_ratio | Biên Lợi nhuận ròng (Numeric, %) |
| Phân loại & Xếp hạng | investment | Kết quả đầu tư (Factor: GOOD/BAD) |
| Phân loại & Xếp hạng | ESG_ranking | Xếp hạng ESG (Numeric) |
Nghiên cứu này được cấu trúc thành 6 mục chính, bám sát quy trình phân tích dữ liệu:
Giới thiệu và chuẩn bị dữ liệu (Mục 1.1): Bao
gồm tổng quan, kiểm tra chất lượng, làm sạch, và tạo các biến phái sinh
cần thiết từ bộ dữ liệu gốc. Kết quả là bộ dữ liệu
nyse_clean sẵn sàng cho phân tích.
Lược khảo nghiên cứu liên quan (Mục 1.2): Trình bày các lý thuyết tài chính nền tảng và kết quả từ các nghiên cứu thực nghiệm trước đây về các yếu tố ảnh hưởng đến lợi suất cổ phiếu, làm cơ sở để đối chiếu và thảo luận kết quả.
Thống kê mô tả (Mục 1.3): Đi sâu vào phân tích đặc điểm phân phối, tương quan, và kiểm định sự khác biệt trung bình giữa các nhóm dữ liệu bằng các công cụ thống kê.
Trực quan hóa dữ liệu phân tích (Mục 1.4): Sử
dụng ggplot2 và plotly để xây dựng một hệ
thống biểu đồ đa dạng (phân bố, mối quan hệ, so sánh nhóm, xu hướng thời
gian) nhằm khám phá và trình bày các phát hiện một cách trực
quan.
Thảo luận kết quả (Mục 1.5): Tổng hợp, so sánh các kết quả phân tích thống kê và trực quan hóa với phần lược khảo, đưa ra các bình luận và giải thích về mặt kinh tế/tài chính.
Kết luận và hạn chế (Mục 1.6): Tóm tắt các phát hiện chính, nêu rõ các hạn chế của nghiên cứu và đề xuất hướng phát triển trong tương lai.
# 1. Tải các thư viện cần thiết cho mục này
library(dplyr) # Cho các thao tác dữ liệu sau này
library(readr) # Cung cấp hàm read_csv tối ưu hơn read.csv
library(skimr) # Cung cấp hàm skim() để tóm tắt dữ liệu
library(knitr) # Để tạo bảng đẹp (kable)
# 2. Đọc dữ liệu từ file CSV
# Sử dụng read_csv từ readr để đọc nhanh hơn và xử lý kiểu dữ liệu tốt hơn
# na.strings được giữ nguyên để xử lý giá trị rỗng
file_path <- "C:/Users/Admin/Documents/NGÔN NGỮ R/final_transactions_dataset.csv"
nyse_raw <- read_csv(file_path, na = c("", "NA"))
# 3. Kiểm tra kích thước dữ liệu (Số dòng, số cột)
num_obs_raw <- nrow(nyse_raw) # Số lượng quan sát (dòng)
num_vars_raw <- ncol(nyse_raw) # Số lượng biến (cột)
# In kết quả kích thước
cat("1.1.2.1: Kiểm tra kích thước dữ liệu \n")## 1.1.2.1: Kiểm tra kích thước dữ liệu
## Số lượng quan sát (giao dịch): 405,258
## Số lượng biến (trường thông tin): 25
# Chuyển đổi các cột ngày tháng sang Date ngay sau khi đọc
# (Thao tác này nằm ở Mục 1.3, nhưng thực hiện sớm để skim() nhận diện đúng)
if("date_BUY_fix" %in% names(nyse_raw)) {
nyse_raw <- nyse_raw %>% mutate(date_BUY_fix = as.Date(date_BUY_fix))
}
if("date_SELL_fix" %in% names(nyse_raw)) {
nyse_raw <- nyse_raw %>% mutate(date_SELL_fix = as.Date(date_SELL_fix))
}Dữ liệu gốc được đọc thành công vào đối tượng nyse_raw.
Kết quả kiểm tra kích thước xác nhận quy mô lớn của bộ dữ liệu với
num_obs_raw = 405,258 quan sát và num_vars_raw
= 25 biến. Các cột ngày tháng đã được chuyển đổi sang kiểu
Date để chuẩn bị cho các bước kiểm tra tiếp theo.
# 1. Kiểm tra cấu trúc dữ liệu chi tiết (tên biến, kiểu dữ liệu)
cat("\n 1.1.2.2: Kiểm tra cấu trúc dữ liệu (str)\n")##
## 1.1.2.2: Kiểm tra cấu trúc dữ liệu (str)
## tibble [405,258 × 25] (S3: tbl_df/tbl/data.frame)
## $ ...1 : num [1:405258] 0 1 2 3 4 5 7 8 9 10 ...
## $ company : chr [1:405258] "BBY" "BAC" "AXP" "KSS" ...
## $ sector : chr [1:405258] "RETAIL" "BANK" "BANK" "RETAIL" ...
## $ horizon (days) : num [1:405258] 2 330 7 5 360 15 720 600 30 6 ...
## $ amount : num [1:405258] 100 15000 3000 20000 15000 50000 1500 300 50000 400 ...
## $ date_BUY_fix : Date[1:405258], format: "2017-05-25" "2016-11-22" ...
## $ date_SELL_fix : Date[1:405258], format: "2017-05-26" "2017-10-18" ...
## $ price_BUY : num [1:405258] 55.6 18.6 59.9 38.2 51.9 ...
## $ price_SELL : num [1:405258] 53.5 24.7 59.5 36 52 ...
## $ Volatility_Buy : num [1:405258] 0.384 0.323 0.239 0.429 0.195 ...
## $ Volatility_sell : num [1:405258] 0.386 0.236 0.235 0.429 0.254 ...
## $ Sharpe Ratio : num [1:405258] 0.384 0.323 0.239 0.429 0.195 ...
## $ expected_return (yearly): num [1:405258] 1.44e-03 1.71e-01 2.82e-03 9.39e-05 1.50e-01 ...
## $ inflation : num [1:405258] 1.96 -0.2 -0.2 -0.2 -0.5 -0.2 -0.15 -0.2 -0.5 -0.2 ...
## $ nominal_return : num [1:405258] -0.03722 0.32432 -0.00576 -0.05839 0.00344 ...
## $ investment : chr [1:405258] "BAD" "GOOD" "BAD" "BAD" ...
## $ ESG_ranking : num [1:405258] 12 26.3 19.8 12.9 27.9 17.6 31.6 24.8 26.3 27.9 ...
## $ PE_ratio : num [1:405258] 12.58 11.39 10.58 11.09 9.38 ...
## $ EPS_ratio : num [1:405258] 3.73 1.26 5.64 3.27 5.46 4.56 1.05 1.71 0.96 5.99 ...
## $ PS_ratio : num [1:405258] 0.38 1.71 1.67 0.36 1.87 ...
## $ PB_ratio : num [1:405258] 3.19 0.54 2.6 1.25 0.81 ...
## $ NetProfitMargin_ratio : num [1:405258] 3.01 15.7 15.68 3.17 19.91 ...
## $ current_ratio : num [1:405258] 1.49 0.92 1.91 1.6 0.99 ...
## $ roa_ratio : num [1:405258] 8.69 0.67 3.39 4.41 0.81 ...
## $ roe_ratio : num [1:405258] 26.69 5.54 25.78 11.35 8.91 ...
# 2. Hiển thị 6 dòng dữ liệu đầu tiên để xem mẫu dữ liệu thực tế
cat("\n 1.1.2.2: Hiển thị 6 Dòng Đầu tiên (head)\n")##
## 1.1.2.2: Hiển thị 6 Dòng Đầu tiên (head)
# Sử dụng kable để hiển thị bảng đẹp hơn head() mặc định
kable(head(nyse_raw),
caption = "Bảng 1.1.2: Sáu quan sát đầu tiên của bộ dữ liệu NYSE", # Cập nhật caption
format = "pipe",
align = "l")| …1 | company | sector | horizon (days) | amount | date_BUY_fix | date_SELL_fix | price_BUY | price_SELL | Volatility_Buy | Volatility_sell | Sharpe Ratio | expected_return (yearly) | inflation | nominal_return | investment | ESG_ranking | PE_ratio | EPS_ratio | PS_ratio | PB_ratio | NetProfitMargin_ratio | current_ratio | roa_ratio | roe_ratio |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | BBY | RETAIL | 2 | 100 | 2017-05-25 | 2017-05-26 | 55.55180 | 53.48391 | 0.3836656 | 0.3857480 | 0.3836656 | 0.0014373 | 1.96 | -0.0372245 | BAD | 12.0 | 12.58 | 3.73 | 0.38 | 3.19 | 3.01 | 1.49 | 8.69 | 26.69 |
| 1 | BAC | BANK | 330 | 15000 | 2016-11-22 | 2017-10-18 | 18.61675 | 24.65447 | 0.3228091 | 0.2363500 | 0.3228091 | 0.1709691 | -0.20 | 0.3243168 | GOOD | 26.3 | 11.39 | 1.26 | 1.71 | 0.54 | 15.70 | 0.92 | 0.67 | 5.54 |
| 2 | AXP | BANK | 7 | 3000 | 2016-09-27 | 2016-10-04 | 59.86230 | 59.51773 | 0.2386420 | 0.2354905 | 0.2386420 | 0.0028236 | -0.20 | -0.0057560 | BAD | 19.8 | 10.58 | 5.64 | 1.67 | 2.60 | 15.68 | 1.91 | 3.39 | 25.78 |
| 3 | KSS | RETAIL | 5 | 20000 | 2016-10-11 | 2016-10-17 | 38.21672 | 35.98533 | 0.4285595 | 0.4293397 | 0.4285595 | 0.0000939 | -0.20 | -0.0583879 | BAD | 12.9 | 11.09 | 3.27 | 0.36 | 1.25 | 3.17 | 1.60 | 4.41 | 11.35 |
| 4 | JPM | BANK | 360 | 15000 | 2015-03-12 | 2016-03-07 | 51.86934 | 52.04797 | 0.1946118 | 0.2540115 | 0.1946118 | 0.1499787 | -0.50 | 0.0034439 | GOOD | 27.9 | 9.38 | 5.46 | 1.87 | 0.81 | 19.91 | 0.99 | 0.81 | 8.91 |
| 5 | PEP | FMCG | 15 | 50000 | 2016-09-09 | 2016-09-23 | 91.77097 | 94.67268 | 0.1376212 | 0.1382858 | 0.1376212 | 0.0032632 | -0.20 | 0.0316190 | GOOD | 17.6 | 21.03 | 4.56 | 2.27 | 10.83 | 10.74 | 1.32 | 9.29 | 54.98 |
Kết quả từ str() cho thấy cấu trúc chi tiết:
Kiểu dữ liệu: Các biến số
(price_BUY, nominal_return…) là
num (numeric). Các biến định danh (company,
sector, investment) là chr
(character). Quan trọng là các biến ngày tháng
(date_BUY_fix, date_SELL_fix) đã được chuyển
thành kiểu Date. Các kiểu chr sẽ cần chuyển
thành Factor ở Mục 1.3. Biến X là
dbl cần loại bỏ.
Giá trị mẫu: head() hiển thị dữ
liệu thực tế, giúp hình dung rõ hơn về định dạng và giá trị của các
biến.
# 1. Sử dụng hàm skim() để có cái nhìn tổng quan nhanh về phân bố và kiểu dữ liệu
cat("\n1.1.2.3: Tóm tắt tổng quan (skim)\n")##
## 1.1.2.3: Tóm tắt tổng quan (skim)
# (Chạy skim() trên nyse_raw SAU khi đã chuyển đổi Date)
skim_summary <- skim(nyse_raw)
print(skim_summary) # In kết quả skim đầy đủ## ── Data Summary ────────────────────────
## Values
## Name nyse_raw
## Number of rows 405258
## Number of columns 25
## _______________________
## Column type frequency:
## character 3
## Date 2
## numeric 20
## ________________________
## Group variables None
##
## ── Variable type: character ────────────────────────────────────────────────────
## skim_variable n_missing complete_rate min max empty n_unique whitespace
## 1 company 0 1 1 4 0 27 0
## 2 sector 0 1 4 6 0 5 0
## 3 investment 0 1 3 4 0 2 0
##
## ── Variable type: Date ─────────────────────────────────────────────────────────
## skim_variable n_missing complete_rate min max median
## 1 date_BUY_fix 0 1 2013-10-10 2018-10-09 2016-05-19
## 2 date_SELL_fix 0 1 2013-10-11 2020-09-28 2016-11-21
## n_unique
## 1 1248
## 2 1729
##
## ── Variable type: numeric ──────────────────────────────────────────────────────
## skim_variable n_missing complete_rate mean sd
## 1 ...1 0 1 249936. 144240.
## 2 horizon (days) 0 1 187. 211.
## 3 amount 0 1 8108. 12774.
## 4 price_BUY 0 1 105. 217.
## 5 price_SELL 0 1 117. 250.
## 6 Volatility_Buy 0 1 0.254 0.0981
## 7 Volatility_sell 0 1 0.260 0.0994
## 8 Sharpe Ratio 0 1 0.254 0.0981
## 9 expected_return (yearly) 0 1 0.0708 0.143
## 10 inflation 0 1 0.578 1.04
## 11 nominal_return 0 1 0.0710 0.299
## 12 ESG_ranking 0 1 22.6 6.51
## 13 PE_ratio 0 1 30.3 84.7
## 14 EPS_ratio 0 1 3.44 4.39
## 15 PS_ratio 0 1 2.72 3.60
## 16 PB_ratio 0 1 4.69 5.91
## 17 NetProfitMargin_ratio 0 1 9.21 10.4
## 18 current_ratio 0 1 2.17 2.56
## 19 roa_ratio 0 1 5.60 5.98
## 20 roe_ratio 0 1 15.6 17.5
## p0 p25 p50 p75 p100 hist
## 1 0 125063. 249938. 374755. 499999 ▇▇▇▇▇
## 2 1 15 90 300 720 ▇▂▂▁▁
## 3 50 400 2000 10000 50000 ▇▁▁▁▁
## 4 7.14 28.3 46.2 76.3 2040. ▇▁▁▁▁
## 5 4.01 28.4 48.0 81.6 3451. ▇▁▁▁▁
## 6 0.0904 0.185 0.232 0.307 0.698 ▇▇▃▁▁
## 7 0.0904 0.189 0.238 0.316 0.923 ▇▅▁▁▁
## 8 0.0904 0.185 0.232 0.307 0.698 ▇▇▃▁▁
## 9 -0.278 0.00106 0.0128 0.0826 1.02 ▁▇▁▁▁
## 10 -0.5 -0.2 -0.15 1.68 1.96 ▇▁▁▁▅
## 11 -0.872 -0.0284 0.0141 0.111 8.85 ▇▁▁▁▁
## 12 12 16.3 25.1 27.9 31.6 ▇▅▂▇▇
## 13 0 9.82 13.7 23.5 1117. ▇▁▁▁▁
## 14 -6.56 1.46 2.96 4.56 29.9 ▂▇▁▁▁
## 15 0.16 0.47 1.71 3.18 24.5 ▇▁▁▁▁
## 16 0 1.22 3.05 5.23 47.6 ▇▁▁▁▁
## 17 -24.6 2.62 7.7 15.8 62 ▁▇▆▁▁
## 18 0.61 0.98 1.22 1.79 13.6 ▇▁▁▁▁
## 19 -13.0 1.74 5.71 7.99 38.1 ▁▇▃▁▁
## 20 -99.5 8.83 16.1 26.0 57.2 ▁▁▁▇▃
Xác nhận kích thước & kiểu: Tái xác nhận
405,258 dòng x 25 cột. Phân loại kiểu dữ liệu cho thấy 3 biến
character (cần chuyển thành Factor), 2 biến
Date (đã chuẩn hóa), và 20 biến
numeric.
Kiểm tra NA: Cột n_missing và
complete_rate sẽ xác nhận lại việc bộ dữ liệu không có giá
trị khuyết thiếu.
Phân bố sơ bộ (Numeric): Phần thống kê và
histogram nhỏ cho các biến numeric sẽ tiếp tục cho
thấy:
Độ lệch lớn: Các biến như
nominal_return, PE_ratio có mean
khác median (p50), histogram lệch, cần xử lý outlier/chuẩn
hóa ở Mục 1.3.
Phạm vi rộng: Nhiều biến có khoảng min-max lớn.
Phân bố sơ bộ (Character): Số lượng giá trị duy
nhất (n_unique) cho company,
sector sẽ được hiển thị, xác nhận tính phù hợp để chuyển
thành Factor.
##
## 1.1.2.4: Kiểm tra giá trị khuyết thiếu (NA)
na_counts <- colSums(is.na(nyse_raw))
# 2. Lọc ra các cột có NA (nếu có)
cols_with_na <- na_counts[na_counts > 0]
# 3. Trình bày kết quả
if (length(cols_with_na) == 0) {
cat("Xác nhận: Không có giá trị khuyết thiếu (NA) trong bất kỳ cột nào.\n")
} else {
cat("Các cột chứa giá trị NA và số lượng tương ứng:\n")
# Tạo data frame để trình bày bằng kable
na_table <- data.frame(
TenBien = names(cols_with_na),
SoLuongNA = as.integer(cols_with_na)
)
print(kable(na_table,
caption = "Bảng 1.1.3: Thống kê giá trị khuyết thiếu (NA) theo biến", # Cập nhật caption
format = "pipe",
align = "l"))
}## Xác nhận: Không có giá trị khuyết thiếu (NA) trong bất kỳ cột nào.
Kết quả kiểm tra chi tiết tái khẳng định: không có giá trị khuyết
thiếu (NA) nào trong bộ dữ liệu nyse_raw.
# 1. Đếm số lượng bản ghi (dòng) trùng lặp hoàn toàn
cat("\n 1.1.2.5: Kiểm tra bản ghi trùng lặp\n")##
## 1.1.2.5: Kiểm tra bản ghi trùng lặp
num_duplicates <- sum(duplicated(nyse_raw))
# 2. In kết quả
cat("Số lượng bản ghi trùng lặp hoàn toàn:", num_duplicates, "\n")## Số lượng bản ghi trùng lặp hoàn toàn: 0
# 3. Kiểm tra và thông báo
if (num_duplicates == 0) {
cat("Xác nhận: Không có bản ghi trùng lặp hoàn toàn.\n")
} else {
cat("Cảnh báo: Phát hiện", num_duplicates, "bản ghi trùng lặp. Cần xem xét loại bỏ ở Mục 1.3.\n")
}## Xác nhận: Không có bản ghi trùng lặp hoàn toàn.
Kết quả kiểm tra xác nhận không có bản ghi nào bị trùng lặp hoàn toàn.
Tổng kết 1.1.2: Bộ dữ liệu nyse_raw
(sau khi chuyển đổi Date) có quy mô lớn, đầy đủ (không NA, không trùng
lặp), nhưng cần chuẩn hóa các kiểu dữ liệu character thành
Factor, loại bỏ biến X, và xử lý các biến
numeric có độ lệch cao.
# 1. Tải thư viện cần thiết cho mục này
library(dplyr)
library(lubridate) # Cần cho xử lý ngày tháng
library(knitr) # Cần cho kable
# 2. Tạo bản sao để tránh thay đổi dữ liệu gốc
nyse_clean <- nyse_raw
# 3. Loại bỏ cột index tự động '...1' và cột ngày bán gốc
nyse_clean <- nyse_clean %>%
select(-`...1`, -date_SELL_fix) # Loại bỏ 2 cột
cat("1.1.3.1a: Loại bỏ biến thừa \n")## 1.1.3.1a: Loại bỏ biến thừa
cat("Số lượng biến sau khi loại bỏ (...1, date_SELL_fix):", ncol(nyse_clean), "\n") # Còn lại 23 biến## Số lượng biến sau khi loại bỏ (...1, date_SELL_fix): 23
##
## 1.1.3.1b: Đổi tên biến
nyse_clean <- nyse_clean %>%
rename(
Horizon_Days = `horizon (days)`, # Đổi tên cho Số ngày nắm giữ
Expected_Return_Yr = `expected_return (yearly)`,
NetProfitMargin = NetProfitMargin_ratio,
Current_Ratio = current_ratio,
ROA = roa_ratio,
ROE = roe_ratio,
EPS = EPS_ratio,
PS = PS_ratio,
PB = PB_ratio,
PE = PE_ratio,
ESG = ESG_ranking,
Nominal_Return = nominal_return,
Date_Buy_Raw = date_BUY_fix, # Giữ lại ngày gốc dạng Date
Sharpe_Ratio = `Sharpe Ratio` # Giả sử tên gốc có dấu cách
)
# 5. Kiểm tra lại tên biến sau khi đổi
cat("Tên biến mới (một phần):\n")## Tên biến mới (một phần):
## [1] "company" "sector" "Horizon_Days" "amount" "Date_Buy_Raw"
## [6] "price_BUY"
Thao tác đầu tiên là dọn dẹp bộ dữ liệu. Biến index ...1
và biến ngày bán gốc date_SELL_fix được loại bỏ. Quan trọng
hơn, các biến có tên dài hoặc chứa ký tự đặc biệt/dấu cách (như
`horizon (days)`, `expected_return (yearly)`,
`Sharpe Ratio`) đã được đổi tên thành các tên ngắn gọn,
nhất quán ngay từ đầu. Bộ dữ liệu nyse_clean hiện có 23
biến với tên đã chuẩn hóa.
# 1. Xác định các biến Character cần chuyển đổi thành Factor
# (company, sector, investment - tên gốc đã là character)
cat("\n 1.1.3.2: Chuyển đổi kiểu dữ liệu (Character -> Factor) \n")##
## 1.1.3.2: Chuyển đổi kiểu dữ liệu (Character -> Factor)
# 2. Sử dụng mutate() kết hợp as.factor() để chuyển đổi
nyse_clean <- nyse_clean %>%
mutate(
# across() áp dụng hàm as.factor cho nhiều cột cùng lúc
across(c(company, sector, investment), as.factor)
)
# 3. Kiểm tra lại kiểu dữ liệu của các biến đã chuyển đổi
cat("Kiểu dữ liệu mới của 'company':", class(nyse_clean$company), "\n")## Kiểu dữ liệu mới của 'company': factor
## Kiểu dữ liệu mới của 'sector': factor
## Kiểu dữ liệu mới của 'investment': factor
# 4. In ra các cấp độ (levels) của biến sector để xem xét
cat("Các cấp độ (levels) của biến 'sector':\n")## Các cấp độ (levels) của biến 'sector':
## [1] "AUTO" "BANK" "FMCG" "RETAIL" "TECH"
Chuyển đổi các biến character (company,
sector, investment) thành kiểu
factor là bước chuẩn hóa quan trọng. Kiểu
factor giúp R hiểu rằng đây là các biến phân loại, tối ưu
hóa lưu trữ và cho phép thực hiện các phân tích nhóm và vẽ biểu đồ phân
loại hiệu quả. Kết quả xác nhận việc chuyển đổi thành công và cho thấy
có 5 ngành (sector) chính.
##
## 1.1.3.3: Xử lý biến Nngày tháng
if (!inherits(nyse_clean$Date_Buy, "Date")) {
# (Code chuyển đổi nếu cần, giả sử Date_Buy đã là Date)
cat("Cảnh báo: 'Date_Buy' chưa phải kiểu Date. Đang chuyển đổi...\n")
nyse_clean <- nyse_clean %>% mutate(Date_Buy = as.Date(Date_Buy_Raw))
} else {
cat("'Date_Buy' đã có kiểu Date.\n")
}## Cảnh báo: 'Date_Buy' chưa phải kiểu Date. Đang chuyển đổi...
# 2. Tính toán ngày bán dự kiến từ ngày mua và số ngày nắm giữ
nyse_clean <- nyse_clean %>%
mutate(
Horizon_Days_Int = as.integer(Horizon_Days),
Date_Sell = Date_Buy + Horizon_Days_Int
)
# 3. Tính toán lại Thời gian nắm giữ thực tế (để kiểm tra) bằng difftime
nyse_clean <- nyse_clean %>%
mutate(
Holding_Days = as.numeric(difftime(Date_Sell, Date_Buy, units = "days"))
)
# 4. So sánh Horizon_Days gốc và Holding_Days tính lại
cat("So sánh số ngày nắm giữ gốc và tính toán lại:\n")## So sánh số ngày nắm giữ gốc và tính toán lại:
print(kable(head(nyse_clean %>% select(Horizon_Days, Holding_Days)),
caption = "Bảng 1.1.4: Kiểm tra tính toán Thời gian Nắm giữ",
format="pipe"))##
##
## Table: Bảng 1.1.4: Kiểm tra tính toán Thời gian Nắm giữ
##
## | Horizon_Days| Holding_Days|
## |------------:|------------:|
## | 2| 2|
## | 330| 330|
## | 7| 7|
## | 5| 5|
## | 360| 360|
## | 15| 15|
# 5. Trích xuất Năm mua (Buy_Year) và Quý mua (Buy_Quarter)
nyse_clean <- nyse_clean %>%
mutate(
Buy_Year = year(Date_Buy), # Trích xuất năm
Buy_Quarter_Num = quarter(Date_Buy), # Trích xuất số quý (1-4)
# Tạo biến Buy_Quarter dạng YYYY.Q bằng cách kết hợp Year và Quarter_Num
Buy_Quarter = paste0(Buy_Year, ".", Buy_Quarter_Num)
)
# 6. Hiển thị kết quả trích xuất thời gian
cat("Kết quả trích xuất Năm và Quý mua (6 dòng đầu):\n")## Kết quả trích xuất Năm và Quý mua (6 dòng đầu):
print(kable(head(nyse_clean %>% select(Date_Buy, Buy_Year, Buy_Quarter)),
caption = "Bảng 1.1.5: Kết quả Trích xuất Thông tin Thời gian",
format="pipe"))##
##
## Table: Bảng 1.1.5: Kết quả Trích xuất Thông tin Thời gian
##
## |Date_Buy | Buy_Year|Buy_Quarter |
## |:----------|--------:|:-----------|
## |2017-05-25 | 2017|2017.2 |
## |2016-11-22 | 2016|2016.4 |
## |2016-09-27 | 2016|2016.3 |
## |2016-10-11 | 2016|2016.4 |
## |2015-03-12 | 2015|2015.1 |
## |2016-09-09 | 2016|2016.3 |
Chuẩn hóa ngày: Biến ngày mua
Date_Buy (được tạo từ Date_Buy_Raw) được đảm
bảo có kiểu Date.
Tái tạo ngày bán & kiểm tra:
Date_Sell được tính toán lại từ Date_Buy và
Horizon_Days. So sánh Holding_Days với
Horizon_Days gốc xác nhận tính nhất quán.
Trích xuất chu kỳ: Các biến
Buy_Year và Buy_Quarter được tạo ra, quan
trọng cho phân tích xu hướng và thời vụ sau này.
Log_PE)# 1. Kiểm tra phân bố gốc của PE
# (Đã thấy lệch ở 1.1.2.3 khi xem PE_ratio gốc)
cat("\n 1.1.3.4: Chuẩn hóa Tỷ suất Định giá P/E \n")##
## 1.1.3.4: Chuẩn hóa Tỷ suất Định giá P/E
## Tóm tắt PE gốc:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 9.82 13.71 30.33 23.49 1116.57
# 2. Tạo biến PE_Positive để xử lý giá trị âm/0 trước khi lấy log
# Chỉ giữ lại các giá trị P/E > 0 (hợp lý về mặt kinh tế)
nyse_clean <- nyse_clean %>%
mutate(
# Sử dụng tên biến mới 'PE'
PE_Positive = if_else(PE > 0, PE, NA_real_) # Gán NA nếu PE <= 0
)
# 3. Tính toán logarit tự nhiên của PE_Positive (Log_PE)
# Phép biến đổi log giúp giảm độ lệch và ảnh hưởng của outliers
nyse_clean <- nyse_clean %>%
mutate(
Log_PE = log(PE_Positive) # log() tự động trả về NA nếu input là NA
)
# 4. Kiểm tra phân bố của Log_PE
cat("\nTóm tắt Log_PE (sau khi chuẩn hóa):\n")##
## Tóm tắt Log_PE (sau khi chuẩn hóa):
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1.13 2.38 2.69 2.88 3.21 7.02 39751
# 5. So sánh Mean và Median để đánh giá hiệu quả chuẩn hóa
mean_pe_raw <- summary_pe_raw["Mean"]
median_pe_raw <- summary_pe_raw["Median"]
mean_log_pe <- summary_log_pe["Mean"]
median_log_pe <- summary_log_pe["Median"]
cat(paste("\nPE gốc: Mean =", round(mean_pe_raw, 2), "| Median =", round(median_pe_raw, 2), "=> Chênh lệch lớn (Lệch phải)\n"))##
## PE gốc: Mean = 30.33 | Median = 13.71 => Chênh lệch lớn (Lệch phải)
cat(paste("Log_PE: Mean =", round(mean_log_pe, 2), "| Median =", round(median_log_pe, 2), "=> Chênh lệch nhỏ (Đối xứng hơn)\n"))## Log_PE: Mean = 2.88 | Median = 2.69 => Chênh lệch nhỏ (Đối xứng hơn)
# 6. Đếm số lượng NA phát sinh do PE <= 0
na_log_pe <- sum(is.na(nyse_clean$Log_PE)) # Sử dụng tên biến mới 'Log_PE'
cat("Số lượng quan sát có PE <= 0 (bị gán NA trong Log_PE):", format(na_log_pe, big.mark = ","), "\n")## Số lượng quan sát có PE <= 0 (bị gán NA trong Log_PE): 39,751
Nhận xét phân tích 1.1.3.4:
Biến PE gốc có phân bố cực kỳ lệch phải
(Mean=30.33 >> Median=13.71), bị ảnh
hưởng nặng bởi các giá trị ngoại lai rất lớn (Max=1116.57).
Xử lý giá trị không hợp lệ: Bước tạo
PE_Positive đã loại bỏ các giá trị P/E âm hoặc bằng 0
(khoảng 39,751 quan sát), đảm bảo chỉ các công ty có lợi nhuận dương mới
được đưa vào phân tích định giá P/E.
Hiệu quả chuẩn hóa: Phép biến đổi logarit tự
nhiên đã tạo ra biến Log_PE với phân bố gần đối xứng hơn
nhiều (Mean=2.88 và Median=2.69). Việc này
giúp giảm thiểu tác động của outliers và làm cho biến
Log_PE phù hợp hơn khi sử dụng trong các mô hình thống kê
sau này.
1.1.3.5. Tạo biến đòn bẩy tài chính
(Leverage_Ratio)
# 1. Định nghĩa công thức xấp xỉ từ DuPont: Leverage ~ ROE / ROA
cat("\n 1.1.3.5: Tạo biến Đòn bẩy Tài chính (Leverage_Ratio) \n")##
## 1.1.3.5: Tạo biến Đòn bẩy Tài chính (Leverage_Ratio)
# 2. Tính toán Leverage_Ratio, kiểm soát lỗi chia cho 0 hoặc ROA quá nhỏ
nyse_clean <- nyse_clean %>%
mutate(
# Sử dụng giá trị tuyệt đối abs(ROA)
# Ngưỡng 0.001 (0.1%) để loại bỏ các trường hợp ROA gần bằng 0
Leverage_Ratio = if_else(
abs(ROA) > 0.001, # Điều kiện: ROA phải đủ lớn
ROE / ROA, # Công thức tính
NA_real_ # Gán NA nếu ROA quá nhỏ
)
)
# 3. Kiểm tra phân bố của biến Leverage_Ratio mới tạo
cat("Tóm tắt phân bố Leverage_Ratio:\n")## Tóm tắt phân bố Leverage_Ratio:
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1.103 2.486 3.439 5.212 6.692 34.545 2468
# 4. Đếm số lượng NA phát sinh do ROA quá nhỏ
na_leverage <- sum(is.na(nyse_clean$Leverage_Ratio))
cat("Số lượng quan sát có ROA quá nhỏ (bị gán NA trong Leverage_Ratio):", format(na_leverage, big.mark = ","), "\n")## Số lượng quan sát có ROA quá nhỏ (bị gán NA trong Leverage_Ratio): 2,468
# 5. Phân tích ý nghĩa kinh tế của Min > 1
min_leverage <- summary_leverage["Min."]
if (!is.na(min_leverage) && min_leverage > 1) {
cat("Phân tích: Min > 1 cho thấy các công ty hợp lệ đều có ROE > ROA, tức là đòn bẩy đang có hiệu ứng tích cực.\n")
}## Phân tích: Min > 1 cho thấy các công ty hợp lệ đều có ROE > ROA, tức là đòn bẩy đang có hiệu ứng tích cực.
Nhận xét phân tích 1.1.3.5:
Biến Leverage_Ratio được tạo ra như một thước đo xấp xỉ
mức độ sử dụng đòn bẩy tài chính, dựa trên mối quan hệ ROE ≈ ROA * Đòn
bẩy (sử dụng tên biến mới ROE và ROA).
Kiểm soát Lỗi: Điều kiện
abs(ROA) > 0.001 loại bỏ khoảng 2,468 quan sát có ROA
gần bằng 0, tránh kết quả vô cực.
Phân bố và ý nghĩa: Phân bố lệch phải
(Mean=5.21 > Median=3.44). Giá trị
Min > 1.1 ngụ ý rằng, trong các trường hợp hợp lệ, việc
sử dụng nợ đã có tác động khuếch đại tích cực lên ROE.
Holding_Period)# 1. Xác định các ngưỡng cắt (breaks) và nhãn (labels)
cat("\n 1.1.3.6: Phân loại thời gian nắm giữ (Holding_Period) \n")##
## 1.1.3.6: Phân loại thời gian nắm giữ (Holding_Period)
breaks_days <- c(0, 30, 180, Inf) # Ngưỡng: 0-30 ngày, 31-180 ngày, >180 ngày
labels_period <- c("Short-term (<=30d)", "Mid-term (31-180d)", "Long-term (>180d)")
# 2. Sử dụng hàm cut() để tạo biến Factor mới
# Sử dụng tên biến mới Horizon_Days
nyse_clean <- nyse_clean %>%
mutate(
Holding_Period = cut(Horizon_Days,
breaks = breaks_days,
labels = labels_period,
right = TRUE, include.lowest = TRUE)
)
# 3. Tính toán tần suất và tỷ lệ phần trăm cho từng nhóm
holding_freq <- nyse_clean %>%
count(Holding_Period, name = "Count") %>%
mutate(Percentage = round((Count / sum(Count)) * 100, 2)) %>%
arrange(desc(Count))
# 4. Trình bày kết quả bằng kable
cat("Phân bổ tần suất theo Thời gian Nắm giữ:\n")## Phân bổ tần suất theo Thời gian Nắm giữ:
print(kable(holding_freq,
caption = "Bảng 1.1.6: Tần suất Giao dịch theo Chiến lược Nắm giữ",
col.names = c("Thời gian Nắm giữ", "Số lượng", "Tỷ lệ (%)"),
format = "pipe", align = "l"))##
##
## Table: Bảng 1.1.6: Tần suất Giao dịch theo Chiến lược Nắm giữ
##
## |Thời gian Nắm giữ |Số lượng |Tỷ lệ (%) |
## |:------------------|:--------|:---------|
## |Long-term (>180d) |147526 |36.40 |
## |Short-term (<=30d) |135001 |33.31 |
## |Mid-term (31-180d) |122731 |30.28 |
Nhận xét phân tích 1.1.3.6:
Biến liên tục Horizon_Days được chuyển đổi thành biến
phân loại Holding_Period (Factor).
Phân bổ: Ba chiến lược (Ngắn, Trung, Dài hạn) có sự phân bổ tương đối đồng đều (~30-36%).
Ý nghĩa: Biến Holding_Period cho
phép so sánh hiệu suất, rủi ro giữa các chiến lược thời gian khác
nhau.
Real_Return)# 1. Áp dụng công thức Fisher Equation: Real = (1+Nominal)/(1+Inflation) - 1
cat("\n 1.1.3.7: Tính toán Lợi suất Thực tế (Real_Return) \n")##
## 1.1.3.7: Tính toán Lợi suất Thực tế (Real_Return)
nyse_clean <- nyse_clean %>%
mutate(
Real_Return = ((1 + Nominal_Return) / (1 + inflation)) - 1
)
# 2. Kiểm tra kết quả tính toán (so sánh Nominal và Real cho vài dòng)
cat("So sánh Lợi suất Danh nghĩa và Thực tế (10 dòng đầu):\n")## So sánh Lợi suất Danh nghĩa và Thực tế (10 dòng đầu):
real_return_check <- nyse_clean %>%
select(Nominal_Return, inflation, Real_Return) %>%
mutate(across(everything(), ~ round(. * 100, 2))) # Nhân 100 để hiển thị dạng %
print(kable(head(real_return_check, 10),
caption = "Bảng 1.1.7: So sánh Lợi suất Danh nghĩa và Thực tế (%)",
col.names = c("Danh nghĩa (%)", "Lạm phát (%)", "Thực tế (%)"),
format = "pipe"))##
##
## Table: Bảng 1.1.7: So sánh Lợi suất Danh nghĩa và Thực tế (%)
##
## | Danh nghĩa (%)| Lạm phát (%)| Thực tế (%)|
## |--------------:|------------:|-----------:|
## | -3.72| 196| -67.47|
## | 32.43| -20| 65.54|
## | -0.58| -20| 24.28|
## | -5.84| -20| 17.70|
## | 0.34| -50| 100.69|
## | 3.16| -20| 28.95|
## | 73.31| -15| 103.90|
## | 23.67| -20| 54.59|
## | -1.39| -50| 97.21|
## | 5.10| -20| 31.37|
##
## Tóm tắt phân bố Lợi suất Thực tế (Real_Return):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.95232 -0.62084 0.16733 0.08676 0.48586 16.35331
Nhận xét phân tích 1.1.3.7:
Lợi suất thực tế (Real_Return) được tính toán để phản
ánh sự thay đổi sức mua thực sự sau lạm phát, sử dụng biến
Nominal_Return.
Kiểm tra Logic: Khi inflation âm,
Real_Return > Nominal_Return, phù hợp lý
thuyết.
Phân bố: Phân bố rộng (Min -95%, Max 1635%),
lệch nhẹ (Mean < Median). Trung vị dương
(16.73%) cho thấy đa số giao dịch vẫn có lãi thực.
Real_Return là biến phụ thuộc quan trọng.
Risk_Level)# 1. Phân tích phân vị của Volatility_Buy để xác định ngưỡng
cat("\n 1.1.3.8: Tạo biến phân loại rủi ro (Risk_Level) \n")##
## 1.1.3.8: Tạo biến phân loại rủi ro (Risk_Level)
vol_quantiles <- quantile(nyse_clean$Volatility_Buy, probs = c(0, 0.33, 0.66, 1), na.rm = TRUE)
cat("Phân vị của Volatility_Buy (0%, 33%, 66%, 100%):\n")## Phân vị của Volatility_Buy (0%, 33%, 66%, 100%):
## 0% 33% 66% 100%
## 0.09041632 0.20200655 0.26697053 0.69755648
# 2. Tạo biến Risk_Level dựa trên phân vị (3 nhóm: Low, Medium, High)
nyse_clean <- nyse_clean %>%
mutate(
Risk_Level = cut(Volatility_Buy,
breaks = vol_quantiles,
labels = c("Low", "Medium", "High"),
include.lowest = TRUE, right = TRUE)
)
# 3. Kiểm tra tần suất của biến Risk_Level mới
risk_level_freq <- nyse_clean %>%
count(Risk_Level, name = "Count") %>%
mutate(Percentage = round((Count / sum(Count)) * 100, 2))
cat("\nPhân bổ tần suất theo Mức độ Rủi ro:\n")##
## Phân bổ tần suất theo Mức độ Rủi ro:
print(kable(risk_level_freq,
caption = "Bảng 1.1.8: Tần suất Giao dịch theo Mức độ Rủi ro",
col.names = c("Mức Rủi ro", "Số lượng", "Tỷ lệ (%)"),
format = "pipe", align = "l"))##
##
## Table: Bảng 1.1.8: Tần suất Giao dịch theo Mức độ Rủi ro
##
## |Mức Rủi ro |Số lượng |Tỷ lệ (%) |
## |:----------|:--------|:---------|
## |Low |133740 |33 |
## |Medium |133747 |33 |
## |High |137771 |34 |
Nhận xét phân tích 1.1.3.8:
Biến Volatility_Buy được phân loại thành 3 nhóm
(Low, Medium, High) dựa trên phân
vị.
Phân bổ đều: Mỗi nhóm rủi ro có số lượng quan sát gần bằng nhau (~33%).
Ý nghĩa: Biến Risk_Level giúp đơn
giản hóa phân tích ảnh hưởng của rủi ro và so sánh hiệu suất giữa các
nhóm rủi ro.
Amount_Level)# 1. Phân tích phân vị của amount để xác định ngưỡng
cat("\n 1.1.3.9: Tạo biến Phân loại Quy mô Giao dịch (Amount_Level) \n")##
## 1.1.3.9: Tạo biến Phân loại Quy mô Giao dịch (Amount_Level)
amount_quantiles <- quantile(nyse_clean$amount, probs = c(0, 0.33, 0.66, 1), na.rm = TRUE)
cat("Phân vị của amount (0%, 33%, 66%, 100%):\n")## Phân vị của amount (0%, 33%, 66%, 100%):
## 0% 33% 66% 100%
## 50 500 5000 50000
# 2. Tạo biến Amount_Level dựa trên phân vị (3 nhóm: Small, Medium, Large)
nyse_clean <- nyse_clean %>%
mutate(
Amount_Level = cut(amount,
breaks = amount_quantiles,
labels = c("Small", "Medium", "Large"),
include.lowest = TRUE, right = TRUE)
)
# 3. Kiểm tra tần suất của biến Amount_Level mới
amount_level_freq <- nyse_clean %>%
count(Amount_Level, name = "Count") %>%
mutate(Percentage = round((Count / sum(Count)) * 100, 2))
cat("\nPhân bổ tần suất theo Quy mô Giao dịch:\n")##
## Phân bổ tần suất theo Quy mô Giao dịch:
print(kable(amount_level_freq,
caption = "Bảng 1.1.9: Tần suất Giao dịch theo Quy mô Đầu tư",
col.names = c("Quy mô GD", "Số lượng", "Tỷ lệ (%)"),
format = "pipe", align = "l"))##
##
## Table: Bảng 1.1.9: Tần suất Giao dịch theo Quy mô Đầu tư
##
## |Quy mô GD |Số lượng |Tỷ lệ (%) |
## |:---------|:--------|:---------|
## |Small |142692 |35.21 |
## |Medium |143246 |35.35 |
## |Large |119320 |29.44 |
Nhận xét phân tích 1.1.3.9:
Biến amount được phân thành 3 nhóm (Small,
Medium, Large) dựa trên phân vị.
Ngưỡng phân vị: Kết quả cho thấy các ngưỡng phân vị xác định các nhóm như sau: Small (<= 500 USD), Medium (từ 501 đến 5000 USD), và Large (> 5000 USD).
Phân bổ: Tần suất các nhóm khá đồng đều, với nhóm Small (35.21%) và Medium (35.35%) chiếm tỷ trọng lớn hơn một chút so với nhóm Large (29.44%). Mặc dù không hoàn toàn bằng 1/3, sự phân bổ này vẫn đủ cân bằng để thực hiện các so sánh ý nghĩa giữa các nhóm quy mô giao dịch.
Ý nghĩa: Biến Amount_Level cho phép
phân tích xem quy mô giao dịch có ảnh hưởng đến lợi suất (Real_Return)
hay hành vi đầu tư khác (ví dụ: các giao dịch lớn có tập trung vào
ngành/rủi ro nào không?).
# Kiểm tra sự tồn tại và tóm tắt nhanh các biến đã đổi tên
cat("\n 1.1.3.10: Kiểm tra các biến có sẵn khác \n")##
## 1.1.3.10: Kiểm tra các biến có sẵn khác
# Sử dụng các tên biến mới đã được đổi ở 1.1.3.1
cat("Tóm tắt Biên Lợi nhuận ròng (NetProfitMargin):\n")## Tóm tắt Biên Lợi nhuận ròng (NetProfitMargin):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -24.630 2.620 7.700 9.205 15.770 62.000
##
## Tóm tắt Tỷ số Giá/Doanh thu (PS):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.160 0.470 1.710 2.725 3.180 24.490
##
## Tóm tắt Tỷ lệ Thanh khoản (Current_Ratio):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.610 0.980 1.220 2.173 1.790 13.560
##
## Tóm tắt Tỷ suất Sharpe (Sharpe_Ratio):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.09042 0.18536 0.23220 0.25414 0.30673 0.69756
##
## Tóm tắt Xếp hạng ESG (ESG):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 12.00 16.30 25.10 22.57 27.90 31.60
Nhận xét phân tích 1.1.3.10:
Việc kiểm tra tóm tắt thống kê cho các biến tài chính, rủi ro và ESG cung cấp cái nhìn sâu hơn về đặc điểm của các công ty trong mẫu:
Biên Lợi nhuận ròng
(NetProfitMargin):
Phân bố rộng từ -24.63% đến 62.00%, cho
thấy sự khác biệt rất lớn về hiệu quả hoạt động giữa các công
ty.
Giá trị trung bình (Mean = 9.21%) cao hơn trung vị
(Median = 7.70%), cho thấy phân bố hơi lệch phải, có một số
công ty đạt biên lợi nhuận rất cao kéo trung bình lên. Tuy nhiên, mức độ
lệch không quá nghiêm trọng như PE. Đa số công ty có biên
lợi nhuận dương.
Tỷ số Giá/Doanh thu (PS):
Dao động từ 0.16 đến 24.49. Giá trị
trung bình (Mean = 2.73) cao hơn trung vị
(Median = 1.71), cho thấy phân bố lệch phải, có một số công
ty được thị trường định giá rất cao so với doanh thu.
Giá trị PS thường thấp hơn PE, điều này phù hợp với kết quả
(Median PS=1.71 < Median
PE=13.71).
Tỷ lệ Thanh khoản
(Current_Ratio):
Dao động từ 0.61 đến 13.56. Giá trị
trung bình (Mean = 2.17) cao hơn trung vị
(Median = 1.22) khá nhiều, cho thấy sự lệch phải mạnh do
một số công ty có tỷ lệ thanh khoản cực kỳ cao.
Mức trung vị 1.22 cho thấy một nửa số công ty có tỷ
lệ thanh khoản ở mức an toàn (tài sản ngắn hạn > nợ ngắn hạn). Tuy
nhiên, 1st Qu. = 0.98 cho thấy có khoảng 25% công ty có rủi
ro thanh khoản tiềm ẩn (tài sản ngắn hạn < nợ ngắn hạn).
Tỷ suất Sharpe (Sharpe_Ratio):
Điều thú vị là tất cả các giá trị đều dương, dao động từ
0.09 đến 0.70. Giá trị trung bình
(Mean = 0.25) và trung vị (Median = 0.23) khá
gần nhau, cho thấy phân bố tương đối đối xứng.
Việc Sharpe Ratio luôn dương có thể là đặc điểm của dữ liệu giả lập hoặc giai đoạn thị trường được mô phỏng. Nó đo lường lợi suất vượt trội trên mỗi đơn vị rủi ro (so với tài sản phi rủi ro), giá trị dương cho thấy các khoản đầu tư, trung bình, đã tạo ra lợi suất bù đắp được rủi ro.
Xếp hạng ESG (ESG):
Dao động từ 12.00 đến 31.60. Giá trị
trung bình (Mean = 22.57) và trung vị (Median
= 25.10) khá gần nhau, nhưng Mean < Median
cho thấy phân bố hơi lệch trái nhẹ (có một số công ty bị xếp hạng ESG
thấp kéo trung bình xuống).
Nhìn chung, các công ty trong mẫu có xếp hạng ESG tập trung ở mức
trung bình đến khá (đa số nằm giữa 1st Qu.=16.3 và
3rd Qu.=27.9).
Kết luận: Các biến này cung cấp thêm thông tin đa
chiều về hiệu quả hoạt động (NetProfitMargin), định giá
(PS), sức khỏe tài chính (Current_Ratio), hiệu
quả điều chỉnh rủi ro (Sharpe_Ratio), và yếu tố bền vững
(ESG).
# 1. Kiểm tra nhanh các biến quan trọng đã được tạo/xử lý/đổi tên
cat("\n 1.1.3.11: Chọn lọc Biến cuối cùng và Lưu trữ \n")##
## 1.1.3.11: Chọn lọc Biến cuối cùng và Lưu trữ
## Kiểm tra tóm tắt một vài biến cuối cùng (trước khi chọn lọc):
summary(nyse_clean %>% select(Log_PE, Leverage_Ratio, Real_Return, Holding_Period, Risk_Level, Amount_Level))## Log_PE Leverage_Ratio Real_Return
## Min. :1.13 Min. : 1.103 Min. :-0.95232
## 1st Qu.:2.38 1st Qu.: 2.486 1st Qu.:-0.62084
## Median :2.69 Median : 3.439 Median : 0.16733
## Mean :2.88 Mean : 5.212 Mean : 0.08676
## 3rd Qu.:3.21 3rd Qu.: 6.692 3rd Qu.: 0.48586
## Max. :7.02 Max. :34.545 Max. :16.35331
## NA's :39751 NA's :2468
## Holding_Period Risk_Level Amount_Level
## Short-term (<=30d):135001 Low :133740 Small :142692
## Mid-term (31-180d):122731 Medium:133747 Medium:143246
## Long-term (>180d) :147526 High :137771 Large :119320
##
##
##
##
# 2. Tạo phiên bản "Cốt lõi" (32 biến) bằng cách loại bỏ các cột trung gian
# Liệt kê các cột trung gian không cần thiết cho phân tích cuối cùng:
# Date_Buy_Raw (đã có Date_Buy), Horizon_Days_Int (đã có Horizon_Days),
# Holding_Days (đã có Horizon_Days), PE_Positive (đã có Log_PE),
# Buy_Quarter_Num (đã có Buy_Quarter)
cols_to_remove <- c("Date_Buy_Raw", "Horizon_Days_Int", "Holding_Days", "PE_Positive", "Buy_Quarter_Num")
# Kiểm tra xem các cột này có tồn tại không trước khi loại bỏ (tránh lỗi)
cols_exist <- cols_to_remove %in% colnames(nyse_clean)
cols_to_remove_final <- cols_to_remove[cols_exist]
# Tạo nyse_clean_core bằng cách loại bỏ các cột trên
nyse_clean_core <- nyse_clean %>%
select(-all_of(cols_to_remove_final))
# 3. Kiểm tra tên và số lượng biến của cả hai phiên bản
cat("\nKiểm tra phiên bản đầy đủ (nyse_clean):\n")##
## Kiểm tra phiên bản đầy đủ (nyse_clean):
## Số biến: 37
## [1] "company" "sector" "Horizon_Days" "amount" "Date_Buy_Raw"
## [6] "price_BUY"
##
## Kiểm tra phiên bản cốt lõi (nyse_clean_core):
## Số biến: 32
## [1] "company" "sector" "Horizon_Days" "amount" "price_BUY"
## [6] "price_SELL"
# 4. Lưu cả hai đối tượng vào file .RData
# Hàm save() có thể lưu nhiều đối tượng cùng lúc
save(nyse_clean, nyse_clean_core, file = "nyse_processed_final.RData")
cat("\n✅ Đã hoàn tất Mục 1.1.3 và lưu cả hai phiên bản dữ liệu (nyse_clean, nyse_clean_core) vào file: nyse_processed_final.RData\n")##
## ✅ Đã hoàn tất Mục 1.1.3 và lưu cả hai phiên bản dữ liệu (nyse_clean, nyse_clean_core) vào file: nyse_processed_final.RData
Nhận xét:
Sau khi hoàn tất các bước xử lý, một phiên bản dữ liệu “cốt lõi” (nyse_clean_core) gồm 32 biến chính đã được tạo ra bằng cách loại bỏ 5 cột tính toán trung gian (Date_Buy_Raw, Horizon_Days_Int, Holding_Days, PE_Positive, Buy_Quarter_Num) khỏi phiên bản đầy đủ (nyse_clean, 37 biến). Cả hai phiên bản dữ liệu này đều được lưu vào tệp nyse_processed_final.RData. Phiên bản nyse_clean_core gọn gàng hơn và sẽ là cơ sở chính cho các phân tích, trong khi nyse_clean có thể được giữ lại để tham chiếu nếu cần xem xét các bước tính toán trung gian.
Do Fama (1970) đề xuất, EMH cho rằng giá cả chứng khoán luôn phản ánh
đầy đủ và ngay lập tức tất cả các thông tin sẵn có. Lý thuyết này tồn
tại ở ba dạng: yếu (giá quá khứ không dự báo được giá tương lai), trung
bình (thông tin công khai đã phản ánh vào giá), và mạnh (mọi thông tin,
kể cả nội bộ, đã phản ánh vào giá). Nếu EMH đúng, việc phân tích các chỉ
số tài chính (thông tin công khai) sẽ không giúp nhà đầu tư đạt được lợi
suất vượt trội một cách nhất quán. Tuy nhiên, nhiều nghiên cứu đã chỉ ra
các Bất thường Thị trường (Anomalies) như hiệu ứng quy mô (size
effect), hiệu ứng giá trị (value effect - cổ phiếu P/B thấp có lợi suất
cao hơn), hay hiệu ứng đà (momentum effect), thách thức tính đúng đắn
tuyệt đối của EMH. Phân tích về mối quan hệ giữa các chỉ số (PE, PB) và
lợi suất (Real_Return) sẽ kiểm chứng sự tồn tại của các bất
thường này trong bộ dữ liệu.
CAPM (Sharpe, 1964; Lintner, 1965) là mô hình cơ bản giải thích lợi
suất kỳ vọng của một tài sản dựa trên lãi suất phi rủi ro, phần bù rủi
ro thị trường và hệ số beta (đo lường rủi ro hệ thống). Tuy nhiên, CAPM
bị phê bình vì chỉ dựa vào một yếu tố rủi ro duy nhất. Các mô hình đa
nhân tố như Mô hình ba nhân tố Fama-French (1993) bổ sung thêm
yếu tố quy mô (SMB - Small Minus Big) và yếu tố giá trị (HML - High
Minus Low Book-to-Market) để giải thích tốt hơn sự biến động của lợi
suất. *Mô hình năm nhân tố Fama-French (2015)** tiếp tục bổ sung yếu tố
lợi nhuận (RMW - Robust Minus Weak) và yếu tố đầu tư (CMA - Conservative
Minus Aggressive). Mặc dù bộ dữ liệu không có đủ thông tin để tính toán
trực tiếp các nhân tố Fama-French, việc phân tích ảnh hưởng của các biến
đại diện như quy mô (amount), định giá
(Log_PE, PB), và hiệu quả sinh lời
(ROE, ROA) lên Real_Return là có
liên quan mật thiết đến các lý thuyết này.
Ngược lại với EMH giả định nhà đầu tư hoàn toàn lý trí, Tài chính hành vi (Kahneman & Tversky, 1979; Thaler, 1980) cho rằng các yếu tố tâm lý và sai lệch nhận thức (cognitive biases) ảnh hưởng đáng kể đến quyết định đầu tư và biến động thị trường. Các hiệu ứng như quá tự tin (overconfidence), tâm lý bầy đàn (herding), sợ thua lỗ (loss aversion) có thể dẫn đến việc định giá sai lệch và các bất thường thị trường. Phân tích về sự biến động của P/E (Mục 1.5.3, Biểu đồ 15) hay sự phân kỳ giữa vốn hóa và lợi nhuận (Biểu đồ 14) có thể phản ánh một phần các yếu tố tâm lý này.
Nhiều lý thuyết và thực nghiệm cho thấy các chỉ số tài chính cơ bản là công cụ quan trọng để đánh giá giá trị nội tại và dự báo lợi suất cổ phiếu.
Định giá (P/E, P/B, PS): Lý thuyết đầu tư giá
trị (Graham & Dodd) cho rằng mua cổ phiếu có tỷ số định giá thấp (so
với ngành hoặc lịch sử) có thể mang lại lợi suất cao hơn trong dài hạn.
Biến Log_PE và các tỷ số khác trong bộ dữ liệu sẽ được dùng
để kiểm chứng giả thuyết này.
Hiệu quả Sinh lời (ROE, ROA, NetProfitMargin):
Lợi nhuận cao và bền vững là động lực tăng trưởng giá trị doanh nghiệp.
Các chỉ số này phản ánh khả năng quản lý và tạo ra lợi nhuận từ vốn và
tài sản. Mối quan hệ giữa các chỉ số này và Real_Return sẽ
được phân tích.
Đòn bẩy (Leverage): Lý thuyết cấu trúc vốn
(Modigliani & Miller) cho thấy việc sử dụng nợ có thể khuếch đại lợi
nhuận (ROE) nhưng cũng làm tăng rủi ro tài chính. Tác động thực tế của
Leverage_Ratio lên Real_Return và
ROE sẽ được kiểm tra.
Các nghiên cứu thực nghiệm trên thị trường chứng khoán, đặc biệt là NYSE và các thị trường phát triển, đã cung cấp nhiều bằng chứng về các yếu tố ảnh hưởng đến lợi suất:
Yếu tố ảnh hưởng Lợi suất: Nhiều nghiên cứu thực
nghiệm (ví dụ: Al-Qenae et al., 2002; Al-Sharkas, 2004; Eita, 2012,
trích dẫn trong AB Academies, 2021; Nguyen & Pham, 2023) đã xác nhận
tác động của các biến số như EPS (+), Lãi suất (-), Lạm
phát (-/+ tùy bối cảnh), Quy mô doanh nghiệp (+/- tùy nghiên cứu), Tỷ
giá (+/- tùy ngành) lên giá cổ phiếu hoặc lợi suất. Nghiên cứu của ta sẽ
kiểm tra lại các mối quan hệ này trong bộ dữ liệu cụ thể đang phân
tích.
Hiệu quả Chiến lược đầu tư: Các nghiên cứu về
bất thường thị trường thường kiểm chứng hiệu quả của các chiến lược như
đầu tư giá trị (dựa trên P/B, P/E thấp), đầu tư theo đà (momentum - mua
cổ phiếu tăng giá gần đây), hoặc đầu tư theo quy mô (cổ phiếu nhỏ). Phân
tích của chúng ta về hiệu suất theo Holding_Period và mối
quan hệ giữa Log_PE và Real_Return sẽ cung cấp
góc nhìn về hiệu quả tương đối của các chiến lược này.
Quan hệ Rủi ro - Lợi suất: Mối quan hệ dương
giữa rủi ro (thường đo bằng Beta hoặc Độ lệch chuẩn - Volatility) và lợi
suất kỳ vọng là nền tảng của tài chính hiện đại. Tuy nhiên, một số
nghiên cứu thực nghiệm (đặc biệt là về “anomalies”) đôi khi tìm thấy mối
quan hệ yếu hoặc thậm chí nghịch đảo (cổ phiếu rủi ro thấp lại có lợi
suất cao hơn). Phân tích về Volatility_Buy và
Sharpe_Ratio sẽ đóng góp vào cuộc tranh luận này. Phát hiện
sơ bộ về tương quan dương mạnh giữa Sharpe_Ratio và
Volatility là một điểm cần thảo luận.
Ảnh hưởng của ESG: Các yếu tố Môi trường
(Environmental), Xã hội (Social), và Quản trị (Governance) ngày càng
được quan tâm. Nhiều nghiên cứu (chủ yếu gần đây) cho thấy các công ty
có xếp hạng ESG cao hơn có thể có hiệu quả hoạt động tốt
hơn và rủi ro thấp hơn trong dài hạn, mặc dù kết quả vẫn còn tranh cãi.
Chúng ta sẽ phân tích mối quan hệ giữa biến ESG và các chỉ
số hiệu suất (Real_Return, ROE) trong bộ dữ
liệu này.
Kết luận lược khảo: Các lý thuyết và nghiên cứu thực nghiệm cung cấp một khung phân tích phong phú về các yếu tố có thể ảnh hưởng đến lợi suất đầu tư trên sàn NYSE. Phân tích dữ liệu khám phá (EDA) trong các mục tiếp theo sẽ đối chiếu các phát hiện từ bộ dữ liệu cụ thể này với các cơ sở lý luận và bằng chứng thực nghiệm đã có, nhằm đưa ra những kết luận sâu sắc và có ý nghĩa.
# 1. Tải các thư viện cần thiết
library(dplyr)
library(knitr)
library(tibble)
# 2. Tải dữ liệu đã xử lý (phiên bản core - 32 biến)
load("nyse_processed_final.RData")
# 3. Chọn các biến định lượng quan trọng để tóm tắt
vars_to_summarize <- c("Real_Return", "Nominal_Return", "amount", "Horizon_Days",
"Volatility_Buy", "Sharpe_Ratio",
"Log_PE", "PB", "PS",
"ROE", "ROA", "NetProfitMargin",
"Leverage_Ratio", "Current_Ratio", "ESG")
# 4. Tính toán trực tiếp và trình bày dạng biến là hàng
cat(" 1.3.1.1: Tóm tắt Phân bố Trung tâm và Phân tán \n")## 1.3.1.1: Tóm tắt Phân bố Trung tâm và Phân tán
summary_stats_wide <- nyse_clean_core %>%
# Chọn các cột cần tóm tắt
select(all_of(vars_to_summarize)) %>%
# Tính toán từng thống kê mong muốn, xử lý NA
summarise(across(everything(),
list(
Min = ~ min(.x, na.rm = TRUE),
Q1 = ~ quantile(.x, 0.25, na.rm = TRUE),
Median = ~ median(.x, na.rm = TRUE),
Mean = ~ mean(.x, na.rm = TRUE),
Q3 = ~ quantile(.x, 0.75, na.rm = TRUE),
Max = ~ max(.x, na.rm = TRUE)
),
# Đặt tên cột kết quả dạng: TenBien_TenThongKe
.names = "{.col}_{.fn}"
))
# 5. Chuyển vị (Transpose) kết quả
# Chuyển tibble 1 hàng thành matrix, sau đó chuyển vị, rồi chuyển lại data frame
summary_transposed_df <- summary_stats_wide %>%
as.matrix() %>% # Chuyển thành ma trận
t() %>% # Chuyển vị (Transpose)
as.data.frame() # Chuyển lại thành data frame
# Đặt tên cột đầu tiên là "Value" (vì data frame chuyển vị chỉ có 1 cột)
colnames(summary_transposed_df) <- "Value"
# 6. Tách tên hàng (vd: "Real_Return_Min") thành tên biến và tên thống kê
summary_final_table <- summary_transposed_df %>%
rownames_to_column(var = "VarStat") %>% # Chuyển tên hàng thành cột VarStat
mutate(
Statistic = gsub(".*_", "", VarStat), # Lấy phần sau dấu "_" (Min, Q1...)
Variable = gsub("_.*", "", VarStat) # Lấy phần trước dấu "_" (Real_Return...)
) %>%
select(Variable, Statistic, Value) %>% # Chọn và sắp xếp lại cột
# Sắp xếp lại thứ tự thống kê cho chuẩn
mutate(Statistic = factor(Statistic, levels = c("Min", "Q1", "Median", "Mean", "Q3", "Max"))) %>%
# Chuyển lại dạng rộng để trình bày bảng (Biến là hàng, Thống kê là cột)
tidyr::pivot_wider(names_from = Statistic, values_from = Value) %>%
# Làm tròn số cuối cùng
mutate(across(where(is.numeric), ~ round(.x, 3))) %>%
# Sắp xếp theo tên biến
arrange(Variable)
# 7. In bảng kết quả bằng kable
kable(summary_final_table,
caption = "Bảng 1.3.1: Thống kê Mô tả Tổng quan cho các Biến Định lượng Chính",
col.names = c("Tên Biến", "Min", "Q1", "Median", "Mean", "Q3", "Max"), # Đặt tên cột rõ ràng
format = "pipe",
align = "l")| Tên Biến | Min | Q1 | Median | Mean | Q3 | Max |
|---|---|---|---|---|---|---|
| Current | 0.610 | 0.980 | 1.220 | 2.173 | 1.790 | 13.560 |
| ESG | 12.000 | 16.300 | 25.100 | 22.571 | 27.900 | 31.600 |
| Horizon | 1.000 | 15.000 | 90.000 | 187.085 | 300.000 | 720.000 |
| Leverage | 1.103 | 2.486 | 3.439 | 5.212 | 6.692 | 34.545 |
| Log | 1.131 | 2.383 | 2.686 | 2.879 | 3.211 | 7.018 |
| NetProfitMargin | -24.630 | 2.620 | 7.700 | 9.205 | 15.770 | 62.000 |
| Nominal | -0.872 | -0.028 | 0.014 | 0.071 | 0.111 | 8.847 |
| PB | 0.000 | 1.220 | 3.050 | 4.688 | 5.230 | 47.620 |
| PS | 0.160 | 0.470 | 1.710 | 2.725 | 3.180 | 24.490 |
| ROA | -12.990 | 1.740 | 5.710 | 5.596 | 7.990 | 38.130 |
| ROE | -99.490 | 8.830 | 16.100 | 15.644 | 26.030 | 57.250 |
| Real | -0.952 | -0.621 | 0.167 | 0.087 | 0.486 | 16.353 |
| Sharpe | 0.090 | 0.185 | 0.232 | 0.254 | 0.307 | 0.698 |
| Volatility | 0.090 | 0.185 | 0.232 | 0.254 | 0.307 | 0.698 |
| amount | 50.000 | 400.000 | 2000.000 | 8108.475 | 10000.000 | 50000.000 |
Nhận xét phân tích 1.3.1.1: Bảng 1.3.1 cung cấp một
cái nhìn tổng thể chi tiết về phân bố của 15 biến định lượng chính đã
được chọn lọc và xử lý (từ nyse_clean_core):
Xu hướng Trung tâm:
Lợi suất: Lợi suất Thực tế
(Real_Return) có Median = 0.167 (16.7%), cao
hơn đáng kể so với Mean = 0.087 (8.7%), cho thấy phân bố
lệch trái mạnh ở phần âm (do các khoản lỗ lớn). Lợi suất Danh nghĩa
(Nominal_Return) cũng tương tự (Median=0.014,
Mean=0.071).
Quy mô & Thời gian: Khoản đầu tư
amount phổ biến (Median) là 2000 USD, nhưng
Mean (8108 USD) cao hơn nhiều do các khoản đầu tư lớn. Thời
gian nắm giữ Horizon_Days phổ biến (Median) là
90 ngày (3 tháng), Mean là 187 ngày (~6 tháng).
Định giá: Log_PE (đã chuẩn hóa) có
Median = 2.686 (tương đương P/E ~14.7) và Mean
= 2.879, khá gần nhau, xác nhận hiệu quả chuẩn hóa. PB
(Giá/Giá trị sổ sách) có Median = 3.05, Mean =
4.69. PS (Giá/Doanh thu) có Median = 1.71,
Mean = 2.73. Cả PB và PS đều lệch
phải.
Hiệu quả HĐ: ROE có
Median = 16.1%, Mean = 15.6%. ROA
có Median = 5.7%, Mean = 5.6%.
NetProfitMargin có Median = 7.7%,
Mean = 9.2%. Các chỉ số hiệu quả này cho thấy mức sinh lời
trung bình khá, với ROE có vẻ đối xứng hơn ROA
và NetProfitMargin.
Rủi ro & Các chỉ số khác:
Volatility_Buy và Sharpe_Ratio có
Median và Mean rất gần nhau (lần lượt
~0.23/0.25 và ~0.23/0.25), cho thấy phân bố tương đối đối xứng.
Leverage_Ratio lệch phải (Median=3.4,
Mean=5.2). Current_Ratio lệch phải mạnh
(Median=1.2, Mean=2.2). ESG gần
đối xứng (Median=25.1, Mean=22.6).
Độ Phân tán:
Khoảng Min-Max cực lớn của Real_Return (-0.952 đến
16.353) và Nominal_Return (-0.872 đến 8.847) khẳng định rủi
ro và tiềm năng lợi nhuận/thua lỗ rất cao.
Các chỉ số định giá PB (0 đến 47.6) và
PS (0.16 đến 24.5) cũng có biên độ rất rộng.
ROE có biên độ rất lớn (-99.5% đến 57.3%), trong khi
ROA hẹp hơn (-13.0% đến 38.1%).
Leverage_Ratio (1.1 đến 34.5) và
Current_Ratio (0.6 đến 13.6) cũng cho thấy sự khác biệt lớn
về cấu trúc tài chính giữa các công ty.
Kết luận Sơ bộ: Bộ dữ liệu phản ánh một thị trường đầu tư năng động với sự đa dạng lớn về lợi suất, rủi ro, định giá và hiệu quả hoạt động. Sự tồn tại của các phân bố lệch và biên độ dao động rộng cho thấy tầm quan trọng của việc phân tích sâu hơn về outliers, hình dạng phân phối và kiểm định sự khác biệt giữa các nhóm để rút ra kết luận đáng tin cậy.
# 1. Tính toán độ lệch chuẩn (SD) cho các biến đã chọn ở trên
# Sử dụng summarise() và across() để tính SD cho nhiều cột
sd_stats <- nyse_clean_core %>%
summarise(across(all_of(vars_to_summarize),
~ sd(.x, na.rm = TRUE), # Hàm tính SD, bỏ qua NA
.names = "SD_{.col}")) # Đặt tên cột kết quả là SD_TênBiến
# 2. Chuyển kết quả sang dạng dài để trình bày bằng kable
sd_table <- sd_stats %>%
tidyr::pivot_longer(everything(), names_to = "Variable", values_to = "Standard_Deviation") %>%
# Làm tròn giá trị SD
mutate(Standard_Deviation = round(Standard_Deviation, 3)) %>%
# Sắp xếp theo tên biến cho dễ theo dõi
arrange(Variable)
# 3. Trình bày bảng Độ lệch chuẩn
cat("\n 1.3.1.2: Tính toán Độ lệch chuẩn \n")##
## 1.3.1.2: Tính toán Độ lệch chuẩn
kable(sd_table,
caption = "Bảng 1.3.2: Độ lệch chuẩn của các Biến Định lượng Chính",
col.names = c("Tên Biến (Đã chuẩn hóa)", "Độ lệch chuẩn (SD)"),
format = "pipe",
align = "l")| Tên Biến (Đã chuẩn hóa) | Độ lệch chuẩn (SD) |
|---|---|
| SD_Current_Ratio | 2.564 |
| SD_ESG | 6.510 |
| SD_Horizon_Days | 210.703 |
| SD_Leverage_Ratio | 4.986 |
| SD_Log_PE | 0.845 |
| SD_NetProfitMargin | 10.407 |
| SD_Nominal_Return | 0.299 |
| SD_PB | 5.909 |
| SD_PS | 3.601 |
| SD_ROA | 5.978 |
| SD_ROE | 17.479 |
| SD_Real_Return | 0.774 |
| SD_Sharpe_Ratio | 0.098 |
| SD_Volatility_Buy | 0.098 |
| SD_amount | 12774.429 |
Nhận xét phân tích 1.3.1.2:
Bảng 1.3.2 định lượng mức độ phân tán (biến động) tuyệt đối của từng biến thông qua Độ lệch chuẩn (SD):
Rủi ro/Biến động Lợi suất:
Real_Return (SD = 0.774) và Nominal_Return (SD
= 0.299) có độ lệch chuẩn rất lớn so với giá trị trung bình tương ứng
(Mean Real_Return = 0.087, Mean Nominal_Return
= 0.071 từ Bảng 1.3.1). Điều này tái khẳng định mức độ rủi ro và sự biến
động cực kỳ cao của lợi suất đầu tư trên thị trường cổ phiếu NYSE trong
mẫu dữ liệu này.
Biến động Quy mô & Thời gian:
amount (SD = 12,774 USD) có độ lệch chuẩn thậm chí còn lớn
hơn giá trị trung bình (Mean = 8,108 USD), cho thấy sự phân tán cực mạnh
trong quy mô các khoản đầu tư. Horizon_Days (SD = 210.7
ngày) cũng có độ biến động đáng kể so với trung bình (Mean = 187
ngày).
Biến động Rủi ro (Volatility):
Volatility_Buy (SD = 0.098) cho thấy mức độ rủi ro (đo bằng
Volatility) cũng có sự khác biệt đáng kể giữa các cổ phiếu/thời điểm
mua, mặc dù SD tương đối nhỏ hơn so với giá trị trung bình (Mean =
0.254).
Biến động Định giá: Log_PE (SD =
0.845) có độ lệch chuẩn tương đối nhỏ so với giá trị trung bình (Mean =
2.88), cho thấy sau khi chuẩn hóa logarit, mức độ biến động tương đối
của định giá P/E đã giảm bớt và tập trung hơn. Ngược lại, các chỉ số
định giá gốc như PB (SD = 5.91) và PS (SD =
3.60) vẫn cho thấy sự phân tán tuyệt đối rất lớn.
Biến động Hiệu quả HĐ: ROE (SD =
17.48) có độ lệch chuẩn rất cao, thậm chí lớn hơn giá trị trung bình
(Mean = 15.6), phản ánh sự khác biệt cực lớn về hiệu quả sinh lời giữa
các công ty/giai đoạn. ROA (SD = 5.98) và
NetProfitMargin (SD = 10.41) cũng có độ lệch chuẩn đáng kể
so với trung bình tương ứng (Mean ROA = 5.6, Mean NetProfitMargin =
9.2).
Độ ổn định tương đối: Các biến như
Sharpe_Ratio (SD = 0.098) và ESG (SD = 6.51)
có độ lệch chuẩn tương đối nhỏ hơn so với giá trị trung bình của chúng,
cho thấy mức độ biến động thấp hơn so với các chỉ số lợi suất hay hiệu
quả hoạt động. Current_Ratio (SD = 2.56) và
Leverage_Ratio (SD = 4.99) cũng có độ lệch chuẩn đáng
kể.
Kết luận: Độ lệch chuẩn xác nhận mức độ biến
động cao và rủi ro đáng kể đối với các biến liên quan đến lợi suất, quy
mô đầu tư và hiệu quả hoạt động. Các chỉ số định giá (trừ
Log_PE) cũng phân tán mạnh. Các yếu tố như Sharpe Ratio và
ESG có vẻ ổn định hơn trong bộ dữ liệu này.
# 1. Tải các thư viện cần thiết
library(dplyr)
library(knitr)
library(tidyr)
# 3. Tính toán và trình bày bảng tần suất cho từng biến Factor quan trọng
cat("1.3.2.1: Bảng Tần suất Biến Phân loại\n")## 1.3.2.1: Bảng Tần suất Biến Phân loại
# Hàm trợ giúp để tạo bảng tần suất đẹp
create_freq_table <- function(data, var_name, caption_text) {
var_sym <- sym(var_name) # Chuyển tên biến (chuỗi) thành biểu tượng
freq_table <- data %>%
count({{ var_sym }}, name = "SoLuong") %>% # Đếm số lượng theo biến
# Kiểm tra xem có NA không, nếu có thì báo cáo
mutate(TyLe_PhanTram = round((SoLuong / sum(SoLuong)) * 100, 2)) %>% # Tính tỷ lệ %
arrange(desc(SoLuong)) # Sắp xếp giảm dần theo số lượng
# In bảng bằng kable
print(kable(freq_table,
caption = caption_text,
col.names = c(var_name, "Số lượng", "Tỷ lệ (%)"),
format = "pipe", align = "l"))
cat("\n") # Thêm dòng trống
}
# 4. Áp dụng hàm cho các biến Factor đã tạo/chuẩn hóa
create_freq_table(nyse_clean_core, "sector", "Bảng 1.3.3: Phân bổ Giao dịch theo Ngành")##
##
## Table: Bảng 1.3.3: Phân bổ Giao dịch theo Ngành
##
## |sector |Số lượng |Tỷ lệ (%) |
## |:------|:--------|:---------|
## |RETAIL |96269 |23.75 |
## |TECH |92401 |22.80 |
## |BANK |84757 |20.91 |
## |AUTO |79836 |19.70 |
## |FMCG |51995 |12.83 |
create_freq_table(nyse_clean_core, "investment", "Bảng 1.3.4: Phân bổ Giao dịch theo Kết quả Đầu tư")##
##
## Table: Bảng 1.3.4: Phân bổ Giao dịch theo Kết quả Đầu tư
##
## |investment |Số lượng |Tỷ lệ (%) |
## |:----------|:--------|:---------|
## |BAD |264440 |65.25 |
## |GOOD |140818 |34.75 |
create_freq_table(nyse_clean_core, "Holding_Period", "Bảng 1.3.5: Phân bổ Giao dịch theo Thời gian Nắm giữ")##
##
## Table: Bảng 1.3.5: Phân bổ Giao dịch theo Thời gian Nắm giữ
##
## |Holding_Period |Số lượng |Tỷ lệ (%) |
## |:------------------|:--------|:---------|
## |Long-term (>180d) |147526 |36.40 |
## |Short-term (<=30d) |135001 |33.31 |
## |Mid-term (31-180d) |122731 |30.28 |
create_freq_table(nyse_clean_core, "Risk_Level", "Bảng 1.3.6: Phân bổ Giao dịch theo Mức độ Rủi ro")##
##
## Table: Bảng 1.3.6: Phân bổ Giao dịch theo Mức độ Rủi ro
##
## |Risk_Level |Số lượng |Tỷ lệ (%) |
## |:----------|:--------|:---------|
## |High |137771 |34 |
## |Medium |133747 |33 |
## |Low |133740 |33 |
create_freq_table(nyse_clean_core, "Amount_Level", "Bảng 1.3.7: Phân bổ Giao dịch theo Quy mô Đầu tư")##
##
## Table: Bảng 1.3.7: Phân bổ Giao dịch theo Quy mô Đầu tư
##
## |Amount_Level |Số lượng |Tỷ lệ (%) |
## |:------------|:--------|:---------|
## |Medium |143246 |35.35 |
## |Small |142692 |35.21 |
## |Large |119320 |29.44 |
Nhận xét phän tích 1.3.2.1:
Phân bổ theo Ngành (sector - Bảng
1.3.3):
Kết quả cho thấy sự tập trung đáng kể vào ba ngành chính:
RETAIL (Bán lẻ - 23.75%), TECH (Công nghệ -
22.80%), và BANK (Ngân hàng - 20.91%). Ba ngành này chiếm
gần 2/3 tổng số giao dịch (∼67.4%).
Ngành AUTO (Ô tô - 19.70%) cũng có tỷ trọng đáng
kể.
Ngành FMCG (Hàng tiêu dùng nhanh - 12.83%) có tần
suất thấp nhất.
Sự phân bổ này cho thấy bộ dữ liệu có tính đại diện cho các lĩnh vực kinh tế chính của thị trường NYSE, đặc biệt là các ngành dịch vụ, công nghệ và tài chính, nhưng ngành FMCG có thể ít được đại diện hơn.
Phân bổ theo Kết quả Đầu tư (investment -
Bảng 1.3.4):
Bảng này cho thấy sự mất cân bằng lớp (class imbalance) rất rõ
rệt. Các khoản đầu tư được phân loại là BAD (Thua lỗ/Kém
hiệu quả) chiếm tỷ trọng áp đảo với 65.25%, gấp gần đôi so với nhóm
GOOD (Sinh lời/Hiệu quả) chỉ chiếm 34.75%.
Điều này phản ánh thực tế rằng việc đạt được lợi nhuận thực tế
vượt trội (định nghĩa của GOOD) trên thị trường chứng khoán
là một thách thức, và số lượng giao dịch không thành công thường nhiều
hơn. Sự mất cân bằng này cần được lưu ý khi xây dựng các mô hình dự đoán
biến investment.
Phân bổ theo Thời gian Nắm giữ
(Holding_Period - Bảng 1.3.5):
Kết quả tái khẳng định sự phân bổ tương đối đồng đều giữa ba
chiến lược đã tạo ra ở Mục 1.1.3.6: Long-term (>180d)
chiếm tỷ trọng lớn nhất (36.40%), tiếp theo là
Short-term (<=30d) (33.31%) và
Mid-term (31-180d) (30.28%).
Mặc dù Long-term chiếm ưu thế nhẹ, sự hiện diện đáng
kể của cả ba nhóm cho phép phân tích so sánh hiệu quả của các chiến lược
thời gian khác nhau.
Phân bổ theo Mức độ Rủi ro (Risk_Level -
Bảng 1.3.6):
Do biến Risk_Level được tạo ra dựa trên phân vị
(terciles - chia 3 phần bằng nhau), kết quả tần suất cho thấy sự phân bổ
cực kỳ đồng đều giữa ba nhóm: High (34%),
Medium (33%), và Low (33%).
Điều này đảm bảo rằng khi chúng ta so sánh hiệu suất giữa các nhóm rủi ro, mỗi nhóm đều có số lượng quan sát đủ lớn và tương đương nhau, giúp kết quả so sánh đáng tin cậy hơn.
Phân bổ theo Quy mô Đầu tư (Amount_Level -
Bảng 1.3.7):
Tương tự như Risk_Level, biến
Amount_Level cũng được tạo từ phân vị. Kết quả cho thấy
nhóm Medium (35.35%) và Small (35.21%) có tỷ
trọng lớn hơn một chút so với nhóm Large (29.44%).
Sự phân bổ này vẫn đủ cân bằng để phân tích ảnh hưởng của quy mô
giao dịch lên các yếu tố khác. Việc nhóm Large có tỷ lệ
thấp hơn một chút có thể phản ánh thực tế rằng các giao dịch với số tiền
rất lớn (>5000 USD theo ngưỡng phân vị) ít phổ biến hơn.
Kết luận: Phân tích tần suất các biến phân loại cho
thấy bộ dữ liệu có tính đa dạng về ngành nghề và chiến lược đầu tư. Tuy
nhiên, có sự mất cân bằng đáng kể về kết quả đầu tư (đa số là
BAD). Các biến phân loại dựa trên phân vị
(Risk_Level, Amount_Level) có sự phân bổ đồng
đều, thuận lợi cho các phân tích so sánh nhóm sau này.
# 1. Chọn các biến định lượng quan trọng cần phân tích phân vị
vars_for_quantile <- c("Real_Return", "amount", "Volatility_Buy",
"Log_PE", "Leverage_Ratio", "Sharpe_Ratio")
# 2. Tính toán các phân vị thường dùng (0%, 25%, 50%, 75%, 100%)
# Sử dụng sapply để áp dụng hàm quantile cho từng cột đã chọn
quantile_results <- sapply(nyse_clean_core[vars_for_quantile],
quantile,
probs = c(0, 0.25, 0.5, 0.75, 1),
na.rm = TRUE) # Bỏ qua NA
# 3. Làm tròn kết quả và chuyển đổi thành data frame để trình bày
quantile_df <- as.data.frame(round(quantile_results, 3))
# Thêm cột tên Phân vị (0%, 25%...)
quantile_df <- tibble::rownames_to_column(quantile_df, var = "Percentile")
# 4. Trình bày bảng Phân vị bằng kable
cat("\n--- 1.3.2.2: Phân tích Phân vị Biến Định lượng ---\n")##
## --- 1.3.2.2: Phân tích Phân vị Biến Định lượng ---
kable(quantile_df,
caption = "Bảng 1.3.8: Các điểm phân vị của các Biến Định lượng Chính",
# Tên cột sẽ là tên biến, hàng là tên phân vị
format = "pipe",
align = "l")| Percentile | Real_Return | amount | Volatility_Buy | Log_PE | Leverage_Ratio | Sharpe_Ratio |
|---|---|---|---|---|---|---|
| 0% | -0.952 | 50 | 0.090 | 1.131 | 1.103 | 0.090 |
| 25% | -0.621 | 400 | 0.185 | 2.383 | 2.486 | 0.185 |
| 50% | 0.167 | 2000 | 0.232 | 2.686 | 3.439 | 0.232 |
| 75% | 0.486 | 10000 | 0.307 | 3.211 | 6.692 | 0.307 |
| 100% | 16.353 | 50000 | 0.698 | 7.018 | 34.545 | 0.698 |
Nhận xét Phân tích 1.3.2.2:
Lợi suất Thực tế (Real_Return):
Phạm vi cực đoan: Từ -0.952 (-95.2%) đến 16.353 (+1635.3%).
Tập trung chính: 50% dữ liệu ở giữa (IQR) nằm trong khoảng khá rộng từ -0.621 (Q1) đến 0.486 (Q3).
Điểm giữa (Median): 0.167 (16.7%), xác nhận đa số
giao dịch có lãi thực.
Quy mô Giao dịch (amount):
Phạm vi: Từ 50 USD đến 50,000 USD.
Tập trung chính: 50% giao dịch ở giữa có quy mô từ 400 USD (Q1) đến 10,000 USD (Q3).
Điểm giữa (Median): 2,000 USD. Điều này cho thấy đa
số giao dịch có quy mô nhỏ đến trung bình.
Rủi ro (Volatility_Buy):
Phạm vi: Từ 0.090 đến 0.698.
Tập trung chính: 50% giao dịch ở giữa có độ biến động từ 0.185 (Q1) đến 0.307 (Q3).
Điểm giữa (Median): 0.232. Phân bố tương đối hẹp và
tập trung quanh mức rủi ro thấp đến trung bình.
Định giá (Log_PE):
Phạm vi (sau log): Từ 1.131 đến 7.018.
Tập trung chính: 50% ở giữa nằm từ 2.383 (Q1, P/E ~10.8) đến 3.211 (Q3, P/E ~24.8).
Điểm giữa (Median): 2.686 (P/E ~14.7). Phân bố khá
tập trung sau khi chuẩn hóa.
Đòn bẩy (Leverage_Ratio):
Phạm vi: Từ 1.103 đến 34.545.
Tập trung chính: 50% ở giữa nằm từ 2.486 (Q1) đến 6.692 (Q3).
Điểm giữa (Median): 3.439. Cho thấy mức đòn bẩy phổ
biến là khoảng 3.4 lần.
Hiệu quả Điều chỉnh Rủi ro
(Sharpe_Ratio):
Phạm vi: Từ 0.090 đến 0.698 (luôn dương).
Tập trung chính: 50% ở giữa nằm trong khoảng hẹp từ 0.185 (Q1) đến 0.307 (Q3).
Điểm giữa (Median): 0.232. Phân bố rất tập
trung.
Kết luận: Phân tích phân vị xác nhận lại biên độ dao
động lớn của lợi suất và quy mô đầu tư. Các chỉ số như rủi ro
(Volatility_Buy), định giá (Log_PE), và hiệu
quả điều chỉnh rủi ro (Sharpe_Ratio) có phân bố tập trung
hơn. Khoảng IQR cung cấp thước đo hữu ích về phạm vi bình thường của
từng biến.
##
## 1.3.2.3: Tần suất Lợi suất Thực tế Dương/Âm
return_sign_freq <- nyse_clean_core %>%
# Tạo biến mới 'Return_Sign' dựa trên Real_Return
mutate(Return_Sign = case_when(
Real_Return > 0 ~ "Lợi suất Dương (>0)",
Real_Return <= 0 ~ "Lợi suất Âm (<=0)",
TRUE ~ "NA" # Xử lý trường hợp Real_Return là NA (nếu có)
)) %>%
# Đếm tần suất theo biến mới tạo
count(Return_Sign, name = "SoLuong") %>%
# Tính tỷ lệ phần trăm
mutate(TyLe_PhanTram = round((SoLuong / sum(SoLuong)) * 100, 2))
# 2. Trình bày bảng kết quả
kable(return_sign_freq,
caption = "Bảng 1.3.9: Tần suất Giao dịch theo Dấu của Lợi suất Thực tế",
col.names = c("Dấu Lợi suất Thực tế", "Số lượng", "Tỷ lệ (%)"),
format = "pipe", align = "l")| Dấu Lợi suất Thực tế | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Lợi suất Dương (>0) | 229767 | 56.7 |
| Lợi suất Âm (<=0) | 175491 | 43.3 |
Nhận xét phân tích 1.3.2.3:
Bảng 1.3.9 phân loại các giao dịch dựa trên dấu của Lợi suất Thực tế
(Real_Return), cung cấp một góc nhìn trực diện về tỷ lệ
thành công/thất bại sau khi đã điều chỉnh lạm phát:
Tỷ lệ Lãi/Lỗ Thực tế: Kết quả cho thấy có
56.7% (229,767 giao dịch) đạt được lợi suất thực tế
dương (Real_Return > 0), nghĩa là làm tăng sức mua cho
nhà đầu tư. Ngược lại, 43.3% (175,491 giao dịch) có lợi
suất thực tế âm hoặc bằng không, tức là làm giảm hoặc không thay đổi sức
mua.
So sánh với investment: Tỷ lệ lợi
suất thực tế dương (56.7%) cao hơn đáng kể so với tỷ lệ các khoản đầu tư
được phân loại là GOOD (34.75% - Bảng 1.3.4). Điều này cho
thấy rằng tiêu chí để phân loại một khoản đầu tư là GOOD
trong bộ dữ liệu này có thể khắt khe hơn, không chỉ đơn thuần là
Real_Return > 0 mà có thể yêu cầu một mức lợi suất tối
thiểu nào đó hoặc kết hợp thêm các yếu tố khác. Tuy nhiên, việc đa số
giao dịch (56.7%) vẫn có lãi thực là một tín hiệu tích cực về tiềm năng
sinh lời chung của thị trường được mô phỏng.
Risk_Level)# 1. Trình bày lại bảng tần suất cho Risk_Level (đã tính ở 1.1.3.8)
cat("\n 1.3.2.4: Tần suất Đầu tư theo Ngưỡng Rủi ro \n")##
## 1.3.2.4: Tần suất Đầu tư theo Ngưỡng Rủi ro
# (Biến risk_level_freq đã được tạo ở Mục 1.1.3.8)
# In lại bảng đó
if(exists("risk_level_freq")){
kable(risk_level_freq,
caption = "Bảng 1.3.10: Phân bổ Giao dịch theo Mức độ Rủi ro (Nhắc lại)",
col.names = c("Mức Rủi ro", "Số lượng", "Tỷ lệ (%)"),
format = "pipe", align = "l")
} else {
cat("Biến risk_level_freq chưa được tạo. Vui lòng chạy lại Mục 1.1.3.8.\n")
}| Mức Rủi ro | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Low | 133740 | 33 |
| Medium | 133747 | 33 |
| High | 137771 | 34 |
Nhận xét phân tích 1.3.2.4:
Bảng 1.3.10 tái khẳng định sự phân bổ đồng đều của các giao dịch giữa
ba nhóm rủi ro (Low, Medium,
High) do biến Risk_Level được tạo ra dựa trên
phân vị. Mỗi nhóm chiếm khoảng 1/3 tổng số quan sát, tạo điều kiện thuận
lợi cho việc so sánh hiệu suất và đặc điểm giữa các nhóm rủi ro khác
nhau trong các phân tích tiếp theo.
# 1. Tải thư viện cần thiết
library(dplyr)
library(knitr)
library(moments) # Chứa hàm skewness() và kurtosis()
# 2. Chọn các biến để tính độ xiên
vars_for_shape <- c("Real_Return", "Nominal_Return", "amount", "Horizon_Days",
"Volatility_Buy", "Sharpe_Ratio", "Log_PE", "PB", "PS",
"ROE", "ROA", "NetProfitMargin", "Leverage_Ratio",
"Current_Ratio", "ESG")
# 3. Tính toán Độ xiên (Skewness) cho từng biến
# Sử dụng sapply để áp dụng hàm skewness
skewness_values <- sapply(nyse_clean_core[vars_for_shape],
skewness,
na.rm = TRUE) # Bỏ qua NA
# 5. Tạo bảng kết quả độ xiên
skewness_table <- data.frame(
Variable = names(skewness_values),
Skewness = round(skewness_values, 3)
) %>% arrange(Variable) # Sắp xếp theo tên biến
# 6. Trình bày bảng Độ xiên
cat(" 1.3.3.1: Đo lường Độ xiên (Skewness) \n")## 1.3.3.1: Đo lường Độ xiên (Skewness)
kable(skewness_table,
caption = "Bảng 1.3.11: Độ xiên của các Biến Định lượng Chính",
col.names = c("Tên Biến", "Độ xiên (Skewness)"),
format = "pipe",
align = "l")| Tên Biến | Độ xiên (Skewness) | |
|---|---|---|
| Current_Ratio | Current_Ratio | 2.831 |
| ESG | ESG | -0.246 |
| Horizon_Days | Horizon_Days | 1.108 |
| Leverage_Ratio | Leverage_Ratio | 2.747 |
| Log_PE | Log_PE | 1.665 |
| NetProfitMargin | NetProfitMargin | 0.199 |
| Nominal_Return | Nominal_Return | 7.522 |
| PB | PB | 3.075 |
| PS | PS | 2.593 |
| ROA | ROA | 0.958 |
| ROE | ROE | -2.013 |
| Real_Return | Real_Return | 2.752 |
| Sharpe_Ratio | Sharpe_Ratio | 1.104 |
| Volatility_Buy | Volatility_Buy | 1.104 |
| amount | amount | 2.140 |
# 7. Diễn giải sơ bộ về độ xiên:
# Skewness = 0: Đối xứng hoàn hảo (như phân phối chuẩn)
# Skewness > 0: Lệch phải (đuôi kéo dài về phía giá trị lớn)
# Skewness < 0: Lệch trái (đuôi kéo dài về phía giá trị nhỏ)
# |Skewness| > 1: Độ lệch đáng kểNhận xét phân tích 1.3.3.1:
Bảng 1.3.11 định lượng mức độ đối xứng của phân phối cho các biến chính:
Lệch Phải Mạnh (|Skewness| > 1): Rất nhiều
biến thể hiện độ lệch phải đáng kể, bao gồm Nominal_Return
(7.52), PB (3.08), PS (2.59),
amount (2.14), Leverage_Ratio (2.75),
Current_Ratio (2.83), Real_Return (2.75),
Log_PE (1.67), Horizon_Days (1.11),
Sharpe_Ratio (1.10), và Volatility_Buy (1.10).
Độ lệch phải dương cho thấy đuôi phân phối kéo dài về phía các giá trị
lớn (ví dụ: các khoản lãi rất cao, P/E rất cao, số tiền đầu tư rất lớn),
và phần lớn dữ liệu tập trung ở phía giá trị thấp hơn.
Lệch Trái Mạnh (|Skewness| <- 1): Chỉ có
ROE (-2.01) thể hiện độ lệch trái đáng kể, cho thấy có một
số công ty/giai đoạn với ROE cực kỳ thấp (âm sâu) kéo đuôi phân phối về
phía giá trị nhỏ.
Gần Đối xứng : Các biến ROA (0.96),
NetProfitMargin (0.20), và ESG (-0.25) có độ
lệch thấp hơn, gần với phân phối đối xứng hơn, mặc dù ROA
vẫn có độ lệch phải nhẹ đáng kể.
Kết luận: Hầu hết các biến quan trọng trong bộ
dữ liệu đều có phân phối không đối xứng đáng kể, chủ
yếu là lệch phải. Điều này vi phạm giả định về tính chuẩn và cần được
lưu ý khi lựa chọn phương pháp phân tích hoặc cần xem xét các phép biến
đổi dữ liệu bổ sung (ngoài Log_PE đã làm).
# 1. Tính toán Độ nhọn (Kurtosis) cho các biến đã chọn
# Lưu ý: Hàm kurtosis() trong gói 'moments' tính Excess Kurtosis
# (Kurtosis - 3). Giá trị > 0 nghĩa là nhọn hơn phân phối chuẩn.
cat("\n 1.3.3.2: Đo lường Độ nhọn (Kurtosis) \n")##
## 1.3.3.2: Đo lường Độ nhọn (Kurtosis)
kurtosis_values <- sapply(nyse_clean_core[vars_for_shape],
kurtosis,
na.rm = TRUE)
# 2. Tạo bảng kết quả độ nhọn
kurtosis_table <- data.frame(
Variable = names(kurtosis_values),
Excess_Kurtosis = round(kurtosis_values, 3)
) %>% arrange(Variable)
# 3. Trình bày bảng Độ nhọn
kable(kurtosis_table,
caption = "Bảng 1.3.12: Độ nhọn (Excess Kurtosis) của các Biến Định lượng Chính",
col.names = c("Tên Biến", "Độ nhọn (Kurtosis - 3)"),
format = "pipe",
align = "l")| Tên Biến | Độ nhọn (Kurtosis - 3) | |
|---|---|---|
| Current_Ratio | Current_Ratio | 10.587 |
| ESG | ESG | 1.553 |
| Horizon_Days | Horizon_Days | 3.044 |
| Leverage_Ratio | Leverage_Ratio | 11.590 |
| Log_PE | Log_PE | 7.610 |
| NetProfitMargin | NetProfitMargin | 4.563 |
| Nominal_Return | Nominal_Return | 117.299 |
| PB | PB | 14.988 |
| PS | PS | 10.195 |
| ROA | ROA | 7.187 |
| ROE | ROE | 12.810 |
| Real_Return | Real_Return | 31.866 |
| Sharpe_Ratio | Sharpe_Ratio | 4.390 |
| Volatility_Buy | Volatility_Buy | 4.390 |
| amount | amount | 7.052 |
# 4. Diễn giải sơ bộ về độ nhọn (Excess Kurtosis):
# Kurtosis = 0: Độ nhọn tương tự phân phối chuẩn (Mesokurtic)
# Kurtosis > 0: Nhọn hơn phân phối chuẩn, đuôi dày hơn (Leptokurtic - rủi ro outlier cao)
# Kurtosis < 0: Bẹt hơn phân phối chuẩn, đuôi mỏng hơn (Platykurtic)Nhận xét phân tích 1.3.3.2:
Bảng 1.3.12 đo lường độ “nhọn” của đỉnh và độ “dày” của đuôi phân phối so với phân phối chuẩn (Excess Kurtosis > 0 là nhọn hơn và đuôi dày hơn - Leptokurtic):
Độ nhọn Cực cao (Kurtosis >> 3):
Nominal_Return (117.3) và Real_Return (31.9)
có độ nhọn cực kỳ cao. Điều này cho thấy phân phối của lợi suất tập
trung rất mạnh quanh giá trị trung tâm nhưng lại có phần đuôi rất “dày”
(heavy tails), nghĩa là các sự kiện lợi nhuận/thua lỗ cực đoan
(outliers) xảy ra thường xuyên hơn nhiều so với dự đoán của phân phối
chuẩn. Đây là đặc điểm phổ biến của dữ liệu lợi suất tài chính.
Độ nhọn Cao (Kurtosis > 3): Nhiều biến khác
cũng có độ nhọn cao hơn đáng kể so với phân phối chuẩn, bao gồm
PB (15.0), Leverage_Ratio (11.6),
Current_Ratio (10.6), PS (10.2),
Log_PE (7.6), amount (7.1), ROA
(7.2), ROE (12.8), NetProfitMargin (4.6),
Volatility_Buy (4.4), Sharpe_Ratio (4.4), và
Horizon_Days (3.0). Điều này cho thấy các biến này cũng có
xu hướng tập trung quanh trung tâm và có đuôi dày hơn chuẩn.
Gần Chuẩn: Chỉ có ESG (1.55) có độ
nhọn gần với phân phối chuẩn hơn cả.
Kết luận: Hầu hết các biến định lượng chính đều có phân phối Leptokurtic (nhọn hơn và đuôi dày hơn chuẩn). Điều này hàm ý rằng rủi ro xảy ra các giá trị cực đoan (outliers) là cao hơn so với giả định phân phối chuẩn, một yếu tố quan trọng cần xem xét trong quản lý rủi ro và mô hình hóa.
# 1. Lưu ý về kích thước mẫu:
# Các kiểm định chuẩn như Shapiro-Wilk rất nhạy với cỡ mẫu lớn.
# Với N > 400,000, kiểm định gần như chắc chắn sẽ bác bỏ giả thuyết H0 (phân phối chuẩn), ngay cả khi độ lệch không quá lớn về mặt thực tế.
# Do đó, ta sẽ thực hiện kiểm định trên một mẫu con nhỏ (ví dụ: 5000)
# để có đánh giá sơ bộ, kết hợp với phân tích Skewness, Kurtosis và QQ-Plot.
cat("\n 1.3.3.3: Kiểm định Tính Phân phối Chuẩn (trên mẫu con) \n")##
## 1.3.3.3: Kiểm định Tính Phân phối Chuẩn (trên mẫu con)
set.seed(123) # Đảm bảo tính lặp lại của mẫu ngẫu nhiên
sample_size <- 5000
if (nrow(nyse_clean_core) >= sample_size) {
nyse_sample <- nyse_clean_core %>% sample_n(sample_size)
# 2. Thực hiện Shapiro-Wilk test cho Real_Return và Log_PE trên mẫu con
# Giả thuyết H0: Dữ liệu tuân theo phân phối chuẩn
# Nếu p-value < 0.05, bác bỏ H0
# Kiểm định cho Real_Return (loại bỏ NA nếu có)
shapiro_test_real_return <- shapiro.test(na.omit(nyse_sample$Real_Return))
cat("Kết quả Shapiro-Wilk Test cho Real_Return (mẫu N=5000):\n")
print(shapiro_test_real_return)
# Kiểm định cho Log_PE (loại bỏ NA nếu có)
shapiro_test_log_pe <- shapiro.test(na.omit(nyse_sample$Log_PE))
cat("\nKết quả Shapiro-Wilk Test cho Log_PE (mẫu N=5000):\n")
print(shapiro_test_log_pe)
} else {
cat("Kích thước mẫu gốc nhỏ hơn 5000, không thể lấy mẫu con.\n")
}## Kết quả Shapiro-Wilk Test cho Real_Return (mẫu N=5000):
##
## Shapiro-Wilk normality test
##
## data: na.omit(nyse_sample$Real_Return)
## W = 0.77222, p-value < 2.2e-16
##
##
## Kết quả Shapiro-Wilk Test cho Log_PE (mẫu N=5000):
##
## Shapiro-Wilk normality test
##
## data: na.omit(nyse_sample$Log_PE)
## W = 0.87725, p-value < 2.2e-16
# 3. Kết luận sơ bộ từ p-value:
# Nếu p-value rất nhỏ (thường < 2.2e-16), có bằng chứng mạnh mẽ để bác bỏ giả thuyết phân phối chuẩn.Nhận xét phân tích 1.3.3.3:
Kết quả kiểm định Shapiro-Wilk trên mẫu con (N=5000) cho cả
Real_Return và Log_PE đều cho giá trị
p-value cực kỳ nhỏ (< 2.2e-16).
Bác bỏ Giả thuyết Chuẩn: Với p-value nhỏ hơn mức
ý nghĩa thông thường (ví dụ: 0.05), chúng ta có bằng chứng thống kê rất
mạnh mẽ để bác bỏ giả thuyết H0 rằng dữ liệu của
Real_Return và Log_PE (ngay cả sau khi biến
đổi log) tuân theo phân phối chuẩn.
Kết hợp với Skewness & Kurtosis: Kết quả
kiểm định này hoàn toàn phù hợp với các giá trị Skewness và Kurtosis
đáng kể đã tính toán ở hai mục trước. Mặc dù Log_PE đã đối
xứng hơn PE gốc, nó vẫn chưa đủ “chuẩn” theo tiêu chuẩn
thống kê chặt chẽ.
Kết luận: Các biến định lượng quan trọng trong bộ dữ liệu này không tuân theo phân phối chuẩn. Điều này hàm ý rằng: (1) Các phương pháp thống kê giả định tính chuẩn (như t-test, ANOVA) cần được sử dụng thận trọng và kiểm tra các giả định khác (như phương sai đồng nhất); (2) Các phương pháp phi tham số hoặc các mô hình tổng quát hơn có thể phù hợp hơn cho phân tích suy luận sâu hơn.
##
## 1.3.3.4: Trực quan hóa Sơ bộ bằng QQ-Plot
# 2. Vẽ QQ-Plot cho Real_Return (trên mẫu con để tránh quá tải)
# QQ-Plot so sánh phân vị của dữ liệu với phân vị lý thuyết của phân phối chuẩn
# Nếu các điểm nằm sát đường thẳng => Gần phân phối chuẩn
cat("Đang vẽ QQ-Plot cho Real_Return (mẫu N=5000)...\n")## Đang vẽ QQ-Plot cho Real_Return (mẫu N=5000)...
if (exists("nyse_sample")) {
qq_plot_real_return <- ggplot(nyse_sample, aes(sample = Real_Return)) +
geom_qq(color = "blue", alpha = 0.5) + # Vẽ các điểm phân vị
geom_qq_line(color = "red", linetype = "dashed") + # Vẽ đường chuẩn lý thuyết
labs(title = "Biểu đồ 1.3.1: QQ-Plot của Lợi suất Thực tế (Real_Return)",
subtitle = "So sánh với Phân phối Chuẩn (trên mẫu N=5000)",
x = "Phân vị Lý thuyết (Chuẩn)",
y = "Phän vị Mẫu (Real_Return)") +
theme_minimal()
print(qq_plot_real_return)
} else {
cat("Biến nyse_sample chưa được tạo.\n")
}##
## Đang vẽ QQ-Plot cho Log_PE (mẫu N=5000)...
if (exists("nyse_sample")) {
qq_plot_log_pe <- ggplot(nyse_sample, aes(sample = Log_PE)) + # Sử dụng tên biến mới
geom_qq(color = "darkgreen", alpha = 0.5) +
geom_qq_line(color = "red", linetype = "dashed") +
labs(title = "Biểu đồ 1.3.2: QQ-Plot của Log(PE) (Log_PE)",
subtitle = "So sánh với Phân phối Chuẩn (trên mẫu N=5000, đã lọc NA)",
x = "Phân vị Lý thuyết (Chuẩn)",
y = "Phân vị Mẫu (Log_PE)") +
theme_minimal()
print(qq_plot_log_pe)
} else {
cat("Biến nyse_sample chưa được tạo.\n")
}Nhận xét phân tích tổng hợp Mục 1.3.3:
Độ xiên (Skewness - Mục 1.3.3.1): Kết quả (Bảng
1.3.11) cho thấy hầu hết các biến quan trọng
(Nominal_Return, Real_Return,
amount, PB, PS,
Leverage_Ratio, Current_Ratio,
Log_PE…) đều có độ lệch phải đáng kể
(Skewness > 1), chỉ có ROE lệch trái mạnh. Điều này cho
thấy sự thiếu đối xứng nghiêm trọng trong dữ liệu.
Độ nhọn (Kurtosis - Mục 1.3.3.2): Kết quả (Bảng
1.3.12) cho thấy hầu hết các biến đều có Excess Kurtosis >
0, đặc biệt là Nominal_Return (117.3) và
Real_Return (31.9). Điều này chứng tỏ các phân phối này
nhọn hơn và có đuôi dày hơn so với phân phối chuẩn, hàm
ý rủi ro xảy ra các giá trị cực đoan (outliers) cao hơn.
Kiểm định Chuẩn (Normality Test - Mục 1.3.3.3):
Kiểm định Shapiro-Wilk trên mẫu con cho cả Real_Return và
Log_PE đều cho p-value cực kỳ nhỏ
(< 2.2e-16). Điều này cung cấp bằng chứng thống kê mạnh
mẽ để bác bỏ giả thuyết rằng các biến này (ngay cả
Log_PE sau khi chuẩn hóa) tuân theo phân phối
chuẩn.
Trực quan hóa QQ-Plot (Mục 1.3.3.4):
QQ-Plot Real_Return: Các điểm dữ
liệu (màu xanh) lệch rất xa khỏi đường chuẩn lý thuyết
(màu đỏ). Đặc biệt ở hai đầu (đuôi), các điểm cong vồng lên ở phía dương
và cong xuống ở phía âm, tạo thành hình chữ “S”. Điều này trực quan hóa
mạnh mẽ kết luận từ Skewness, Kurtosis và Shapiro Test:
Real_Return hoàn toàn không tuân theo phân phối
chuẩn, với phần đuôi dày.
QQ-Plot Log_PE: Mặc dù các điểm dữ
liệu (màu xanh lá) bám sát đường chuẩn lý thuyết (màu đỏ) tốt hơn nhiều
so với Real_Return ở phần trung tâm, nhưng chúng vẫn
lệch ra đáng kể ở hai đầu đuôi. Các điểm ở đuôi trên
(giá trị Log_PE cao) nằm cao hơn đường thẳng, và các điểm ở
đuôi dưới (giá trị Log_PE thấp) nằm thấp hơn đường thẳng.
Điều này cho thấy, mặc dù phép biến đổi logarit đã cải thiện tính đối
xứng, phân phối của Log_PE vẫn có đuôi dày
hơn so với phân phối chuẩn và không hoàn toàn
chuẩn.
Kết luận: Cả bằng chứng định lượng (Skewness, Kurtosis, Shapiro Test) và trực quan (QQ-Plot) đều đi đến cùng một kết luận: Các biến định lượng quan trọng trong bộ dữ liệu NYSE này không tuân theo phân phối chuẩn. Chúng thường bị lệch và có đuôi dày. Điều này là đặc điểm phổ biến của dữ liệu tài chính và cần được xem xét cẩn thận khi lựa chọn các mô hình thống kê và diễn giải kết quả ở các mục sau. Việc sử dụng các phương pháp phi tham số hoặc các mô hình robust với outliers có thể là cần thiết.
Nhằm đo lường mức độ và chiều hướng của mối quan hệ tuyến tính giữa các cặp biến định lượng quan trọng. Hệ số tương quan Pearson (r) dao động từ -1 đến +1, trong đó:
# 1. Tải thư viện cần thiết
library(dplyr)
library(knitr)
library(reshape2) # Cần cho việc xử lý ma trận sau này
# 3. Chọn các biến định lượng chính để tính tương quan
# (Bao gồm lợi suất, rủi ro, định giá, hiệu quả, quy mô...)
# Lựa chọn cẩn thận để tránh đưa vào quá nhiều biến gây nhiễu
vars_for_cor <- c("Real_Return", "Nominal_Return", "amount", "Horizon_Days",
"Volatility_Buy", "Sharpe_Ratio",
"Log_PE", "PB", "PS",
"ROE", "ROA", "NetProfitMargin",
"Leverage_Ratio", "Current_Ratio", "ESG")
# 4. Tạo data frame con chỉ chứa các biến này và xử lý NA/Inf
# Hàm cor() yêu cầu dữ liệu numeric và không có NA/Inf
cor_data_input <- nyse_clean_core %>%
select(all_of(vars_for_cor)) %>%
# Xử lý Inf/NaN một lần nữa cho chắc chắn
mutate(across(everything(), ~ ifelse(is.finite(.x), .x, NA))) %>%
# Loại bỏ các hàng có bất kỳ giá trị NA nào trong các cột đã chọn
# 'pairwise.complete.obs' trong cor() có thể xử lý NA, nhưng lọc trước rõ ràng hơn
na.omit()
# Kiểm tra số lượng quan sát còn lại sau khi lọc NA
n_obs_cor <- nrow(cor_data_input)
cat("1.3.4.1: Tính toán Ma trận Tương quan \n")## 1.3.4.1: Tính toán Ma trận Tương quan
cat("Số lượng quan sát hợp lệ (không NA/Inf) để tính tương quan:", format(n_obs_cor, big.mark = ","), "\n")## Số lượng quan sát hợp lệ (không NA/Inf) để tính tương quan: 364,662
# 5. Tính toán ma trận tương quan Pearson
# use = "pairwise.complete.obs" xử lý NA bằng cách tính tương quan cho từng cặp biến dựa trên các quan sát hoàn chỉnh của cặp đó
# method = "pearson" là mặc định
cor_matrix <- cor(cor_data_input, method = "pearson", use = "pairwise.complete.obs")
# 6. Hiển thị ma trận tương quan (làm tròn để dễ đọc)
cat("\nMa trận Tương quan Pearson (làm tròn 2 chữ số):\n")##
## Ma trận Tương quan Pearson (làm tròn 2 chữ số):
## Real_Return Nominal_Return amount Horizon_Days Volatility_Buy
## Real_Return 1.00 0.49 0 0.13 0.06
## Nominal_Return 0.49 1.00 0 0.31 0.13
## amount 0.00 0.00 1 0.00 0.00
## Horizon_Days 0.13 0.31 0 1.00 0.00
## Volatility_Buy 0.06 0.13 0 0.00 1.00
## Sharpe_Ratio 0.06 0.13 0 0.00 1.00
## Log_PE -0.01 0.10 0 0.00 -0.07
## PB -0.10 0.09 0 0.00 -0.01
## PS -0.02 0.08 0 0.00 0.13
## ROE -0.10 -0.03 0 0.00 -0.06
## ROA -0.02 0.07 0 0.00 0.06
## NetProfitMargin -0.02 0.06 0 0.00 -0.02
## Leverage_Ratio -0.07 -0.13 0 0.00 0.03
## Current_Ratio 0.06 0.08 0 0.00 0.21
## ESG -0.03 -0.10 0 0.00 -0.26
## Sharpe_Ratio Log_PE PB PS ROE ROA NetProfitMargin
## Real_Return 0.06 -0.01 -0.10 -0.02 -0.10 -0.02 -0.02
## Nominal_Return 0.13 0.10 0.09 0.08 -0.03 0.07 0.06
## amount 0.00 0.00 0.00 0.00 0.00 0.00 0.00
## Horizon_Days 0.00 0.00 0.00 0.00 0.00 0.00 0.00
## Volatility_Buy 1.00 -0.07 -0.01 0.13 -0.06 0.06 -0.02
## Sharpe_Ratio 1.00 -0.07 -0.01 0.13 -0.06 0.06 -0.02
## Log_PE -0.07 1.00 0.75 0.50 -0.20 0.10 0.05
## PB -0.01 0.75 1.00 0.40 0.31 0.35 0.10
## PS 0.13 0.50 0.40 1.00 0.04 0.51 0.71
## ROE -0.06 -0.20 0.31 0.04 1.00 0.63 0.25
## ROA 0.06 0.10 0.35 0.51 0.63 1.00 0.58
## NetProfitMargin -0.02 0.05 0.10 0.71 0.25 0.58 1.00
## Leverage_Ratio 0.03 -0.12 -0.24 -0.27 -0.26 -0.55 -0.13
## Current_Ratio 0.21 0.30 0.20 0.83 0.04 0.48 0.55
## ESG -0.26 0.12 -0.06 0.15 -0.44 -0.35 0.04
## Leverage_Ratio Current_Ratio ESG
## Real_Return -0.07 0.06 -0.03
## Nominal_Return -0.13 0.08 -0.10
## amount 0.00 0.00 0.00
## Horizon_Days 0.00 0.00 0.00
## Volatility_Buy 0.03 0.21 -0.26
## Sharpe_Ratio 0.03 0.21 -0.26
## Log_PE -0.12 0.30 0.12
## PB -0.24 0.20 -0.06
## PS -0.27 0.83 0.15
## ROE -0.26 0.04 -0.44
## ROA -0.55 0.48 -0.35
## NetProfitMargin -0.13 0.55 0.04
## Leverage_Ratio 1.00 -0.27 0.30
## Current_Ratio -0.27 1.00 0.12
## ESG 0.30 0.12 1.00
Nhận xét
Ma trận Tương quan tổng thể:
Vấn đề đa cộng tuyến: Phát hiện quan trọng nhất
là tương quan dương hoàn hảo (r=1.00) giữa Volatility_Buy
và Sharpe_Ratio. Điều này cho thấy hai biến này đo lường
gần như cùng một khái niệm trong bộ dữ liệu này hoặc có thể có lỗi trong
cách tính/định nghĩa Sharpe_Ratio gốc. Chỉ giữ lại một
trong hai biến (Volatility_Buy là lựa chọn tốt hơn vì nó là
chỉ số rủi ro gốc) trong các mô hình hồi quy sau này để tránh đa cộng
tuyến hoàn hảo.
Tương quan lợi suất: Real_Return và
Nominal_Return có tương quan dương trung bình (r=0.49), xác
nhận tác động của biến inflation đã làm giảm mối liên hệ
trực tiếp. Cả hai loại lợi suất đều có tương quan rất
yếu với hầu hết các chỉ số tài chính, định giá và rủi ro khác.
Ví dụ, Real_Return gần như không tương quan tuyến tính với
amount (r=0.00), Log_PE (r=-0.01),
PS (r=-0.02), ROA (r=-0.02),
NetProfitMargin (r=-0.02), ESG (r=-0.03).
Tương quan yếu với Volatility_Buy (r=0.06),
Leverage_Ratio (r=-0.07), PB (r=-0.10),
ROE (r=-0.10). Tương quan dương yếu nhất là với
Horizon_Days (r=0.13).
Tương quan nội tại mạnh (khác):
Định giá: Log_PE tương quan dương
mạnh với PB (r=0.75) và PS (r=0.50).
Hiệu quả HĐ & Thanh khoản: PS
tương quan rất mạnh với Current_Ratio (r=0.83) và
NetProfitMargin (r=0.71). NetProfitMargin cũng
tương quan khá mạnh với Current_Ratio (r=0.55) và
ROA (r=0.58). ROE và ROA tương
quan dương mạnh (r=0.63).
Tương quan âm đáng chú ý (khác):
Leverage_Ratio có tương quan âm mạnh nhất với
ROA (r=-0.55), tiếp tục củng cố nhận định rằng các công ty
có hiệu quả tài sản cao hơn thường dùng ít nợ hơn. Nó cũng tương quan âm
với PS (r=-0.27), Current_Ratio (r=-0.27),
ROE (r=-0.26), PB (r=-0.24).
ESG có tương quan âm mạnh nhất với ROE
(r=-0.44) và ROA (r=-0.35), cho thấy các công ty có xếp
hạng ESG cao hơn có xu hướng hiệu quả sinh lời trên vốn/tài sản thấp hơn
trong mẫu này. ESG cũng tương quan âm với
Volatility_Buy (r=-0.26), gợi ý rằng các công ty ESG cao
hơn có thể có rủi ro thấp hơn.
Biến gần như Độc lập: amount và
Horizon_Days tiếp tục cho thấy tương quan gần bằng 0 với
hầu hết các biến tài chính và rủi ro.
# 1. Chuyển đổi ma trận tương quan thành dạng dài (Var1, Var2, Correlation)
cat("\n 1.3.4.2: Xác định các cặp tương quan mạnh \n")##
## 1.3.4.2: Xác định các cặp tương quan mạnh
# Sử dụng melt từ reshape2 hoặc pivot_longer từ tidyr
melted_cor <- melt(cor_matrix, na.rm = TRUE) # na.rm loại bỏ NA nếu có
# 2. Loại bỏ các cặp trùng lặp (vd: A vs B và B vs A) và tự tương quan (A vs A)
# Chỉ giữ lại phần tam giác trên hoặc dưới của ma trận
melted_cor_unique <- melted_cor %>%
filter(as.character(Var1) < as.character(Var2)) # Chỉ giữ Var1 < Var2 (theo thứ tự alphabet)
# 3. Sắp xếp theo giá trị tương quan tuyệt đối giảm dần
strongest_cor <- melted_cor_unique %>%
arrange(desc(abs(value))) # Sắp xếp theo giá trị tuyệt đối |r|
# 4. Hiển thị Top 10 cặp tương quan mạnh (cả dương và âm)
cat("Top 10 cặp biến có tương quan tuyến tính mạnh (Tuyệt đối |r|):\n")## Top 10 cặp biến có tương quan tuyến tính mạnh (Tuyệt đối |r|):
top_10_cor <- head(strongest_cor, 10) %>%
mutate(value = round(value, 3)) # Làm tròn kết quả
kable(top_10_cor,
caption = "Bảng 1.3.14: Top 10 Cặp Tương quan Tuyến tính Mạnh nhất",
col.names = c("Biến 1", "Biến 2", "Hệ số Tương quan (r)"),
format = "pipe", align = "l")| Biến 1 | Biến 2 | Hệ số Tương quan (r) |
|---|---|---|
| Sharpe_Ratio | Volatility_Buy | 1.000 |
| Current_Ratio | PS | 0.833 |
| Log_PE | PB | 0.752 |
| NetProfitMargin | PS | 0.708 |
| ROA | ROE | 0.628 |
| NetProfitMargin | ROA | 0.577 |
| Current_Ratio | NetProfitMargin | 0.554 |
| Leverage_Ratio | ROA | -0.548 |
| PS | ROA | 0.512 |
| Log_PE | PS | 0.495 |
# 5. Hiển thị Top 5 cặp tương quan DƯƠNG mạnh nhất
cat("\nTop 5 cặp biến có tương quan DƯƠNG mạnh nhất (r > 0):\n")##
## Top 5 cặp biến có tương quan DƯƠNG mạnh nhất (r > 0):
top_5_pos_cor <- strongest_cor %>%
filter(value > 0) %>% # Chỉ lấy r dương
head(5) %>%
mutate(value = round(value, 3))
kable(top_5_pos_cor,
caption = "Bảng 1.3.15: Top 5 Cặp Tương quan Dương Mạnh nhất",
col.names = c("Biến 1", "Biến 2", "Hệ số Tương quan (r)"),
format = "pipe", align = "l")| Biến 1 | Biến 2 | Hệ số Tương quan (r) |
|---|---|---|
| Sharpe_Ratio | Volatility_Buy | 1.000 |
| Current_Ratio | PS | 0.833 |
| Log_PE | PB | 0.752 |
| NetProfitMargin | PS | 0.708 |
| ROA | ROE | 0.628 |
# 6. Hiển thị Top 5 cặp tương quan ÂM mạnh nhất
cat("\nTop 5 cặp biến có tương quan ÂM mạnh nhất (r < 0):\n")##
## Top 5 cặp biến có tương quan ÂM mạnh nhất (r < 0):
top_5_neg_cor <- strongest_cor %>%
filter(value < 0) %>% # Chỉ lấy r âm
# Sắp xếp lại theo giá trị âm nhỏ nhất (tức là âm mạnh nhất)
arrange(value) %>%
head(5) %>%
mutate(value = round(value, 3))
kable(top_5_neg_cor,
caption = "Bảng 1.3.16: Top 5 Cặp Tương quan Âm Mạnh nhất",
col.names = c("Biến 1", "Biến 2", "Hệ số Tương quan (r)"),
format = "pipe", align = "l")| Biến 1 | Biến 2 | Hệ số Tương quan (r) |
|---|---|---|
| Leverage_Ratio | ROA | -0.548 |
| ESG | ROE | -0.440 |
| ESG | ROA | -0.349 |
| Current_Ratio | Leverage_Ratio | -0.274 |
| Leverage_Ratio | PS | -0.272 |
Các cặp tương quan mạnh:
Bảng Top 10/Top 5 xác nhận lại các mối quan hệ mạnh nhất đã nêu
trên, đặc biệt là tương quan hoàn hảo giữa Sharpe_Ratio và
Volatility_Buy, tương quan rất mạnh giữa
Current_Ratio và PS, và các tương quan nội tại
khác trong nhóm định giá và hiệu quả.
Tương quan âm mạnh nhất được xác nhận là giữa
Leverage_Ratio và ROA.
# 1. Chọn các cặp biến quan trọng để kiểm định
# Ví dụ: Mối quan hệ giữa Lợi suất và các yếu tố Rủi ro, Định giá
cat("\n 1.3.4.3: Kiểm định ý nghĩa thống kê của tương quan chính \n")##
## 1.3.4.3: Kiểm định ý nghĩa thống kê của tương quan chính
pairs_to_test <- list(
c("Real_Return", "Volatility_Buy"),
c("Real_Return", "Log_PE"),
c("Real_Return", "Sharpe_Ratio"),
c("Volatility_Buy", "Sharpe_Ratio"), # Cặp tương quan dương mạnh bất thường
c("ROA", "Leverage_Ratio") # Cặp tương quan âm mạnh bất thường
)
# 2. Thực hiện kiểm định cor.test() cho từng cặp
# Giả thuyết H0: Hệ số tương quan bằng 0 (không có tương quan tuyến tính)
# Nếu p-value < 0.05, bác bỏ H0, kết luận tương quan có ý nghĩa thống kê
results_cor_test <- list() # Tạo list để lưu kết quả
for (pair in pairs_to_test) {
var1 <- pair[1]
var2 <- pair[2]
# Thực hiện kiểm định, xử lý lỗi nếu có (có thể do NA)
test_result <- tryCatch({
# Sử dụng dữ liệu đã lọc NA 'cor_data_input'
cor.test(cor_data_input[[var1]], cor_data_input[[var2]], method = "pearson")
}, error = function(e) {
# Trả về NA nếu có lỗi
list(estimate = NA, p.value = NA, parameter = list(df = NA))
})
# Lưu kết quả vào list
results_cor_test[[paste(var1, "vs", var2)]] <- list(
correlation = round(test_result$estimate, 3),
p_value = test_result$p.value, # Giữ nguyên p-value để đánh giá
df = test_result$parameter # Bậc tự do (n-2)
)
}
# 3. Chuyển kết quả kiểm định thành data frame để trình bày
cor_test_df <- do.call(rbind, lapply(results_cor_test, function(x) data.frame(Correlation = x$correlation, P_Value = x$p_value, DF = x$df)))
cor_test_df <- tibble::rownames_to_column(cor_test_df, var = "Pair")
# Định dạng lại P-value cho dễ đọc
cor_test_df <- cor_test_df %>%
mutate(P_Value_Formatted = format.pval(P_Value, digits = 3, eps = 0.001), # Hiển thị <0.001 nếu quá nhỏ
Significance = ifelse(P_Value < 0.05, "Có ý nghĩa (p < 0.05)", "Không ý nghĩa (p >= 0.05)"))
# 4. Trình bày bảng kết quả kiểm định
kable(cor_test_df %>% select(Pair, Correlation, P_Value_Formatted, Significance, DF),
caption = "Bảng 1.3.17: Kết quả Kiểm định Ý nghĩa Thống kê cho các Tương quan Chính",
col.names = c("Cặp Biến", "Hệ số r", "P-value", "Kết luận", "Bậc tự do (df)"),
format = "pipe", align = "l")| Cặp Biến | Hệ số r | P-value | Kết luận | Bậc tự do (df) |
|---|---|---|---|---|
| Real_Return vs Volatility_Buy | 0.057 | <0.001 | Có ý nghĩa (p < 0.05) | 364660 |
| Real_Return vs Log_PE | -0.006 | <0.001 | Có ý nghĩa (p < 0.05) | 364660 |
| Real_Return vs Sharpe_Ratio | 0.057 | <0.001 | Có ý nghĩa (p < 0.05) | 364660 |
| Volatility_Buy vs Sharpe_Ratio | 1.000 | <0.001 | Có ý nghĩa (p < 0.05) | 364660 |
| ROA vs Leverage_Ratio | -0.548 | <0.001 | Có ý nghĩa (p < 0.05) | 364660 |
Kiểm định ý nghĩa thống kê:
* Đúng như dự đoán, với cỡ mẫu cực lớn (df ≈ 364,660), tất cả các hệ số tương quan được kiểm định (bao gồm cả những hệ số rất nhỏ như r=-0.006 giữa `Real_Return` và `Log_PE`) đều có **p-value < 0.001**. Do đó, tất cả các mối quan hệ này đều "có ý nghĩa thống kê".
* Tuy nhiên, ý nghĩa thực tiễn mới là quan trọng. Kết quả kiểm định tái khẳng định rằng mặc dù có ý nghĩa thống kê, mối quan hệ tuyến tính giữa `Real_Return` với `Volatility_Buy` (r=0.057) và `Log_PE` (r=-0.006) là **quá yếu** để có thể coi là có ý nghĩa thực tiễn hoặc giá trị dự báo đáng kể. Ngược lại, các mối quan hệ mạnh hơn như `Volatility_Buy` vs `Sharpe_Ratio` (r=1.000) và `ROA` vs `Leverage_Ratio` (r=-0.548) vừa có ý nghĩa thống kê, vừa có ý nghĩa thực tiễn (mặc dù mối quan hệ r=1 cần được xử lý).Kết luận tổng hợp mục 1.3.4: Phân tích tương quan
cho thấy các mối liên kết nội tại mạnh mẽ giữa các nhóm chỉ số tài chính
(định giá, hiệu quả, thanh khoản), nhưng lại bộc lộ mối quan hệ
tuyến tính rất yếu giữa hầu hết các yếu tố này với
lợi suất thực tế (Real_Return). Phát hiện
này đặt ra câu hỏi về tính hiệu quả của thị trường hoặc tính phù hợp của
các mô hình tuyến tính đơn giản trong việc giải thích lợi suất. Vấn đề
tương quan hoàn hảo giữa Volatility_Buy và
Sharpe_Ratio cần được giải quyết bằng cách loại bỏ một
biến. Các mối tương quan âm đáng chú ý (như ROA vs Leverage, ESG vs
ROE/ROA) cung cấp những hiểu biết có giá trị về đặc điểm của các công ty
trong mẫu.
Sau khi mô tả phân bố và tương quan, mục này sử dụng thống kê suy luận để kiểm tra xem liệu có sự khác biệt có ý nghĩa thống kê về giá trị trung bình của các biến định lượng giữa các nhóm được xác định bởi các biến phân loại hay không. Giả thuyết gốc (H0) thường là “không có sự khác biệt trung bình giữa các nhóm”. Nếu p-value < 0.05, chúng ta bác bỏ H0 và kết luận có sự khác biệt ý nghĩa.
Real_Return theo
investment (GOOD/BAD)##
## --- So sánh Lợi suất Thực tế theo Kết quả Đầu tư (t-test) ---
##
##
## Table: Bảng: Kết quả Welch t-test cho Lợi suất Thực tế theo Kết quả Đầu tư
##
## |T-statistic |P-value |Mean Grp1 |Mean Grp2 |Chênh lệch |95% CI Low |95% CI High |
## |:-----------|:-------|:---------|:---------|:----------|:----------|:-----------|
## |-425.525 |0 |-0.248 |0.715 |-0.963 |-0.968 |-0.959 |
## Kết luận: Có sự khác biệt trung bình ý nghĩa thống kê (p < 0.05).
Nhận xét 1.3.5:
Mục này sử dụng các kiểm định t-test (so sánh 2 nhóm) và ANOVA (so sánh >= 3 nhóm) để kiểm tra xem có sự khác biệt ý nghĩa thống kê về giá trị trung bình của các biến định lượng giữa các nhóm phân loại hay không. Kết quả được diễn giải dưới đây:
1.3.5.1. So sánh Real_Return theo
investment (GOOD/BAD):
Kết quả Welch t-test cho thấy giá trị p-value = 0 (nhỏ hơn 0.05).
Kết luận: Có sự khác biệt trung bình rất có
ý nghĩa thống kê về Lợi suất Thực tế giữa nhóm GOOD và
BAD. Trung bình Real_Return của nhóm
GOOD (Mean Grp2 = 0.715, tức 71.5%) cao hơn
đáng kể so với nhóm BAD (Mean Grp1 = -0.248,
tức -24.8%). Chênh lệch trung bình ước tính là 0.963 (96.3%). Điều này
khẳng định biến investment phân loại rất hiệu quả dựa trên
lợi suất.
Real_Return theo
sector##
## So sánh Lợi suất Thực tế theo Ngành (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Lợi suất Thực tế theo Ngành
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:----------|:--------|:-----------|:-------|
## |sector |4 |4131.683 |1032.921 |1751.865 |0 |
## |Residuals |405253 |238942.110 |0.590 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $sector
## diff lwr upr p adj
## BANK-AUTO -0.027029578 -0.037359812 -0.016699343 0.0000000
## FMCG-AUTO -0.019380871 -0.031184628 -0.007577113 0.0000735
## RETAIL-AUTO 0.028849231 0.018823064 0.038875397 0.0000000
## TECH-AUTO 0.234274372 0.224153517 0.244395226 0.0000000
## FMCG-BANK 0.007648707 -0.004019119 0.019316533 0.3804336
## RETAIL-BANK 0.055878809 0.046013035 0.065744582 0.0000000
## TECH-BANK 0.261303950 0.251341963 0.271265936 0.0000000
## RETAIL-FMCG 0.048230101 0.036830609 0.059629594 0.0000000
## TECH-FMCG 0.253655242 0.242172381 0.265138104 0.0000000
## TECH-RETAIL 0.205425141 0.195778824 0.215071458 0.0000000
1.3.5.2. So sánh Real_Return theo
sector:
Kết quả ANOVA cho thấy p-value = 0 (nhỏ hơn
0.05) đối với yếu tố sector.
Kết luận ANOVA: Có sự khác biệt trung bình rất có ý nghĩa thống kê về Lợi suất Thực tế giữa ít nhất hai ngành.
Phân tích TukeyHSD:
Kiểm định post-hoc cho thấy sự khác biệt rất rõ ràng về lợi suất thực tế trung bình giữa các ngành.
Ngành TECH có lợi suất trung bình
cao nhất, vượt trội đáng kể so với tất cả các ngành còn lại
(tất cả các so sánh TECH- đều có
p adj = 0).
Ngành RETAIL đứng thứ hai, có lợi
suất trung bình cao hơn đáng kể so với AUTO,
FMCG, và BANK.
Các ngành BANK và
FMCG có lợi suất trung bình thấp nhất, và
sự khác biệt giữa hai ngành này là không có ý nghĩa thống kê
(FMCG-BANK có p adj = 0.38).
Thứ tự lợi suất trung bình (từ cao đến thấp) là: TECH > RETAIL > AUTO > FMCG \(\approx\) BANK.
Real_Return theo
Holding_Period##
## So sánh Lợi suất Thực tế theo Thời gian Nắm giữ (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Lợi suất Thực tế theo Thời gian Nắm giữ
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:----------|:--------|:-----------|:-------|
## |Holding_Period |2 |2441.686 |1220.843 |2056.055 |0 |
## |Residuals |405255 |240632.106 |0.594 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $Holding_Period
## diff lwr upr p adj
## Mid-term (31-180d)-Short-term (<=30d) 0.02196404 0.0148412 0.02908688 0
## Long-term (>180d)-Short-term (<=30d) 0.17075291 0.1639508 0.17755500 0
## Long-term (>180d)-Mid-term (31-180d) 0.14878887 0.1418115 0.15576624 0
Nhận xét:
Kết quả ANOVA: Bảng ANOVA cho thấy
p-value = 0 (nhỏ hơn 0.05) đối với yếu tố
Holding_Period. Điều này khẳng định có sự khác biệt trung
bình rất có ý nghĩa thống kê về Lợi suất Thực tế
(Real_Return) giữa ít nhất hai trong ba chiến lược thời
gian nắm giữ (Ngắn hạn, Trung hạn, Dài hạn).
Kiểm định Post-hoc TukeyHSD: Bảng kết quả TukeyHSD cho thấy p adj = 0 (nhỏ hơn 0.05) cho tất cả ba cặp so sánh:
Mid-term vs. Short-term: Có khác biệt ý
nghĩa (diff = 0.022).Long-term vs. Short-term: Có khác biệt ý
nghĩa (diff = 0.171).Long-term vs. Mid-term: Có khác biệt ý
nghĩa (diff = 0.149).Diễn giải sự khác biệt:
diff) dương cho thấy nhóm thứ nhất có trung
bình cao hơn nhóm thứ hai.Long-term có Mean(Real_Return) cao hơn
đáng kể so với cả Short-term (cao hơn 0.171 hay 17.1%) và
Mid-term (cao hơn 0.149 hay 14.9%).Mid-term cũng có Mean(Real_Return) cao hơn
một chút so với Short-term (cao hơn 0.022 hay 2.2%).Kết luận: Trái ngược với dự đoán ban đầu dựa
trên Median, kiểm định TukeyHSD trên trung bình
(Mean) cho thấy một kết quả phù hợp hơn với lý thuyết đầu
tư dài hạn: Chiến lược Long-term (>180 ngày) có
lợi suất thực tế trung bình cao nhất, cao hơn đáng kể so với
Mid-term và Short-term. Chiến lược
Mid-term cũng hiệu quả hơn Short-term một
chút. Điều này gợi ý rằng, trung bình, việc nắm giữ cổ phiếu lâu hơn
trong bộ dữ liệu này mang lại lợi suất thực tế tốt hơn, mặc dù có thể đi
kèm với biến động lớn hơn (như đã thấy trong boxplot).
Volatility_Buy theo
sector##
## So sánh Độ biến động theo Ngành (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Độ biến động theo Ngành
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:--------|:-------|:-----------|:-------|
## |sector |4 |660.544 |165.136 |20634.03 |0 |
## |Residuals |405253 |3243.275 |0.008 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $sector
## diff lwr upr p adj
## BANK-AUTO -0.011519269 -0.012722796 -0.0103157426 0.0000000
## FMCG-AUTO -0.127787130 -0.129162330 -0.1264119305 0.0000000
## RETAIL-AUTO -0.008612833 -0.009780934 -0.0074447323 0.0000000
## TECH-AUTO -0.009721902 -0.010901034 -0.0085427688 0.0000000
## FMCG-BANK -0.116267861 -0.117627224 -0.1149084980 0.0000000
## RETAIL-BANK 0.002906436 0.001757021 0.0040558503 0.0000000
## TECH-BANK 0.001797368 0.000636744 0.0029579914 0.0002323
## RETAIL-FMCG 0.119174297 0.117846196 0.1205023977 0.0000000
## TECH-FMCG 0.118065229 0.116727415 0.1194030424 0.0000000
## TECH-RETAIL -0.001109068 -0.002232915 0.0000147784 0.0551339
Nhận xét:
Kết quả ANOVA: Bảng ANOVA cho thấy
p-value = 0 (nhỏ hơn 0.05) đối với yếu tố
sector. Điều này khẳng định có sự khác biệt trung bình
rất có ý nghĩa thống kê về Mức độ Rủi ro
(Volatility_Buy) giữa các ngành.
Kiểm định Post-hoc TukeyHSD: Bảng kết quả
TukeyHSD cho thấy hầu hết các cặp ngành đều có sự khác biệt ý
nghĩa thống kê về Volatility_Buy trung bình (p adj
= 0.0000000), ngoại trừ cặp TECH-RETAIL (p adj = 0.055,
không có ý nghĩa ở mức 5%).
Diễn giải sự khác biệt (Dựa trên cột
diff):
Ngành Rủi ro Thấp nhất: FMCG có
Volatility_Buy trung bình thấp hơn đáng kể so với tất cả
các ngành khác (ví dụ: FMCG-AUTO diff = -0.128, nghĩa là
FMCG thấp hơn AUTO khoảng 0.128). Điều này phù hợp với đặc tính phòng
thủ, ổn định của ngành hàng tiêu dùng nhanh.
Nhóm Rủi ro Cao: Các ngành AUTO,
BANK, RETAIL, TECH có mức
Volatility_Buy trung bình cao hơn và khá tương đồng nhau.
Kết quả so sánh giữa các cặp trong nhóm này cho thấy:
BANK, RETAIL, TECH đều có
rủi ro thấp hơn AUTO một chút (diff âm).
RETAIL và TECH có rủi ro cao hơn
BANK một chút (diff dương).
TECH và RETAIL có mức rủi ro gần như
tương đương (p adj > 0.05).
Kết luận: Có sự khác biệt rõ rệt về mức độ rủi
ro giữa các ngành. Ngành FMCG là ngành có rủi ro (biến động
giá) thấp nhất. Bốn ngành còn lại (AUTO, BANK,
RETAIL, TECH) có mức rủi ro cao hơn đáng kể và
tương đối gần nhau, trong đó AUTO có vẻ là ngành có rủi ro
cao nhất trong nhóm này.
Log_PE theo
sector##
## So sánh Log(PE) theo Ngành (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Log(PE) theo Ngành
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:---------|:---------|:-----------|:-------|
## |sector |4 |93979.78 |23494.944 |51492.87 |0 |
## |Residuals |365502 |166769.66 |0.456 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $sector
## diff lwr upr p adj
## BANK-AUTO 0.31693813 0.30686149 0.32701477 0
## FMCG-AUTO 0.88127613 0.87013495 0.89241732 0
## RETAIL-AUTO 0.33984960 0.33025857 0.34944063 0
## TECH-AUTO 1.39166851 1.38200806 1.40132895 0
## FMCG-BANK 0.56433800 0.55360405 0.57507195 0
## RETAIL-BANK 0.02291147 0.01379668 0.03202625 0
## TECH-BANK 1.07473037 1.06554257 1.08391818 0
## RETAIL-FMCG -0.54142654 -0.55170597 -0.53114710 0
## TECH-FMCG 0.51039237 0.50004814 0.52073661 0
## TECH-RETAIL 1.05181891 1.04316645 1.06047136 0
Nhận xét:
Kết quả ANOVA: Bảng ANOVA cho thấy
p-value = 0 (nhỏ hơn 0.05) đối với yếu tố
sector. Điều này khẳng định có sự khác biệt trung bình
rất có ý nghĩa thống kê về Mức định giá (Log_PE)
giữa các ngành.
Kiểm định Post-hoc TukeyHSD: Bảng kết quả
TukeyHSD cho thấy tất cả các cặp ngành đều có sự khác biệt ý
nghĩa thống kê về Log_PE trung bình (tất cả
p adj đều bằng 0).
Diễn giải sự khác biệt (Dựa trên cột diff -
chênh lệch Log_PE trung bình):
Ngành Định giá Cao nhất: TECH có
Log_PE trung bình cao nhất, cao hơn đáng kể so với tất cả
các ngành khác (ví dụ: TECH-AUTO diff = 1.39,
TECH-BANK diff = 1.07, TECH-FMCG diff = 0.51,
TECH-RETAIL diff = 1.05). Điều này phản ánh kỳ vọng tăng
trưởng cao mà thị trường đặt vào ngành công nghệ.
Ngành Định giá Cao thứ hai: FMCG có
Log_PE trung bình cao thứ hai (FMCG-AUTO diff
= 0.88, FMCG-BANK diff = 0.56). Ngành hàng tiêu dùng nhanh
thường được coi là ổn định và có thể được định giá cao hơn các ngành chu
kỳ như AUTO hay BANK.
Nhóm Định giá Thấp hơn: BANK và
RETAIL có Log_PE trung bình khá tương đồng
(RETAIL-BANK diff = 0.02, chênh lệch rất nhỏ) và thấp hơn
đáng kể so với TECH và FMCG.
Ngành Định giá Thấp nhất: AUTO có
Log_PE trung bình thấp nhất trong 5 ngành (ví dụ:
BANK-AUTO diff = 0.32, RETAIL-AUTO diff =
0.34). Điều này có thể phản ánh tính chu kỳ cao và rủi ro của ngành ô
tô.
Kết luận: Có sự phân hóa rất rõ ràng về mức định
giá P/E (đã chuẩn hóa logarit) giữa các ngành. Ngành TECH
được thị trường định giá cao nhất, tiếp theo là FMCG. Các
ngành BANK và RETAIL có mức định giá tương
đương và thấp hơn, trong khi ngành AUTO có mức định giá
thấp nhất. Sự khác biệt này phản ánh kỳ vọng tăng trưởng và mức độ rủi
ro khác nhau giữa các ngành.
Leverage_Ratio theo
sector##
## So sánh Đòn bẩy Tài chính theo Ngành (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Đòn bẩy Tài chính theo Ngành
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:-------|:----------|:-----------|:-------|
## |sector |4 |5814373 |1453593.19 |139499.5 |0 |
## |Residuals |402785 |4197043 |10.42 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $sector
## diff lwr upr p adj
## BANK-AUTO 7.4731534 7.4294114 7.5168953 0
## FMCG-AUTO -1.6609884 -1.7106101 -1.6113666 0
## RETAIL-AUTO -1.8981419 -1.9402908 -1.8559929 0
## TECH-AUTO -2.8407324 -2.8832794 -2.7981853 0
## FMCG-BANK -9.1341417 -9.1834709 -9.0848125 0
## RETAIL-BANK -9.3712952 -9.4130993 -9.3294911 0
## TECH-BANK -10.3138857 -10.3560911 -10.2716803 0
## RETAIL-FMCG -0.2371535 -0.2850757 -0.1892312 0
## TECH-FMCG -1.1797440 -1.2280167 -1.1314712 0
## TECH-RETAIL -0.9425905 -0.9831426 -0.9020384 0
Nhận xét:
Kết quả ANOVA: Bảng ANOVA cho thấy
p-value = 0 (nhỏ hơn 0.05) đối với yếu tố
sector. Điều này khẳng định có sự khác biệt trung bình
rất có ý nghĩa thống kê về Mức độ Đòn bẩy
(Leverage_Ratio) giữa các ngành.
Kiểm định Post-hoc TukeyHSD: Bảng kết quả
TukeyHSD cho thấy tất cả các cặp ngành đều có sự khác biệt ý
nghĩa thống kê về Leverage_Ratio trung bình (tất
cả p adj đều bằng 0).
Diễn giải sự khác biệt (Dựa trên cột diff -
chênh lệch Leverage_Ratio trung bình):
Ngành Đòn bẩy Cao nhất: BANK có
Leverage_Ratio trung bình cao nhất, cao hơn rất đáng
kể so với tất cả các ngành khác (ví dụ: BANK-AUTO diff
= 7.47; BANK-FMCG diff = 9.13; BANK-RETAIL
diff = 9.37; BANK-TECH diff = 10.31). Điều này hoàn toàn
phù hợp với bản chất hoạt động kinh doanh của ngành ngân hàng, vốn sử
dụng đòn bẩy tài chính rất cao (huy động vốn để cho vay).
Ngành Đòn bẩy Cao thứ hai: AUTO có
Leverage_Ratio trung bình cao thứ hai, nhưng thấp hơn đáng
kể so với BANK (diff = -7.47).
Nhóm Đòn bẩy Thấp: Các ngành FMCG,
RETAIL, và TECH có mức đòn bẩy trung bình thấp
hơn và khá gần nhau. Thứ tự từ cao xuống thấp trong nhóm này là
FMCG > RETAIL > TECH (ví
dụ: FMCG-RETAIL diff = 0.24, FMCG-TECH diff =
1.18, RETAIL-TECH diff = 0.94). Ngành TECH có
mức đòn bẩy trung bình thấp nhất.
Kết luận: Có sự phân hóa cực kỳ rõ ràng về việc
sử dụng đòn bẩy tài chính giữa các ngành. Ngành BANK nổi
bật với mức đòn bẩy cao nhất do đặc thù ngành. Ngành AUTO
cũng sử dụng đòn bẩy tương đối cao. Các ngành FMCG,
RETAIL, và đặc biệt là TECH có xu hướng sử
dụng ít đòn bẩy hơn đáng kể, có thể do cấu trúc tài sản khác biệt hoặc
chính sách tài trợ thận trọng hơn.
Sharpe_Ratio theo
investment (GOOD/BAD)# Tính toán t-test
t_test_inv_sharpe <- run_t_test_calc(nyse_clean_finite, Sharpe_Ratio ~ investment)##
## --- So sánh Tỷ suất Sharpe theo Kết quả Đầu tư (t-test) ---
##
##
## Table: Bảng: Kết quả Welch t-test cho Tỷ suất Sharpe theo Kết quả Đầu tư
##
## |T-statistic |P-value |Mean Grp1 |Mean Grp2 |Chênh lệch |95% CI Low |95% CI High |
## |:-----------|:-------|:---------|:---------|:----------|:----------|:-----------|
## |-29.962 |0 |0.251 |0.261 |-0.01 |-0.01 |-0.009 |
## Kết luận: Có sự khác biệt trung bình ý nghĩa thống kê (p < 0.05).
1.3.5.7. So sánh Sharpe_Ratio theo
investment (GOOD/BAD):
Kết quả Welch t-test cho thấy p-value = 0 (nhỏ hơn 0.05).
Kết luận: Có sự khác biệt trung bình rất có
ý nghĩa thống kê về Tỷ suất Sharpe giữa nhóm GOOD và
BAD. Trung bình Sharpe_Ratio của nhóm
GOOD (Mean Grp2 = 0.261) cao hơn một chút so
với nhóm BAD (Mean Grp1 = 0.251). Mặc dù khác
biệt có ý nghĩa thống kê (do cỡ mẫu lớn), chênh lệch tuyệt đối
(difference = 0.01) là rất nhỏ, cho thấy
Sharpe_Ratio không phải là yếu tố phân biệt mạnh mẽ giữa
hai nhóm này.
amount theo
sector# Hiển thị kết quả ANOVA và TukeyHSD
display_anova_result(anova_sec_amt, "Quy mô Giao dịch", "Ngành")##
## So sánh Quy mô Giao dịch theo Ngành (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Quy mô Giao dịch theo Ngành
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:------------|:---------|:-----------|:-------|
## |sector |4 |3.617148e+08 |90428703 |0.554 |0.696 |
## |Residuals |405253 |6.613193e+13 |163186766 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $sector
## diff lwr upr p adj
## BANK-AUTO 50.9457285 -120.9121 222.80360 0.9280834
## FMCG-AUTO 0.5415207 -195.8305 196.91350 1.0000000
## RETAIL-AUTO -33.4123900 -200.2117 133.38688 0.9824036
## TECH-AUTO -19.5671184 -187.9417 148.80742 0.9978166
## FMCG-BANK -50.4042078 -244.5148 143.70636 0.9546812
## RETAIL-BANK -84.3581185 -248.4890 79.77279 0.6263713
## TECH-BANK -70.5128470 -236.2444 95.21870 0.7738686
## RETAIL-FMCG -33.9539107 -223.6004 155.69255 0.9884579
## TECH-FMCG -20.1086391 -211.1421 170.92479 0.9985180
## TECH-RETAIL 13.8452716 -146.6347 174.32522 0.9993228
Nhận xét:
Kết quả ANOVA: Bảng ANOVA cho thấy
p-value = 0.696 (lớn hơn 0.05) đối với yếu tố
sector.
Kiểm định Post-hoc TukeyHSD: Bảng kết quả TukeyHSD cho thấy p adj cho tất cả các cặp so sánh giữa các ngành đều lớn hơn 0.05 (thực tế đều rất gần 1).
Kết luận: Cả kết quả ANOVA và TukeyHSD đều đi
đến cùng một kết luận: Không có đủ bằng chứng thống kê
để nói rằng có sự khác biệt ý nghĩa về Quy mô Giao dịch trung
bình (amount) giữa các ngành
(sector). Mặc dù có thể có sự khác biệt nhỏ về giá trị
trung bình (như cột diff trong TukeyHSD cho thấy), những
khác biệt này không đủ lớn để có ý nghĩa thống kê với mức tin cậy 95%.
Điều này gợi ý rằng quy mô các khoản đầu tư (số tiền) trong bộ dữ liệu
này không phụ thuộc một cách hệ thống vào ngành nghề của cổ phiếu được
giao dịch.
ESG theo
sector##
## So sánh Xếp hạng ESG theo Ngành (ANOVA)
##
##
## Table: Bảng: Kết quả ANOVA cho Xếp hạng ESG theo Ngành
##
## |Nguồn Biến đổi |df |SS |MS |F-statistic |P-value |
## |:--------------|:------|:--------|:----------|:-----------|:-------|
## |sector |4 |5670182 |1417545.62 |49930.46 |0 |
## |Residuals |405253 |11505293 |28.39 |NA |NA |
## Kết luận ANOVA: Không thể xác định p-value (NA).
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = formula, data = data)
##
## $sector
## diff lwr upr p adj
## BANK-AUTO -1.252598 -1.324280 -1.180916 0
## FMCG-AUTO -4.790929 -4.872836 -4.709021 0
## RETAIL-AUTO -9.957872 -10.027444 -9.888299 0
## TECH-AUTO -6.303788 -6.374018 -6.233559 0
## FMCG-BANK -3.538331 -3.619295 -3.457366 0
## RETAIL-BANK -8.705274 -8.773733 -8.636814 0
## TECH-BANK -5.051190 -5.120317 -4.982063 0
## RETAIL-FMCG -5.166943 -5.246045 -5.087841 0
## TECH-FMCG -1.512860 -1.592540 -1.433179 0
## TECH-RETAIL 3.654084 3.587147 3.721020 0
Nhận xét:
Kết quả ANOVA: Bảng ANOVA cho thấy
p-value = 0 (nhỏ hơn 0.05) đối với yếu tố
sector. Điều này khẳng định có sự khác biệt trung bình
rất có ý nghĩa thống kê về Xếp hạng ESG (ESG) giữa
các ngành.
Kiểm định Post-hoc TukeyHSD (Dựa trên kết quả bạn cung
cấp): Bảng kết quả TukeyHSD cho thấy tất cả các cặp
ngành đều có sự khác biệt ý nghĩa thống kê về ESG
trung bình (tất cả p adj đều bằng 0).
Diễn giải sự khác biệt (Dựa trên cột diff -
chênh lệch ESG trung bình):
Thứ tự Xếp hạng ESG (Từ cao xuống thấp): Dựa
trên các giá trị diff (chênh lệch dương nghĩa là nhóm 1 cao
hơn nhóm 2, chênh lệch âm nghĩa là nhóm 1 thấp hơn nhóm 2), chúng ta có
thể suy ra thứ tự xếp hạng ESG trung bình của các ngành như sau:
AUTO (Cao nhất)
BANK (BANK-AUTO diff = -1.25 => BANK
thấp hơn AUTO)
TECH (TECH-BANK diff = -5.05 => TECH
thấp hơn BANK; TECH-AUTO diff = -6.30)
FMCG (FMCG-TECH diff = -1.51 => FMCG
thấp hơn TECH; FMCG-AUTO diff = -4.79)
RETAIL (Thấp nhất) (RETAIL-AUTO diff =
-9.96; RETAIL-FMCG diff = -5.17)
Mức độ Khác biệt: Sự khác biệt là rất đáng kể
giữa các ngành. Ví dụ, AUTO có ESG trung bình cao hơn
RETAIL tới gần 10 điểm. Ngành TECH và
FMCG có vẻ gần nhau hơn.
Kết luận: Có sự phân hóa rất rõ ràng về mức độ
xếp hạng ESG trung bình giữa các ngành trong bộ dữ liệu này. Ngành
AUTO và BANK có xu hướng được xếp hạng ESG cao
hơn, trong khi TECH, FMCG, và đặc biệt là
RETAIL có xếp hạng ESG trung bình thấp hơn đáng kể. Điều
này có thể phản ánh các tiêu chuẩn ESG khác nhau áp dụng cho từng ngành
hoặc mức độ ưu tiên khác nhau của các công ty trong việc thực hành
ESG.
Các phát hiện chính:
Phân tích kiểm định sự khác biệt trung bình giữa các nhóm (Mục 1.3.5.1 đến 1.3.5.9) đã cung cấp những bằng chứng thống kê quan trọng:
Yếu tố phân loại chính: Biến
investment (GOOD/BAD) cho thấy sự khác biệt trung bình rất
lớn và có ý nghĩa thống kê đối với Real_Return, khẳng định
vai trò phân loại hiệu quả của nó. Sự khác biệt về
Sharpe_Ratio giữa hai nhóm này tuy có ý nghĩa thống kê (do
cỡ mẫu lớn) nhưng chênh lệch thực tế lại rất nhỏ.
Ảnh hưởng của Ngành (sector): Ngành
nghề có ảnh hưởng đáng kể đến hầu hết các chỉ số được kiểm định, bao gồm
Real_Return, Volatility_Buy (Rủi ro),
Log_PE (Định giá), Leverage_Ratio (Đòn bẩy),
và ESG. Kết quả TukeyHSD cho thấy sự phân hóa rõ rệt, ví dụ
ngành TECH có Real_Return và Log_PE cao nhất,
BANK có Leverage_Ratio cao nhất, FMCG có
Volatility_Buy thấp nhất, RETAIL có ESG thấp
nhất. Tuy nhiên, không tìm thấy bằng chứng về sự khác biệt ý nghĩa về
Quy mô Giao dịch (amount) trung bình giữa các
ngành.
Ảnh hưởng của Chiến lược nắm giữ
(Holding_Period): Thời gian nắm giữ cũng ảnh hưởng
có ý nghĩa thống kê đến Real_Return trung bình. Kết quả
TukeyHSD cho thấy chiến lược Long-term (>180 ngày) có
lợi suất thực tế trung bình cao nhất, tiếp theo là Mid-term
và cuối cùng là Short-term.
Giải thích lựa chọn phương pháp kiểm định:
t-test vs. ANOVA: Kiểm định
t-test (cụ thể là Welch t-test, không yêu cầu phương
sai bằng nhau) được sử dụng khi so sánh giá trị trung bình giữa
hai nhóm độc lập (ví dụ: investment có 2
nhóm GOOD và BAD). Khi cần so sánh giá trị trung bình giữa ba
nhóm trở lên (ví dụ: sector có 5 nhóm,
Holding_Period có 3 nhóm), chúng ta sử dụng
ANOVA (Phân tích Phương sai). ANOVA kiểm tra giả thuyết
H0 rằng trung bình của tất cả các nhóm là bằng nhau. Nếu ANOVA có ý
nghĩa (p < 0.05), chúng ta mới thực hiện kiểm định
post-hoc (như TukeyHSD) để xác định cụ
thể những cặp nhóm nào khác biệt với nhau.
Kiểm định tham số (t-test/ANOVA) vs. Phi tham số: Mặc dù Mục 1.3.3 cho thấy nhiều biến định lượng không tuân theo phân phối chuẩn (một giả định của t-test/ANOVA), nghiên cứu này vẫn ưu tiên sử dụng các kiểm định tham số vì:
Định lý giới hạn trung tâm (CLT) và cỡ mẫu Lớn: Với cỡ mẫu cực lớn (N > 300,000), theo CLT, phân phối của trung bình mẫu có xu hướng xấp xỉ chuẩn. Điều này làm cho các kiểm định t-test và ANOVA trở nên khá “robust” (ít bị ảnh hưởng) bởi sự vi phạm giả định về tính chuẩn của dữ liệu gốc. Kết quả p-value vẫn được coi là đáng tin cậy để xác định sự tồn tại của khác biệt trung bình.
Khả năng giải thích: Các kiểm định tham số trực tiếp so sánh giá trị trung bình (mean), một chỉ số dễ hiểu và thường được quan tâm trong phân tích tài chính hơn là trung vị (median) hoặc xếp hạng (rank) mà các kiểm định phi tham số (như Wilcoxon test, Kruskal-Wallis test) sử dụng. Do đó, việc sử dụng t-test và ANOVA trong bối cảnh này, kết hợp với việc báo cáo các hạn chế về giả định, được xem là phù hợp cho mục tiêu phân tích khám phá dữ liệu (EDA).
Kết luận chung: Kết quả kiểm định cung cấp bằng chứng định lượng mạnh mẽ cho thấy các yếu tố phân loại như ngành nghề, chiến lược nắm giữ, và kết quả đầu tư có mối liên hệ ý nghĩa thống kê với hiệu suất, rủi ro, và định giá trong bộ dữ liệu NYSE này. Các phát hiện chi tiết từ TukeyHSD giúp làm rõ hơn bản chất của những khác biệt đó.
Các phân tích trước (Skewness, Kurtosis, Mean vs Median) đã cho thấy sự tồn tại của các giá trị cực đoan (outliers) trong nhiều biến định lượng. Mục này sẽ định lượng cụ thể mức độ outliers bằng phương pháp IQR (Interquartile Range) và phân tích đặc điểm của chúng.
# 1. Chọn các biến để phân tích outlier
# (Chọn các biến có độ lệch/độ nhọn cao từ Mục 1.3.3)
vars_for_outlier <- c("Real_Return", "amount", "PE", "Leverage_Ratio", "Nominal_Return")
# 2. Áp dụng hàm identify_outliers_iqr cho từng biến
outlier_results_list <- lapply(vars_for_outlier, function(var) {
identify_outliers_iqr(nyse_clean_core, var)
})
# 3. Chuyển list kết quả thành data frame để trình bày
outlier_threshold_df <- do.call(rbind, lapply(outlier_results_list, function(res) {
data.frame(
Variable = res$var_name,
Q1 = round(res$Q1, 3),
Q3 = round(res$Q3, 3),
IQR = round(res$IQR, 3),
Lower_Bound = round(res$Lower_Bound, 3),
Upper_Bound = round(res$Upper_Bound, 3)
)
}))
# 4. Trình bày bảng ngưỡng Outlier
cat("\n 1.3.6.1: Xác định Ngưỡng Ngoại lai bằng Phương pháp IQR \n")##
## 1.3.6.1: Xác định Ngưỡng Ngoại lai bằng Phương pháp IQR
kable(outlier_threshold_df,
caption = "Bảng 1.3.18: Ngưỡng xác định Giá trị Ngoại lai (Outlier) bằng Phương pháp IQR",
col.names = c("Tên Biến", "Q1", "Q3", "IQR", "Ngưỡng Dưới (Q1-1.5*IQR)", "Ngưỡng Trên (Q3+1.5*IQR)"),
format = "pipe", align = "l")| Tên Biến | Q1 | Q3 | IQR | Ngưỡng Dưới (Q1-1.5*IQR) | Ngưỡng Trên (Q3+1.5*IQR) | |
|---|---|---|---|---|---|---|
| 25% | Real_Return | -0.621 | 0.486 | 1.107 | -2.281 | 2.146 |
| 25%1 | amount | 400.000 | 10000.000 | 9600.000 | -14000.000 | 24400.000 |
| 25%2 | PE | 9.820 | 23.490 | 13.670 | -10.685 | 43.995 |
| 25%3 | Leverage_Ratio | 2.486 | 6.692 | 4.207 | -3.824 | 13.002 |
| 25%4 | Nominal_Return | -0.028 | 0.111 | 0.140 | -0.238 | 0.321 |
Nhận xét:
Bảng 1.3.18 trình bày các ngưỡng dưới (Lower Bound) và ngưỡng trên (Upper Bound) được tính toán bằng phương pháp IQR (Q1 - 1.5IQR và Q3 + 1.5IQR) để xác định các giá trị ngoại lai tiềm năng cho 5 biến có độ lệch cao:
Lợi suất Thực tế (Real_Return):
Khoảng tứ phân vị (IQR) là 1.107 (từ Q1=-0.621 đến Q3=0.486).
Ngưỡng outlier được xác định là các giá trị dưới -2.281 (-228.1%) hoặc trên 2.146 (+214.6%). Bất kỳ lợi suất nào nằm ngoài khoảng rộng này đều được coi là ngoại lai.
Quy mô Giao dịch (amount):
IQR là 9,600 USD (từ Q1=400 đến Q3=10,000).
Ngưỡng outlier là các giá trị dưới -14,000 USD (không thực tế vì amount luôn dương) hoặc trên 24,400 USD. Các giao dịch có quy mô lớn hơn 24,400 USD được coi là ngoại lai.
Định giá (PE - Gốc):
IQR là 13.67 (từ Q1=9.82 đến Q3=23.49).
Ngưỡng outlier là các giá trị dưới -10.685 (P/E
âm đã bị loại bỏ khi tính Log_PE) hoặc trên
43.995. Các công ty có P/E dương cao hơn ~44 lần được coi là có
định giá ngoại lai.
Đòn bẩy (Leverage_Ratio):
IQR là 4.207 (từ Q1=2.486 đến Q3=6.692).
Ngưỡng outlier là các giá trị dưới -3.824 (không thực tế vì Leverage_Ratio > 1) hoặc trên 13.002. Các công ty có tỷ lệ ROE/ROA cao hơn ~13 lần được coi là có mức đòn bẩy ngoại lai (hoặc ROA rất nhỏ).
Lợi suất Danh nghĩa
(Nominal_Return):
IQR là 0.140 (từ Q1=-0.028 đến Q3=0.111).
Ngưỡng outlier là các giá trị dưới -0.238
(-23.8%) hoặc trên 0.321 (+32.1%). Khoảng ngưỡng này
hẹp hơn đáng kể so với Real_Return, phản ánh tác động của
biến inflation (có giá trị âm) đã khuếch đại biên độ của
Real_Return.
Kết luận: Các ngưỡng IQR cung cấp một định nghĩa định lượng rõ ràng cho các giá trị ngoại lai. Bước tiếp theo (1.3.6.2) sẽ sử dụng các ngưỡng này để đếm số lượng và tỷ lệ outlier thực tế trong dữ liệu.
# 1. Chuyển list kết quả thành data frame chứa số lượng outlier
outlier_count_df <- do.call(rbind, lapply(outlier_results_list, function(res) {
data.frame(
Variable = res$var_name,
Num_Outliers_Low = res$Num_Outliers_Low,
Num_Outliers_High = res$Num_Outliers_High,
Total_Outliers = res$Total_Outliers,
Total_NonNA = res$Total_NonNA # Tổng số quan sát không NA của biến đó
)
}))
# 2. Tính toán tỷ lệ phần trăm outlier
outlier_percentage_df <- outlier_count_df %>%
mutate(
# Tỷ lệ outlier = Tổng outlier / Tổng số quan sát không NA
Percentage_Outliers = round((Total_Outliers / Total_NonNA) * 100, 2)
) %>%
# Sắp xếp theo tỷ lệ giảm dần
arrange(desc(Percentage_Outliers))
# 3. Trình bày bảng Tỷ lệ Outlier
cat("\n 1.3.6.2: Định lượng Tỷ lệ Phần trăm Ngoại lai \n")##
## 1.3.6.2: Định lượng Tỷ lệ Phần trăm Ngoại lai
kable(outlier_percentage_df %>% select(Variable, Total_Outliers, Total_NonNA, Percentage_Outliers),
caption = "Bảng 1.3.19: Số lượng và Tỷ lệ Phần trăm Giá trị Ngoại lai",
col.names = c("Tên Biến", "Số lượng Outlier", "Tổng Quan sát (Không NA)", "Tỷ lệ Outlier (%)"),
format = "pipe", align = "l")| Tên Biến | Số lượng Outlier | Tổng Quan sát (Không NA) | Tỷ lệ Outlier (%) |
|---|---|---|---|
| Nominal_Return | 54140 | 405258 | 13.36 |
| amount | 47556 | 405258 | 11.73 |
| PE | 37258 | 405258 | 9.19 |
| Leverage_Ratio | 22506 | 402790 | 5.59 |
| Real_Return | 3140 | 405258 | 0.77 |
Bảng 1.3.19 định lượng số lượng và tỷ lệ phần trăm các giá trị được xác định là ngoại lai (outlier) theo phương pháp IQR (nằm ngoài khoảng [Q1 - 1.5IQR, Q3 + 1.5IQR]) cho 5 biến được kiểm tra:
Mức độ Outlier Cao:
Nominal_Return: Có tỷ lệ outlier
cao nhất với 13.36% (54,140 quan sát). Điều này phù hợp
với độ nhọn cực cao đã thấy ở Mục 1.3.3.2, cho thấy lợi suất danh nghĩa
có phần đuôi rất dày chứa nhiều giá trị cực đoan (cả lãi rất cao và lỗ
rất sâu).
amount: Có tỷ lệ outlier cao thứ
hai với 11.73% (47,556 quan sát). Điều này chỉ ra rằng
có một tỷ lệ đáng kể các giao dịch được thực hiện với số tiền rất lớn
(cao hơn ngưỡng 24,400 USD).
PE (Gốc): Có tỷ lệ outlier là
9.19% (37,258 quan sát). Tỷ lệ này phản ánh sự tồn tại
của nhiều công ty có P/E rất cao (> 44 lần) trong mẫu dữ
liệu.
Mức độ Outlier Trung bình:
Leverage_Ratio: Có tỷ lệ outlier là
5.59% (22,506 quan sát). Tỷ lệ này cho thấy có một số
lượng đáng kể các công ty sử dụng mức đòn bẩy rất cao (> 13 lần
ROE/ROA), nhưng ít phổ biến hơn so với outlier về lợi suất hay quy mô.
Lưu ý rằng Total_NonNA (402,790) thấp hơn tổng số quan sát
do đã loại bỏ các trường hợp ROA gần 0.Mức độ Outlier Thấp:
Real_Return: Đáng ngạc nhiên là
Real_Return chỉ có tỷ lệ outlier rất thấp
0.77% (3,140 quan sát). Mặc dù nó có độ nhọn cao thứ
hai (Kurtosis = 31.9), phương pháp IQR lại xác định ít outlier hơn so
với Nominal_Return. Điều này có thể do biến
inflation (thường âm) đã “kéo dãn” khoảng IQR của
Real_Return (IQR = 1.107) so với
Nominal_Return (IQR = 0.140), khiến các ngưỡng outlier trở
nên rộng hơn và ít giá trị bị coi là cực đoan hơn theo định nghĩa
này.Kết luận: Phân tích định lượng cho thấy outliers là
một đặc điểm phổ biến trong dữ liệu lợi suất
(Nominal_Return), quy mô giao dịch (amount),
và định giá (PE). Leverage_Ratio cũng có một
tỷ lệ outlier đáng kể. Real_Return, mặc dù có đuôi dày, lại
có ít outlier hơn theo định nghĩa IQR do khoảng IQR rộng hơn. Sự hiện
diện của outliers nhấn mạnh tầm quan trọng của việc sử dụng các thước đo
thống kê robust (như Median thay vì Mean) và cần xem xét các kỹ thuật xử
lý outlier hoặc mô hình hóa phù hợp ở các bước sau.
# 1. Lấy ngưỡng outlier cho Real_Return từ kết quả trước
cat("\n 1.3.6.3: Phân tích Đặc điểm Ngoại lai của Lợi suất Thực tế \n")##
## 1.3.6.3: Phân tích Đặc điểm Ngoại lai của Lợi suất Thực tế
rr_outlier_info <- outlier_results_list[[which(sapply(outlier_results_list, `[[`, "var_name") == "Real_Return")]]
rr_lower_bound <- rr_outlier_info$Lower_Bound
rr_upper_bound <- rr_outlier_info$Upper_Bound
cat(paste("Ngưỡng Outlier cho Real_Return: Dưới", round(rr_lower_bound, 3), "và Trên", round(rr_upper_bound, 3), "\n"))## Ngưỡng Outlier cho Real_Return: Dưới -2.281 và Trên 2.146
# 2. Tạo data frame chỉ chứa các outlier của Real_Return
real_return_outliers <- nyse_clean_core %>%
filter(Real_Return < rr_lower_bound | Real_Return > rr_upper_bound)
# 3. Phân tích đặc điểm: Tần suất theo Ngành (sector)
cat("\nPhân bổ Outlier Lợi suất Thực tế theo Ngành:\n")##
## Phân bổ Outlier Lợi suất Thực tế theo Ngành:
outlier_by_sector <- real_return_outliers %>%
count(sector, name = "SoLuongOutlier") %>%
mutate(TyLeTrongOutlier = round((SoLuongOutlier / sum(SoLuongOutlier)) * 100, 2)) %>%
arrange(desc(SoLuongOutlier))
kable(outlier_by_sector,
caption = "Bảng 1.3.20: Phân bổ Outlier Lợi suất Thực tế theo Ngành",
col.names = c("Ngành", "Số lượng Outlier", "Tỷ lệ trong Tổng Outlier (%)"),
format = "pipe", align = "l")| Ngành | Số lượng Outlier | Tỷ lệ trong Tổng Outlier (%) |
|---|---|---|
| TECH | 2785 | 88.69 |
| RETAIL | 241 | 7.68 |
| BANK | 80 | 2.55 |
| AUTO | 34 | 1.08 |
# 4. Phân tích đặc điểm: Tần suất theo Năm mua (Buy_Year)
cat("\nPhân bổ Outlier Lợi suất Thực tế theo Năm Mua:\n")##
## Phân bổ Outlier Lợi suất Thực tế theo Năm Mua:
outlier_by_year <- real_return_outliers %>%
count(Buy_Year, name = "SoLuongOutlier") %>%
mutate(TyLeTrongOutlier = round((SoLuongOutlier / sum(SoLuongOutlier)) * 100, 2)) %>%
arrange(Buy_Year) # Sắp xếp theo năm
kable(outlier_by_year,
caption = "Bảng 1.3.21: Phân bổ Outlier Lợi suất Thực tế theo Năm Mua",
col.names = c("Năm Mua", "Số lượng Outlier", "Tỷ lệ trong Tổng Outlier (%)"),
format = "pipe", align = "l")| Năm Mua | Số lượng Outlier | Tỷ lệ trong Tổng Outlier (%) |
|---|---|---|
| 2014 | 82 | 2.61 |
| 2015 | 2176 | 69.30 |
| 2016 | 882 | 28.09 |
Nhận xét:
Phân tích đặc điểm của 3,140 giao dịch có Lợi suất Thực tế
(Real_Return) được xác định là ngoại lai (dưới -228.1% hoặc
trên +214.6%) theo phương pháp IQR:
Phân bổ theo Ngành (Bảng 1.3.20):
Tập trung cao độ: Các giá trị lợi suất cực đoan
(cả âm và dương) tập trung chủ yếu vào ngành TECH (Công
nghệ), chiếm tới 88.69% tổng số outlier. Ngành
RETAIL (Bán lẻ) đứng thứ hai nhưng chỉ chiếm
7.68%. Các ngành BANK (2.55%) và
AUTO (1.08%) có rất ít outlier về lợi suất. (Lưu ý: Ngành
FMCG không xuất hiện, nghĩa là không có outlier nào thuộc
ngành này).
Ý nghĩa: Điều này cho thấy ngành Công nghệ là ngành có biến động lợi suất mạnh nhất và tiềm ẩn nhiều rủi ro/cơ hội cực đoan nhất trong bộ dữ liệu này. Các ngành khác có vẻ ổn định hơn về mặt lợi suất.
Phân bổ theo Năm Mua (Bảng 1.3.21):
Tập trung vào Giai đoạn Khủng hoảng/Biến động: Phần lớn các outlier (lợi suất cực đoan) xảy ra trong các giao dịch được thực hiện vào năm 2015 (69.30%) và 2016 (28.09%). Hai năm này chiếm tới 97.39% tổng số outlier. Năm 2014 chỉ chiếm 2.61%. (Lưu ý: Các năm 2013, 2017, 2018 không xuất hiện, nghĩa là không có outlier nào được mua vào các năm đó).
Ý nghĩa: Kết quả này cho thấy giai đoạn 2015-2016 là giai đoạn thị trường có biến động mạnh nhất, tạo ra nhiều cơ hội siêu lợi nhuận hoặc thua lỗ cực lớn, đặc biệt là trong ngành Công nghệ. Các năm khác có vẻ ổn định hơn.
Kết luận: Phân tích đặc điểm outlier của
Real_Return cho thấy chúng không phân bổ ngẫu nhiên mà tập
trung mạnh vào ngành Công nghệ (TECH) và
các giao dịch được thực hiện trong giai đoạn 2015-2016.
Điều này gợi ý rằng các mô hình phân tích hoặc dự báo cần xem xét đến
yếu tố ngành và yếu tố thời gian (chu kỳ thị trường) để giải thích hoặc
kiểm soát các biến động lợi suất cực đoan này.
(So sánh Mean và SD của Real_Return trước và sau khi
loại bỏ outlier)
# 1. Tính Mean và SD gốc (đã có từ Mục 1.3.1)
cat("\n 1.3.6.4: Đánh giá ảnh hưởng của ngoại lai lên thống kê Lợi suất \n")##
## 1.3.6.4: Đánh giá ảnh hưởng của ngoại lai lên thống kê Lợi suất
mean_rr_original <- mean(nyse_clean_core$Real_Return, na.rm = TRUE)
sd_rr_original <- sd(nyse_clean_core$Real_Return, na.rm = TRUE)
# 2. Tạo data frame không chứa outlier của Real_Return
nyse_no_rr_outliers <- nyse_clean_core %>%
filter(Real_Return >= rr_lower_bound & Real_Return <= rr_upper_bound)
# 3. Tính Mean và SD sau khi loại bỏ outlier
mean_rr_no_outlier <- mean(nyse_no_rr_outliers$Real_Return, na.rm = TRUE)
sd_rr_no_outlier <- sd(nyse_no_rr_outliers$Real_Return, na.rm = TRUE)
# 4. Tạo bảng so sánh
impact_df <- data.frame(
Metric = c("Mean (Trung bình)", "SD (Độ lệch chuẩn)"),
Original = round(c(mean_rr_original, sd_rr_original), 3),
Without_Outliers = round(c(mean_rr_no_outlier, sd_rr_no_outlier), 3)
)
# 5. Trình bày bảng so sánh
kable(impact_df,
caption = "Bảng 1.3.22: So sánh Thống kê Lợi suất Thực tế Trước và Sau khi Loại bỏ Outlier",
col.names = c("Chỉ số Thống kê", "Giá trị Gốc", "Giá trị Sau khi Loại bỏ Outlier"),
format = "pipe", align = "l")| Chỉ số Thống kê | Giá trị Gốc | Giá trị Sau khi Loại bỏ Outlier |
|---|---|---|
| Mean (Trung bình) | 0.087 | 0.057 |
| SD (Độ lệch chuẩn) | 0.774 | 0.666 |
Nhận xét:
Bảng 1.3.22 so sánh giá trị Trung bình (Mean) và Độ lệch chuẩn (SD)
của Lợi suất Thực tế (Real_Return) trước và sau khi loại bỏ
0.77% các giá trị ngoại lai (outlier) được xác định bằng phương pháp
IQR.
Ảnh hưởng lên Trung bình (Mean): Giá trị trung
bình đã giảm từ 0.087 (8.7%) xuống còn
0.057 (5.7%) sau khi loại bỏ outliers. Sự sụt giảm này cho
thấy các outliers bị loại bỏ có xu hướng nghiêng về phía giá trị dương
rất lớn (ví dụ: Max = 16.353), làm “thổi phồng” giá trị trung bình gốc.
Giá trị trung bình mới (5.7%) thấp hơn đáng kể so với trung vị (16.7%),
tiếp tục khẳng định tính lệch trái của phần lớn dữ liệu còn lại (sau khi
bỏ outliers).
Ảnh hưởng lên Độ lệch chuẩn (SD): Độ lệch chuẩn
cũng giảm từ 0.774 xuống
0.666. Việc loại bỏ các giá trị cực đoan ở hai đầu đuôi
phân phối đã làm giảm mức độ phân tán tổng thể của dữ liệu, làm cho SD
nhỏ hơn. Tuy nhiên, SD sau khi loại bỏ outlier (0.666) vẫn còn rất lớn
so với trung bình (0.057), cho thấy Real_Return vẫn là một
biến có độ biến động rất cao ngay cả khi đã loại bỏ các giá trị cực đoan
nhất theo định nghĩa IQR.
Kết luận: Outliers có tác động đáng kể lên các thước đo thống kê mô tả cơ bản như Mean và SD. Giá trị trung bình gốc (8.7%) bị ảnh hưởng mạnh bởi các khoản lãi cực lớn. Độ lệch chuẩn cũng bị ảnh hưởng bởi biên độ rộng do outliers tạo ra. Việc loại bỏ outliers giúp có cái nhìn ổn định hơn về xu hướng trung tâm và độ phân tán của phần lớn dữ liệu, nhưng cũng cần lưu ý rằng outliers là một phần bản chất của dữ liệu lợi suất tài chính và việc loại bỏ chúng có thể làm mất thông tin về rủi ro đuôi (tail risk).
library(dplyr)
library(ggplot2) # Thư viện trực quan hóa chính
library(scales) # Để định dạng trục (vd: percent, comma)
library(knitr) # Để hiển thị bảng (nếu cần)
library(tidyr) # Để xử lý dữ liệu (pivot_longer)
library(plotly) # Sẽ dùng ở các mục sau
# Tải dữ liệu đã xử lý
load("nyse_processed_final.RData") Real_Return)# 1. Chuẩn bị dữ liệu: Chuyển sang dạng dài và lọc bớt giá trị cực đoan để dễ nhìn
return_comparison_long_viz <- nyse_clean_core %>%
select(Nominal_Return, Real_Return) %>%
# Lọc bỏ NA và các giá trị quá lớn/nhỏ để tập trung vào phần chính của phân bố
filter(!is.na(Nominal_Return), !is.na(Real_Return),
Nominal_Return > -1 & Nominal_Return < 2, # Giới hạn trục X cho Nominal
Real_Return > -1 & Real_Return < 2) %>% # Giới hạn trục X cho Real
pivot_longer(
cols = everything(),
names_to = "Return_Type",
values_to = "Return_Value"
)
# 2. Vẽ Biểu đồ Mật độ (Density Plot) bằng ggplot2
p_return_density <- ggplot(return_comparison_long_viz, aes(x = Return_Value, fill = Return_Type)) +
# geom_density vẽ đường cong ước lượng mật độ
# alpha = 0.6 giúp nhìn xuyên qua các lớp màu
geom_density(alpha = 0.6) +
# Thêm đường dọc tại x=0 để phân biệt lãi/lỗ
geom_vline(xintercept = 0, linetype = "dashed", color = "red") +
# Định dạng trục X thành tỷ lệ phần trăm
scale_x_continuous(labels = scales::percent_format(accuracy = 1)) +
# Đặt tiêu đề và nhãn trục
labs(title = "Biểu đồ 1.4.1: So sánh phân bố Lợi suất Thực tế và Danh nghĩa",
subtitle = "Đã lọc giá trị ngoài khoảng [-100%, +200%] để dễ nhìn",
x = "Lợi suất",
y = "Mật độ Ước lượng",
fill = "Loại Lợi suất") + # Tiêu đề cho phần chú thích màu
# Sử dụng theme tối giản
theme_minimal() +
# Điều chỉnh vị trí chú thích (legend)
theme(legend.position = "bottom")
# 3. Hiển thị biểu đồ
print(p_return_density)sector)# 1. Tính toán số lượng theo ngành (trong mục 1.3.2.1)
sector_freq_viz <- nyse_clean_core %>%
count(sector, name = "Count") %>%
arrange(desc(Count))
# 2. Vẽ Biểu đồ Cột (Bar Chart) bằng ggplot2
p_sector_bar <- ggplot(sector_freq_viz,
# aes() định nghĩa ánh xạ: trục X là ngành (sắp xếp lại), trục Y là số lượng
# reorder() sắp xếp các thanh theo Count giảm dần
aes(x = reorder(sector, Count), y = Count, fill = sector)) +
# geom_col vẽ biểu đồ cột với chiều cao tương ứng giá trị Y
geom_col(show.legend = FALSE) + # Ẩn chú thích màu vì trục X đã thể hiện
# geom_text thêm nhãn số lượng trên đỉnh cột
# stat="identity" dùng giá trị Y trực tiếp, nudge_y đẩy nhẹ nhãn lên trên
geom_text(aes(label = scales::comma(Count)), stat = "identity", nudge_y = 5000, size = 3.5) +
# coord_flip() lật trục X và Y để tên ngành dễ đọc hơn
coord_flip() +
# Định dạng trục Y với dấu phẩy ngăn cách hàng nghìn
scale_y_continuous(labels = scales::comma) +
# Đặt tiêu đề và nhãn trục
labs(title = "Biểu đồ 1.4.2: Tần suất Giao dịch theo Ngành",
x = "Ngành (Sector)",
y = "Số lượng Giao dịch") +
# Sử dụng theme tối giản
theme_minimal()
# 3. Hiển thị biểu đồ
print(p_sector_bar)investment)# 1. Tính toán số lượng theo investment (trong mục 1.3.2.1)
investment_freq_viz <- nyse_clean_core %>%
count(investment, name = "Count")
# 2. Vẽ Biểu đồ Cột
p_investment_bar <- ggplot(investment_freq_viz, aes(x = investment, y = Count, fill = investment)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = scales::comma(Count)), vjust = -0.5, size = 4) + # vjust điều chỉnh vị trí nhãn theo chiều dọc
scale_y_continuous(labels = scales::comma) +
labs(title = "Biểu đồ 1.4.3: Tần suất Giao dịch theo Kết quả Đầu tư (GOOD/BAD)",
x = "Kết quả Đầu tư",
y = "Số lượng Giao dịch") +
theme_minimal()
# 3. Hiển thị biểu đồ
print(p_investment_bar)Holding_Period)# 1. Tính toán số lượng theo Holding_Period (trong mục 1.3.2.1 / 1.1.3.6)
holding_freq_viz <- nyse_clean_core %>%
count(Holding_Period, name = "Count")
# 2. Vẽ Biểu đồ Cột
p_holding_bar <- ggplot(holding_freq_viz, aes(x = Holding_Period, y = Count, fill = Holding_Period)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = scales::comma(Count)), vjust = -0.5, size = 4) +
scale_y_continuous(labels = scales::comma) +
labs(title = "Biểu đồ 1.4.4: Tần suất Giao dịch theo Thời gian Nắm giữ",
x = "Thời gian Nắm giữ",
y = "Số lượng Giao dịch") +
theme_minimal()
# 3. Hiển thị biểu đồ
print(p_holding_bar)Log_PE)# 1. Vẽ Biểu đồ Histogram kết hợp Density Plot cho Log_PE
p_logpe_hist <- ggplot(nyse_clean_core, aes(x = Log_PE)) +
# geom_histogram vẽ biểu đồ tần suất dạng cột
# bins = 50 chia thành 50 khoảng giá trị
# fill задает цвет заливки, color - цвет контура
geom_histogram(aes(y = after_stat(density)), # Trục Y là mật độ thay vì tần suất
bins = 50, fill = "#1F77B4", color = "white", alpha = 0.7) +
# geom_density vẽ đường cong mật độ ước lượng
geom_density(color = "red", linewidth = 1) + # linewidth thay cho size
# Đặt tiêu đề và nhãn trục
labs(title = "Biểu đồ 1.4.5: Phân bố Tỷ suất P/E sau Chuẩn hóa Logarit (Log_PE)",
subtitle = "Histogram (Mật độ) và Đường cong Mật độ Ước lượng",
x = "Giá trị Log(PE)",
y = "Mật độ (Density)") +
# Sử dụng theme tối giản
theme_minimal()
# 2. Hiển thị biểu đồ
print(p_logpe_hist)Real_Return)# 1. Vẽ Box Plot cho Real_Return
p_realreturn_box <- ggplot(nyse_clean_core, aes(x = "", y = Real_Return)) + # x="" để vẽ 1 boxplot duy nhất
# geom_boxplot vẽ biểu đồ hộp
# outlier.shape=1 vẽ outlier dạng vòng tròn rỗng (dễ nhìn hơn điểm đặc)
# outlier.alpha=0.3 làm mờ outlier
geom_boxplot(fill = "lightblue", outlier.shape = 1, outlier.alpha = 0.3) +
# Định dạng trục Y thành tỷ lệ phần trăm
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
# Đặt tiêu đề và nhãn trục (bỏ nhãn trục X)
labs(title = "Biểu đồ 1.4.6: Phân bố Lợi suất Thực tế (Real_Return)",
subtitle = "Boxplot thể hiện Median, IQR và Outliers",
x = "",
y = "Lợi suất Thực tế (%)") +
# Sử dụng theme tối giản
theme_minimal() +
# Xóa các yếu tố không cần thiết của trục X
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank())
# 2. Hiển thị biểu đồ
print(p_realreturn_box)amount)# 1. Vẽ Box Plot cho amount
p_amount_box <- ggplot(nyse_clean_core, aes(x = "", y = amount)) +
geom_boxplot(fill = "lightgreen", outlier.shape = 1, outlier.alpha = 0.1) + # alpha thấp hơn do nhiều outlier
# Sử dụng thang log10 cho trục Y do độ lệch rất lớn của amount
# Điều này giúp "nén" các giá trị lớn lại để thấy rõ hơn phần hộp và râu
scale_y_log10(labels = scales::comma_format()) + # Định dạng số với dấu phẩy
# Đặt tiêu đề và nhãn trục
labs(title = "Biểu đồ 1.4.7: Phân bố Quy mô Giao dịch (amount)",
subtitle = "Boxplot thể hiện Median, IQR và Outliers (Trục Y Logarit)",
x = "",
y = "Số tiền Đầu tư (USD, thang Log10)") +
theme_minimal() +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank())
# 2. Hiển thị biểu đồ
print(p_amount_box)Leverage_Ratio)# 1. Vẽ Histogram kết hợp Density Plot cho Leverage_Ratio
# Lọc bỏ NA và có thể lọc giá trị quá lớn để dễ nhìn hơn
p_leverage_hist <- ggplot(nyse_clean_core %>% filter(!is.na(Leverage_Ratio) & Leverage_Ratio < 20),
aes(x = Leverage_Ratio)) + # Giới hạn trục X < 20
geom_histogram(aes(y = after_stat(density)), bins = 50,
fill = "#FF7F0E", color = "white", alpha = 0.7) +
geom_density(color = "blue", linewidth = 1) +
labs(title = "Biểu đồ 1.4.8: Phân bố Tỷ số Đòn bẩy Tài chính (Leverage_Ratio)",
subtitle = "Đã lọc NA và giá trị > 20 để dễ nhìn",
x = "Đòn bẩy Tài chính (ROE/ROA)",
y = "Mật độ (Density)") +
theme_minimal()
# 2. Hiển thị biểu đồ
print(p_leverage_hist)Volatility_Buy)# 1. Vẽ Histogram kết hợp Density Plot cho Volatility_Buy
p_volatility_hist <- ggplot(nyse_clean_core, aes(x = Volatility_Buy)) +
geom_histogram(aes(y = after_stat(density)), bins = 50,
fill = "#9467BD", color = "white", alpha = 0.7) +
geom_density(color = "black", linewidth = 1) +
labs(title = "Biểu đồ 1.4.9: Phân bố Rủi ro Đầu tư (Volatility_Buy)",
x = "Độ biến động tại thời điểm Mua",
y = "Mật độ (Density)") +
theme_minimal()
# 2. Hiển thị biểu đồ
print(p_volatility_hist)Sharpe_Ratio)# 1. Vẽ Histogram kết hợp Density Plot cho Sharpe_Ratio
p_sharpe_hist <- ggplot(nyse_clean_core, aes(x = Sharpe_Ratio)) +
geom_histogram(aes(y = after_stat(density)), bins = 50,
fill = "#8C564B", color = "white", alpha = 0.7) +
geom_density(color = "darkred", linewidth = 1) +
labs(title = "Biểu đồ 1.4.10: Phân bố Tỷ suất Sharpe",
x = "Sharpe Ratio",
y = "Mật độ (Density)") +
theme_minimal()
# 2. Hiển thị biểu đồ
print(p_sharpe_hist)Mục tiêu chính là phân tích sức khỏe tài chính và hiệu quả hoạt động của Tổng Công ty Khí Việt Nam (GAS) trong giai đoạn 11 năm (2014-2024). Phân tích cũng tìm cách khám phá mối quan hệ (nếu có) giữa các chỉ số tài chính nội tại và giá trị thị trường của cổ phiếu.
Bộ dữ liệu được xây dựng từ hai nguồn chính:
Dữ liệu tài chính: Trích xuất từ các Báo cáo tài chính hợp nhất đã được kiểm toán (Bảng Cân đối Kế toán, Bảng Kết quả Kinh doanh, Bảng Lưu Chuyển Tiền Tệ) hàng năm của GAS, từ 31/12/2014 đến 31/12/2024.
Dữ liệu thị trường: Thu thập từ các nguồn dữ liệu thị trường (ví dụ: CafeF, Vietstock) về giá cổ phiếu tại ngày chốt báo cáo (31/12 hàng năm).
Đơn vị quan sát và phạm vi
Đơn vị quan sát: Dữ liệu được tổng hợp theo năm.
Phạm vi thời gian: 11 năm, từ 2014 đến 2024.
Cấu trúc bộ dữ liệu (Các biến số):
Bộ dữ liệu GAS_data_final sau khi xử lý (ở mục 2.3) sẽ bao gồm 12 biến sau:
Biến định danh (Identifier):
Biến Tài chính Cơ bản (Trích xuất từ BCTC):
DoanhThu: (Numeric) Doanh thu thuần hàng năm.
LoiNhuanSauThue: (Numeric) Lợi nhuận sau thuế của cổ đông công ty mẹ.
TongTaiSan: (Numeric) Tổng cộng tài sản cuối kỳ.
NoPhaiTra: (Numeric) Tổng nợ phải trả cuối kỳ.
VonChuSoHuu: (Numeric) Tổng vốn chủ sở hữu cuối kỳ.
Biến Thị trường:
Biến Phái sinh (Được tính toán - Feature Engineering):
ROE_Nam: (Numeric) Tỷ suất lợi nhuận trên vốn chủ sở hữu (LNST / VCSH).
ROA_Nam: (Numeric) Tỷ suất lợi nhuận trên tổng tài sản (LNST / Tổng Tài sản).
TySoNo_Tren_VCSH: (Numeric) Tỷ số Nợ trên Vốn chủ sở hữu, đo lường đòn bẩy tài chính.
DoanhThu_TangTruong_YoY: (Numeric) Tỷ lệ % tăng trưởng doanh thu so với năm trước.
LoiNhuan_TangTruong_YoY: (Numeric) Tỷ lệ % tăng trưởng lợi nhuận so với năm trước.
# 1. Tải thư viện
library(readxl) # Dùng để đọc file Excel
library(dplyr) # Dùng để xử lý dữ liệu (rename, mutate, filter...)
library(stringr) # Dùng để xử lý chuỗi (str_remove_all)
# 2. Đọc dữ liệu từ excel
bctc_path <- "C:/Users/Admin/Documents/NGÔN NGỮ R/PV GAS.xlsx"
# 3. Đọc sheet cụ thể
bckt_raw <- read_excel(bctc_path, sheet = 1) # Bảng Cân đối Kế toán
kqkd_raw <- read_excel(bctc_path, sheet = 2) # Bảng Kết quả Kinh doanh
# 4. Chuẩn hóa tên cột
# Đổi tên cột đầu tiên (chỉ tiêu) thành "ChiTieu" cho cả 2 bảng
if ("TÀI SẢN" %in% names(bckt_raw)) { # Dùng 'if' để kiểm tra xem cột 'TÀI SẢN' (%in%) có tồn tại trong danh sách tên cột (names()) của bckt_raw không
bckt_raw <- bckt_raw %>% rename(ChiTieu = `TÀI SẢN`)} # Nếu có, dùng 'rename' đổi tên cột 'TÀI SẢN' thành 'ChiTieu'
if ("CHỈ TIÊU" %in% names(kqkd_raw)) {kqkd_raw <- kqkd_raw %>% rename(ChiTieu = `CHỈ TIÊU`)}
print("Đã chuẩn hóa tên cột thành 'ChiTieu'.")## [1] "Đã chuẩn hóa tên cột thành 'ChiTieu'."
# PHẦN 1: HÀM HỖ TRỢ
# 1. Hàm trích xuất (với gỡ lỗi 'fixed = TRUE')
extract_row_data <- function(df, chi_tieu_name) {
# Lọc hàng dựa trên chuỗi ký tự chính xác (fixed = TRUE)
data_row <- df %>%
filter(grepl(chi_tieu_name, ChiTieu, ignore.case = TRUE, fixed = TRUE))
# Báo lỗi nếu không tìm thấy (giúp gỡ lỗi)
if(nrow(data_row) == 0) {
stop(paste("\n--- LỖI TÌM KIẾM (fixed=TRUE) ---",
"\nKhông tìm thấy chỉ tiêu nào khớp CHÍNH XÁC với chuỗi:",
"\n'", chi_tieu_name, "'",
"\n>>> Hãy kiểm tra chuỗi này từ file Excel"))
}
# Báo lỗi nếu tìm thấy nhiều hơn 1 hàng (đảm bảo tính duy nhất)
if(nrow(data_row) > 1) {
stop(paste("\n--- LỖI TÌM KIẾM (fixed=TRUE) ---",
"\nTìm thấy nhiều hơn 1 hàng khớp với chuỗi:",
"\n'", chi_tieu_name, "'",
"\n>>> Hãy cung cấp chuỗi ký tự ở phần 3 sao cho nó là duy nhất."))
}
# Chọn 11 cột dữ liệu (ứng với 2014-2024) và chuyển thành vector
data_vec <- data_row %>%
select(-ChiTieu) %>% # Bỏ cột 'ChiTieu'
select(1:11) %>% # Lấy 11 cột (2014 -> 2024)
unlist(use.names = FALSE) # Chuyển thành vector
return(data_vec)
}
# 2. Hàm làm sạch số (loại bỏ dấu ".")
clean_numeric <- function(x) {
x_char <- as.character(x) # Chuyển sang dạng text
x_cleaned <- str_remove_all(x_char, "\\.") # Loại bỏ tất cả dấu chấm
return(as.numeric(x_cleaned)) # Chuyển về dạng số
}
# PHẦN 2: TRÍCH XUẤT VÀ LÀM SẠCH
print("Bắt đầu trích xuất dữ liệu...")## [1] "Bắt đầu trích xuất dữ liệu..."
nam_vec <- 2014:2024 # Tạo vector 11 năm
# 3. Trích xuất các chỉ tiêu cốt lõi
# Từ KQKD
dt_vec <- extract_row_data(kqkd_raw, "3. Doanh thu thuần về bán hàng và cung cấp dịch vụ")
lnst_vec <- extract_row_data(kqkd_raw, "18.1. Lợi nhuận sau thuế của cổ đông của Công ty mẹ")
# Từ BCKT
tts_vec <- extract_row_data(bckt_raw, "TỔNG CỘNG TÀI SẢN")
no_vec <- extract_row_data(bckt_raw, "C. NỢ PHẢI TRẢ")
vcsh_vec <- extract_row_data(bckt_raw, "D. VỐN CHỦ SỞ HỮU")
print("Đã trích xuất thành công 5 chỉ tiêu.")## [1] "Đã trích xuất thành công 5 chỉ tiêu."
# 4. Tạo bảng dữ liệu (Data Frame) và Mã hóa
# Tạo bảng từ các vector đã trích xuất
GAS_data_df <- data.frame(
Nam = nam_vec,
DoanhThu_Raw = dt_vec,
LoiNhuanSauThue_Raw = lnst_vec,
TongTaiSan_Raw = tts_vec,
NoPhaiTra_Raw = no_vec,
VonChuSoHuu_Raw = vcsh_vec
)
# Áp dụng hàm làm sạch số (Mã hóa)
GAS_data_final <- GAS_data_df %>%
mutate(across(-Nam, clean_numeric)) %>% # Áp dụng hàm 'clean_numeric' cho TẤT CẢ các cột TRỪ cột 'Nam'
# Đổi tên cột
rename(
DoanhThu = DoanhThu_Raw,
LoiNhuanSauThue = LoiNhuanSauThue_Raw,
TongTaiSan = TongTaiSan_Raw,
NoPhaiTra = NoPhaiTra_Raw,
VonChuSoHuu = VonChuSoHuu_Raw
)
print("Đã làm sạch và mã hóa dữ liệu số.")## [1] "Đã làm sạch và mã hóa dữ liệu số."
## Nam DoanhThu LoiNhuanSauThue TongTaiSan NoPhaiTra VonChuSoHuu
## 1 2014 7.339340e+13 1.412268e+13 5.379141e+13 1.611206e+13 3.767935e+13
## 2 2015 6.430020e+13 2.984305e+11 5.671461e+13 1.382554e+13 4.288906e+13
## 3 2016 5.907619e+13 1.522566e+11 5.675385e+13 1.591001e+13 4.084385e+13
## 4 2017 6.452244e+13 2.529287e+11 6.188934e+13 1.861783e+13 4.327151e+13
## 5 2018 7.561155e+13 2.545966e+11 6.261442e+13 1.574730e+13 4.686713e+13
## 6 2019 7.500530e+13 1.834033e+11 6.217874e+11 1.256426e+13 4.961453e+13
# PHẦN 3: BỔ SUNG DỮ LIỆU & TẠO BIẾN MỚI (FEATURE ENGINEERING)
# 5. Bổ sung dữ liệu thị trường
gia_dong_cua_vec <- c(
34154.5, # 2014
18128.8, # 2015
33089.0, # 2016
56311.2, # 2017
52231.7, # 2018
58209.9, # 2019
56436.3, # 2020
64672.3, # 2021
70096.3, # 2022
64830.3, # 2023
64160.1 # 2024
)
# 6. Tính toán các chỉ số phái sinh
GAS_data_final <- GAS_data_final %>%
mutate(
Gia_DongCua_CuoiNam = gia_dong_cua_vec, # Thêm cột giá
# Các chỉ số hiệu quả
ROE_Nam = (LoiNhuanSauThue / VonChuSoHuu) * 100, # Đơn vị %
ROA_Nam = (LoiNhuanSauThue / TongTaiSan) * 100, # Đơn vị %
# Chỉ số đòn bẩy
TySoNo_Tren_VCSH = NoPhaiTra / VonChuSoHuu, # Tỷ lệ
# Chỉ số tăng trưởng
DoanhThu_TangTruong_YoY = (DoanhThu / lag(DoanhThu) - 1) * 100, # lag() là hàm lấy giá trị của hàng (năm) trước đó
LoiNhuan_TangTruong_YoY = (LoiNhuanSauThue / lag(LoiNhuanSauThue) - 1) * 100
)
# 7. Xử lý giá trị NA (cho năm 2014)
GAS_data_final <- GAS_data_final %>%
mutate(
# Hàm ifelse: NẾU (IF) giá trị là NA, THÌ (THEN) đổi thành 0, NẾU KHÔNG (ELSE) giữ nguyên giá trị cũ
DoanhThu_TangTruong_YoY = ifelse(is.na(DoanhThu_TangTruong_YoY), 0, DoanhThu_TangTruong_YoY),
LoiNhuan_TangTruong_YoY = ifelse(is.na(LoiNhuan_TangTruong_YoY), 0, LoiNhuan_TangTruong_YoY)
# (ĐÃ LOẠI BỎ XỬ LÝ P/E)
)
print("Bảng dữ liệu 'GAS_data_final' hoàn chỉnh (11 hàng, 12 cột):")## [1] "Bảng dữ liệu 'GAS_data_final' hoàn chỉnh (11 hàng, 12 cột):"
## Nam DoanhThu LoiNhuanSauThue TongTaiSan NoPhaiTra VonChuSoHuu
## 1 2014 7.339340e+13 1.412268e+13 5.379141e+13 1.611206e+13 3.767935e+13
## 2 2015 6.430020e+13 2.984305e+11 5.671461e+13 1.382554e+13 4.288906e+13
## 3 2016 5.907619e+13 1.522566e+11 5.675385e+13 1.591001e+13 4.084385e+13
## 4 2017 6.452244e+13 2.529287e+11 6.188934e+13 1.861783e+13 4.327151e+13
## 5 2018 7.561155e+13 2.545966e+11 6.261442e+13 1.574730e+13 4.686713e+13
## 6 2019 7.500530e+13 1.834033e+11 6.217874e+11 1.256426e+13 4.961453e+13
## 7 2020 6.413497e+13 7.854956e+12 6.320840e+13 1.370872e+13 4.949968e+13
## 8 2021 7.899216e+13 8.672965e+12 7.876870e+13 2.657534e+13 5.219273e+13
## 9 2022 1.007235e+14 1.479832e+13 8.266265e+13 2.148909e+13 6.117356e+13
## 10 2023 8.995391e+13 1.160603e+13 8.775446e+13 2.245584e+13 6.529862e+13
## 11 2024 1.035641e+14 1.039873e+13 8.185488e+13 2.028389e+13 6.157100e+13
## Gia_DongCua_CuoiNam ROE_Nam ROA_Nam TySoNo_Tren_VCSH
## 1 34154.5 37.4812093 26.2545195 0.4276098
## 2 18128.8 0.6958196 0.5261969 0.3223559
## 3 33089.0 0.3727773 0.2682753 0.3895325
## 4 56311.2 0.5845154 0.4086788 0.4302562
## 5 52231.7 0.5432306 0.4066101 0.3359987
## 6 58209.9 0.3696564 29.4961404 0.2532374
## 7 56436.3 15.8687001 12.4270758 0.2769456
## 8 64672.3 16.6171897 11.0106737 0.5091771
## 9 70096.3 24.1907065 17.9020595 0.3512806
## 10 64830.3 17.7737762 13.2255742 0.3438945
## 11 64160.1 16.8890076 12.7038606 0.3294390
## DoanhThu_TangTruong_YoY LoiNhuan_TangTruong_YoY
## 1 0.0000000 0.0000000
## 2 -12.3896680 -97.8868699
## 3 -8.1244079 -48.9808874
## 4 9.2190229 66.1199968
## 5 17.1864317 0.6594479
## 6 -0.8017943 -27.9631807
## 7 -14.4927520 4182.8873336
## 8 23.1655081 10.4139240
## 9 27.5108241 70.6258138
## 10 -10.6922788 -21.5719566
## 11 15.1302157 -10.4023558
# Thao tác 1: Kiểm tra cấu trúc dữ liệu.
# Mục đích: Đảm bảo 12 biến đã được mã hóa đúng kiểu (numeric/int)
print("--- Thao tác 1: Cấu trúc dữ liệu (str) ---")## [1] "--- Thao tác 1: Cấu trúc dữ liệu (str) ---"
## 'data.frame': 11 obs. of 12 variables:
## $ Nam : int 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 ...
## $ DoanhThu : num 7.34e+13 6.43e+13 5.91e+13 6.45e+13 7.56e+13 ...
## $ LoiNhuanSauThue : num 1.41e+13 2.98e+11 1.52e+11 2.53e+11 2.55e+11 ...
## $ TongTaiSan : num 5.38e+13 5.67e+13 5.68e+13 6.19e+13 6.26e+13 ...
## $ NoPhaiTra : num 1.61e+13 1.38e+13 1.59e+13 1.86e+13 1.57e+13 ...
## $ VonChuSoHuu : num 3.77e+13 4.29e+13 4.08e+13 4.33e+13 4.69e+13 ...
## $ Gia_DongCua_CuoiNam : num 34155 18129 33089 56311 52232 ...
## $ ROE_Nam : num 37.481 0.696 0.373 0.585 0.543 ...
## $ ROA_Nam : num 26.255 0.526 0.268 0.409 0.407 ...
## $ TySoNo_Tren_VCSH : num 0.428 0.322 0.39 0.43 0.336 ...
## $ DoanhThu_TangTruong_YoY: num 0 -12.39 -8.12 9.22 17.19 ...
## $ LoiNhuan_TangTruong_YoY: num 0 -97.887 -48.981 66.12 0.659 ...
# Thao tác 2: Tóm tắt (Min, Q1, Median, Mean, Q3, Max)
# Mục đích: Xem nhanh phân phối, giá trị trung tâm và các điểm ngoại lai
print("--- Thao tác 2: Tóm tắt (summary) ---")## [1] "--- Thao tác 2: Tóm tắt (summary) ---"
# Dùng options(scipen=999) để R hiển thị số đầy đủ, không dùng ký hiệu "e+" (scientific notation)
options(scipen = 999)
print(summary(GAS_data_final))## Nam DoanhThu LoiNhuanSauThue
## Min. :2014 Min. : 59076193175700 Min. : 152256595845
## 1st Qu.:2016 1st Qu.: 64411322507300 1st Qu.: 253762618570
## Median :2019 Median : 75005297175400 Median : 7854955921940
## Mean :2019 Mean : 77207071686500 Mean : 6235935457210
## 3rd Qu.:2022 3rd Qu.: 84473031317800 3rd Qu.:11002380348300
## Max. :2024 Max. :103564126563000 Max. :14798317219700
## TongTaiSan NoPhaiTra VonChuSoHuu
## Min. : 621787389634 Min. :12564256032000 Min. :37679348560600
## 1st Qu.:56734229902900 1st Qu.:14786419268900 1st Qu.:43080285823500
## Median :62614420245300 Median :16112058787500 Median :49499680985500
## Mean :62421319359500 Mean :17935442513000 Mean :50081910482900
## 3rd Qu.:80311793048400 3rd Qu.:20886487476900 3rd Qu.:56683147115100
## Max. :87754455330400 Max. :26575344013400 Max. :65298620274400
## Gia_DongCua_CuoiNam ROE_Nam ROA_Nam TySoNo_Tren_VCSH
## Min. :18129 Min. : 0.3697 Min. : 0.2683 Min. :0.2532
## 1st Qu.:43193 1st Qu.: 0.5639 1st Qu.: 0.4674 1st Qu.:0.3259
## Median :56436 Median :15.8687 Median :12.4271 Median :0.3439
## Mean :52029 Mean :11.9442 Mean :11.3300 Mean :0.3609
## 3rd Qu.:64416 3rd Qu.:17.3314 3rd Qu.:15.5638 3rd Qu.:0.4086
## Max. :70096 Max. :37.4812 Max. :29.4961 Max. :0.5092
## DoanhThu_TangTruong_YoY LoiNhuan_TangTruong_YoY
## Min. :-14.493 Min. : -97.89
## 1st Qu.: -9.408 1st Qu.: -24.77
## Median : 0.000 Median : 0.00
## Mean : 4.156 Mean : 374.90
## 3rd Qu.: 16.158 3rd Qu.: 38.27
## Max. : 27.511 Max. :4182.89
# Thao tác 3: Định dạng lại đơn vị (Tỷ VND) để dễ đọc
# Mục đích: Tạo bảng hiển thị đễ dễ đọc
print("--- Thao tác 3: Bảng dữ liệu đã định dạng (Tỷ VND) ---")## [1] "--- Thao tác 3: Bảng dữ liệu đã định dạng (Tỷ VND) ---"
GAS_data_display <- GAS_data_final %>%
mutate(
# Tạo các cột mới chia cho 1 tỷ (1e9)
DoanhThu_TyVND = DoanhThu / 1e9,
LoiNhuanSauThue_TyVND = LoiNhuanSauThue / 1e9,
TongTaiSan_TyVND = TongTaiSan / 1e9,
NoPhaiTra_TyVND = NoPhaiTra / 1e9,
VonChuSoHuu_TyVND = VonChuSoHuu / 1e9
) %>%
# Chỉ chọn các cột đã định dạng và các cột %/tỷ lệ
select(
Nam,
DoanhThu_TyVND,
LoiNhuanSauThue_TyVND,
TongTaiSan_TyVND,
NoPhaiTra_TyVND,
VonChuSoHuu_TyVND,
Gia_DongCua_CuoiNam,
ROE_Nam,
ROA_Nam,
TySoNo_Tren_VCSH,
DoanhThu_TangTruong_YoY,
LoiNhuan_TangTruong_YoY
)
# Dùng round() để làm tròn đến 2 chữ số thập phân cho dễ đọc
print(round(as.data.frame(GAS_data_display), 2))## Nam DoanhThu_TyVND LoiNhuanSauThue_TyVND TongTaiSan_TyVND NoPhaiTra_TyVND
## 1 2014 73393.40 14122.68 53791.41 16112.06
## 2 2015 64300.20 298.43 56714.61 13825.54
## 3 2016 59076.19 152.26 56753.85 15910.01
## 4 2017 64522.44 252.93 61889.34 18617.83
## 5 2018 75611.55 254.60 62614.42 15747.30
## 6 2019 75005.30 183.40 621.79 12564.26
## 7 2020 64134.97 7854.96 63208.40 13708.72
## 8 2021 78992.16 8672.97 78768.70 26575.34
## 9 2022 100723.55 14798.32 82662.65 21489.09
## 10 2023 89953.91 11606.03 87754.46 22455.84
## 11 2024 103564.13 10398.73 81854.88 20283.89
## VonChuSoHuu_TyVND Gia_DongCua_CuoiNam ROE_Nam ROA_Nam TySoNo_Tren_VCSH
## 1 37679.35 34154.5 37.48 26.25 0.43
## 2 42889.06 18128.8 0.70 0.53 0.32
## 3 40843.85 33089.0 0.37 0.27 0.39
## 4 43271.51 56311.2 0.58 0.41 0.43
## 5 46867.13 52231.7 0.54 0.41 0.34
## 6 49614.53 58209.9 0.37 29.50 0.25
## 7 49499.68 56436.3 15.87 12.43 0.28
## 8 52192.73 64672.3 16.62 11.01 0.51
## 9 61173.56 70096.3 24.19 17.90 0.35
## 10 65298.62 64830.3 17.77 13.23 0.34
## 11 61571.00 64160.1 16.89 12.70 0.33
## DoanhThu_TangTruong_YoY LoiNhuan_TangTruong_YoY
## 1 0.00 0.00
## 2 -12.39 -97.89
## 3 -8.12 -48.98
## 4 9.22 66.12
## 5 17.19 0.66
## 6 -0.80 -27.96
## 7 -14.49 4182.89
## 8 23.17 10.41
## 9 27.51 70.63
## 10 -10.69 -21.57
## 11 15.13 -10.40
# Thao tác 4: Trích xuất các giá trị thống kê chính
print("--- Thao tác 4: Trích xuất các giá trị chính ---")## [1] "--- Thao tác 4: Trích xuất các giá trị chính ---"
# Tính toán và lưu các giá trị thống kê
mean_lnst_ty <- mean(GAS_data_final$LoiNhuanSauThue) / 1e9
median_lnst_ty <- median(GAS_data_final$LoiNhuanSauThue) / 1e9
mean_roe <- mean(GAS_data_final$ROE_Nam)
median_roe <- median(GAS_data_final$ROE_Nam)
mean_growth_ln <- mean(GAS_data_final$LoiNhuan_TangTruong_YoY)
median_growth_ln <- median(GAS_data_final$LoiNhuan_TangTruong_YoY)
mean_dt_ty <- mean(GAS_data_final$DoanhThu) / 1e9
# In ra
print(paste("Doanh thu trung bình (Mean):", round(mean_dt_ty, 2), "tỷ VND"))## [1] "Doanh thu trung bình (Mean): 77207.07 tỷ VND"
## [1] "Lợi nhuận trung bình (Mean): 6235.94 tỷ VND"
## [1] "Lợi nhuận trung vị (Median): 7854.96 tỷ VND"
## [1] "ROE trung bình (Mean): 11.94 %"
## [1] "ROE trung vị (Median): 15.87 %"
## [1] "Tăng trưởng LN trung bình (Mean): 374.9 %"
## [1] "Tăng trưởng LN trung vị (Median): 0 %"
Kết quả từ str() xác nhận tất cả 12 biến đã được mã hóa chính xác, đảm bảo tính toàn vẹn dữ liệu cho các phân tích sau. Các biến tài chính gốc (ví dụ: DoanhThu) và các biến phái sinh (ví dụ: ROE_Nam) đều ở định dạng số (numeric) hoặc số nguyên (integer).
summary(), cung cấp cái nhìn tổng quan về phân phối của dữ liệu trong giai đoạn 11 năm (2014-2024). Từ kết quả Thao tác 4, Doanh thu trung bình đạt 77,207.07 tỷ VND, trong khi lợi nhuận sau thuế trung bình đạt 6,235.94 tỷ VND.
Một quan sát quan trọng là sự chênh lệch giữa giá trị trung bình (Mean) và trung vị (Median) ở nhiều chỉ số. Cụ thể:
Lợi nhuận sau thuế: Có Trung vị (7,854.96 tỷ VND) cao hơn đáng kể so với Trung bình (6,235.94 tỷ VND).
ROE (Tỷ suất sinh lời/VCSH): Có Trung vị (15.87%) cao hơn Trung bình (11.94%).
Cả hai hiện tượng này đều cho thấy phân phối của dữ liệu bị lệch trái. Về mặt tài chính, điều này ngụ ý rằng có một số năm hoạt động với lợi nhuận và hiệu quả sinh lời thấp bất thường (như kết quả Min. và 1st Qu. rất thấp trong bảng summary()) đã kéo giá trị trung bình chung (Mean) đi xuống. Do đó, giá trị Trung vị (Median) có thể đại diện tốt hơn cho hiệu quả hoạt động “điển hình” của GAS trong giai đoạn này.
Ngược lại, biến LoiNhuan_TangTruong_YoY (Tăng trưởng Lợi nhuận) thể hiện độ lệch cực lớn về bên phải. Kết quả cho thấy giá trị Trung bình (374.90%) cao hơn rất nhiều so với Trung vị (0%). Nguyên nhân là do sự xuất hiện của ít nhất một giá trị ngoại lai rất lớn (Max: 4182.89% từ summary()). Trong trường hợp này, Mean hoàn toàn không có ý nghĩa đại diện; Median (0%) là thước đo xu hướng trung tâm đáng tin cậy hơn, cho thấy một năm “điển hình” của GAS có mức tăng trưởng lợi nhuận không quá đột biến.
# Thao tác 5: Phân tích phân vị (Quantiles) cho ROE
print("--- Thao tác 5: Phân vị của ROE (%) ---")## [1] "--- Thao tác 5: Phân vị của ROE (%) ---"
## 0% 25% 50% 75% 100%
## 0.37 0.56 15.87 17.33 37.48
# Thao tác 6: Phân tích phân vị cho Tăng trưởng Lợi nhuận
print("--- Thao tác 6: Phân vị của Tăng trưởng Lợi nhuận (%) ---")## [1] "--- Thao tác 6: Phân vị của Tăng trưởng Lợi nhuận (%) ---"
# Tạo một vector mới bỏ qua năm 2014 (giá trị 0) để phân tích
growth_ln_subset <- GAS_data_final$LoiNhuan_TangTruong_YoY[GAS_data_final$Nam > 2014]
q_growth <- quantile(growth_ln_subset, probs = c(0, .25, .5, .75, 1))
print(round(q_growth, 2))## 0% 25% 50% 75% 100%
## -97.89 -26.37 -4.87 52.19 4182.89
# Thao tác 7: Thống kê Tần suất cho Tăng trưởng LN
print("--- Thao tác 7: Tần suất Tăng trưởng Lợi nhuận ---")## [1] "--- Thao tác 7: Tần suất Tăng trưởng Lợi nhuận ---"
# table() dùng để đếm số lần xuất hiện của mỗi nhóm
freq_growth <- table(GAS_data_final$LoiNhuan_TangTruong_YoY > 0)
names(freq_growth) <- c("Tăng trưởng Âm hoặc Bằng 0", "Tăng trưởng Dương")
print(freq_growth)## Tăng trưởng Âm hoặc Bằng 0 Tăng trưởng Dương
## 6 5
# Thao tác 8: Thống kê Tần suất cho ROE
print("--- Thao tác 8: Tần suất ROE > 15% (Ngưỡng hiệu quả) ---")## [1] "--- Thao tác 8: Tần suất ROE > 15% (Ngưỡng hiệu quả) ---"
# Sử dụng ngưỡng 15% (gần median) thay vì 20%
# sum() của một biểu thức logic sẽ đếm số lần TRUE
roe_tren_15 <- sum(GAS_data_final$ROE_Nam > 15)
print(paste("Số năm có ROE > 15%:", roe_tren_15, "năm"))## [1] "Số năm có ROE > 15%: 6 năm"
## [1] "--- Thao tác 9: Biểu đồ Boxplot ---"
par(mfrow = c(1, 2)) # Chia cửa sổ đồ thị thành 1 hàng 2 cột
boxplot(GAS_data_final$ROE_Nam,
main = "Boxplot Phân phối ROE (2014-2024)",
ylab = "ROE (%)")
# Thao tác 10: Biểu đồ thống kê đơn giản (Histogram)
print("--- Thao tác 10: Biểu đồ Histogram ---")## [1] "--- Thao tác 10: Biểu đồ Histogram ---"
hist(growth_ln_subset,
main = "Histogram Tăng trưởng LN (2015-2024)",
xlab = "Tăng trưởng Lợi nhuận (%)",
ylab = "Tần suất",
breaks = 10) # 'breaks' gợi ý số lượng cộtPhân tích phân vị (Thao tác 5 & 6):
Kết quả phân vị của ROE (q_roe, Thao tác 5) cho thấy một sự phân hóa rất rõ rệt: 25% số năm tệ nhất (từ 0% đến 25%) có ROE cực kỳ thấp, chỉ từ 0.37% đến 0.56%. Ngược lại, 50% số năm tốt nhất (từ 50%) có ROE từ 15.87% trở lên. Điều này xác nhận nhận định ở Mục 2.4.1: Dữ liệu bị lệch trái (left-skewed) do một số năm hoạt động kém hiệu quả (2015, 2016, 2017) kéo trung bình chung đi xuống.
Đối với tăng trưởng lợi nhuận (q_growth, Thao tác 6, đã loại bỏ năm 2014), phân phối cũng cho thấy sự bất ổn định lớn: Mức trung vị (Median) là -4.87%, cho thấy một năm “điển hình” (trong 10 năm qua) có sụt giảm lợi nhuận nhẹ. Khoảng biến động là rất lớn, 25% số năm tệ nhất sụt giảm từ -97.89% (Min) đến -26.37% (Q1). Ngược lại, 25% số năm tốt nhất tăng trưởng từ 52.19% (Q3) đến 4182.89% (Max).
Phân tích tần suất (Thao tác 7 & 8):
Thống kê tần suất tăng trưởng (freq_growth, Thao tác 7) chỉ ra sự thiếu ổn định: trong 11 năm, số năm “Tăng trưởng Âm hoặc Bằng 0” (6 năm) nhiều hơn số năm “Tăng trưởng Dương” (5 năm). Điều này củng cố cho nhận định rằng tăng trưởng lợi nhuận của GAS không bền vững qua các năm.
Tuy nhiên, thống kê về ROE (roe_tren_15, Thao tác 8) lại cho thấy một điểm sáng: có 6 trên 11 năm (chiếm đa số) đạt mức ROE trên 15%. Đây là một con số tương đối tích cực, cho thấy dù có những năm sụt giảm mạnh, GAS vẫn thường xuyên duy trì được mức sinh lời tốt trên vốn chủ sở hữu.
Phân tích biểu đồ (Thao tác 9 & 10):
Biểu đồ Boxplot (ROE): Hình ảnh trực quan hóa chính xác kết quả q_roe. Ta thấy phần “hộp” (IQR, từ Q1 đến Q3) bị dồn về phía dưới. Khoảng cách từ Q1 (0.56%) đến Median (15.87%) là rất lớn, trong khi khoảng cách từ Median (15.87%) đến Q3 (17.33%) lại rất hẹp. Điều này khẳng định sự phân phối lệch trái (lệch về phía giá trị thấp).
Biểu đồ Histogram (Tăng trưởng LN): Hình ảnh này cho thấy rõ sự lệch phải cực đoan. Hầu hết các giá trị (9/10 năm) tập trung thành hai cột ở gần 0 (trong khoảng -100% đến 1000%). Có duy nhất 1 giá trị (1 năm) nằm tách biệt hoàn toàn ở phía xa bên phải (cột > 3000%). Đây chính là giá trị ngoại lai 4182.89% (Max) đã làm sai lệch Mean (trung bình) của tăng trưởng lợi nhuận như đã phân tích ở mục 2.4.1.
# Thao tác 11: Phân tích quy mô (Min/Max)
# (Các giá trị Mean đã được tính ở 2.4.1)
print("--- Thao tác 11: Phân tích quy mô (Min/Max) ---")## [1] "--- Thao tác 11: Phân tích quy mô (Min/Max) ---"
# Tính toán Tổng tài sản trung bình
tts_mean_ty <- mean(GAS_data_final$TongTaiSan) / 1e9
print(paste("Tổng tài sản trung bình (11 năm):", round(tts_mean_ty, 2), "tỷ VND"))## [1] "Tổng tài sản trung bình (11 năm): 62421.32 tỷ VND"
# Xác định năm Lợi nhuận cao nhất (Max)
ln_max <- GAS_data_final %>% filter(LoiNhuanSauThue == max(LoiNhuanSauThue))
print(paste("Năm lợi nhuận cao nhất:", ln_max$Nam,
"| LNST:", round(ln_max$LoiNhuanSauThue / 1e9, 2), "tỷ VND"))## [1] "Năm lợi nhuận cao nhất: 2022 | LNST: 14798.32 tỷ VND"
# Xác định năm Lợi nhuận thấp nhất (Min)
ln_min <- GAS_data_final %>% filter(LoiNhuanSauThue == min(LoiNhuanSauThue))
print(paste("Năm lợi nhuận thấp nhất:", ln_min$Nam,
"| LNST:", round(ln_min$LoiNhuanSauThue / 1e9, 2), "tỷ VND"))## [1] "Năm lợi nhuận thấp nhất: 2016 | LNST: 152.26 tỷ VND"
# Thao tác 12: Phân tích Cơ cấu tài chính (Đòn bẩy)
print("--- Thao tác 12: Phân tích Cơ cấu tài chính ---")## [1] "--- Thao tác 12: Phân tích Cơ cấu tài chính ---"
# Tính tỷ lệ Nợ trên Tổng Tài sản
gas_co_cau_von <- GAS_data_final %>%
mutate(TyLeNo_TTS = NoPhaiTra / TongTaiSan)
# Tính trung bình của tỷ lệ này (đã có TySoNo_Tren_VCSH, đây là chỉ số khác)
co_cau_no_tb <- mean(gas_co_cau_von$TyLeNo_TTS)
print(paste("Tỷ lệ Nợ / Tổng Tài sản trung bình:", round(co_cau_no_tb * 100, 2), "%"))## [1] "Tỷ lệ Nợ / Tổng Tài sản trung bình: 208.19 %"
print(paste("Tỷ số Nợ / VCSH trung bình (từ 1.4.1):", round(mean(GAS_data_final$TySoNo_Tren_VCSH), 2)))## [1] "Tỷ số Nợ / VCSH trung bình (từ 1.4.1): 0.36"
# Thao tác 13: Phân tích Hiệu quả sinh lời (Biên Lợi nhuận)
print("--- Thao tác 13: Phân tích Biên Lợi nhuận ròng ---")## [1] "--- Thao tác 13: Phân tích Biên Lợi nhuận ròng ---"
gas_bien_ln <- GAS_data_final %>%
mutate(Bien_LN_Rong = LoiNhuanSauThue / DoanhThu)
bien_ln_tb <- mean(gas_bien_ln$Bien_LN_Rong)
bien_ln_median <- median(gas_bien_ln$Bien_LN_Rong)
print(paste("Biên lợi nhuận ròng trung bình (Mean):", round(bien_ln_tb * 100, 2), "%"))## [1] "Biên lợi nhuận ròng trung bình (Mean): 7.44 %"
## [1] "Biên lợi nhuận ròng trung vị (Median): 10.04 %"
Nhận xét
Quy mô và biến động (Thao tác 11): Quy mô của GAS rất lớn, với Tổng tài sản trung bình là 62,421.32 tỷ VND. Tuy nhiên, kết quả kinh doanh thể hiện sự biến động mạnh, phản ánh rủi ro ngành cụ thể:
Năm đỉnh cao lợi nhuận là 2022, đạt 14,798.32 tỷ VND.
Năm khó khăn nhất là 2016, khi lợi nhuận chỉ đạt 152.26 tỷ VND.
Sự chênh lệch cực lớn (chênh lệch hàng trăm lần) cho thấy lợi nhuận của GAS chịu ảnh hưởng rất mạnh mẽ từ các yếu tố bên ngoài (như giá dầu, giá khí thế giới).
Phân tích cơ cấu vốn cho thấy một kết quả bất thường và đáng báo động từ dữ liệu. Tỷ lệ Nợ trên Tổng Tài sản trung bình (co_cau_no_tb) lên đến 208.19%. Về mặt lý thuyết, con số này là không thể có (vì Nợ là một phần của Tài sản). Kết quả này có thể cho rằng: Có ít nhất một điểm dữ liệu dị biệt (outlier) nghiêm trọng, nơi NoPhaiTra lớn hơn TongTaiSan rất nhiều. Điểm dị biệt này đã được phát hiện trong summary() ở Mục 2.4.1: TongTaiSan có giá trị Min là 621 tỷ, trong khi NoPhaiTra có Min là 12,564 tỷ.
Do đó, giá trị trung bình 208.19% bị chi phối hoàn toàn bởi điểm ngoại lai này và không có giá trị đại diện.
Ngược lại, chỉ số Tỷ số Nợ / VCSH trung bình (từ summary()) là 0.36, cho thấy trong các năm bình thường, cấu trúc vốn của GAS là an toàn (Nợ chỉ bằng 36% VCSH). Kết luận: Cần phải kiểm tra lại dữ liệu gốc của năm có TongTaiSan thấp bất thường trước khi đưa ra kết luận cuối cùng về đòn bẩy.
Hiệu quả sinh lời (Thao tác 13): Biên lợi nhuận ròng đo lường hiệu quả chuyển đổi doanh thu thành lợi nhuận. Kết quả cho thấy:
Biên lợi nhuận ròng trung bình (bien_ln_tb) là 7.44%.
Biên lợi nhuận ròng trung vị (bien_ln_median) là 10.04%.
Sự chênh lệch (Median > Mean) một lần nữa xác nhận hiện tượng lệch trái do một số năm có biên lợi nhuận rất thấp (như 2015, 2016). Tuy nhiên, con số trung vị 10.04% (bien_ln_median) cho thấy trong một năm “điển hình”, GAS vẫn duy trì được biên lợi nhuận ròng ở mức trên 10%, một con số tích cực.
## [1] "--- Thao tác 14: Độ biến động (Rủi ro) ---"
# sd() là hàm tính Độ lệch chuẩn (Standard Deviation)
sd_lnst <- sd(GAS_data_final$LoiNhuanSauThue)
sd_roe <- sd(GAS_data_final$ROE_Nam)
print(paste("Độ lệch chuẩn LNST:", round(sd_lnst / 1e9, 2), "tỷ VND"))## [1] "Độ lệch chuẩn LNST: 6088.62 tỷ VND"
## [1] "Độ lệch chuẩn ROE: 12.45 %"
# Thao tác 15: Xử lý Outlier trước khi tính Tương quan
print("--- Thao tác 15: Xử lý Outlier trước khi tính Tương quan ---")## [1] "--- Thao tác 15: Xử lý Outlier trước khi tính Tương quan ---"
# Dữ liệu từ 1.4.1 và 1.4.3 cho thấy 1 năm có TTS rất thấp (Min: 621 tỷ)
# Đây là outlier nghiêm trọng, gây ra Tỷ lệ Nợ/TTS > 200%
# lọc bỏ năm này để ma trận tương quan có ý nghĩa hơn.
# Ngưỡng 1,000 tỷ (1e12) được chọn để loại bỏ giá trị 621 tỷ
data_for_cor <- GAS_data_final %>% filter(TongTaiSan > 1e12)
print(paste("Đã loại bỏ", nrow(GAS_data_final) - nrow(data_for_cor), "dòng dữ liệu outlier (TTS < 1,000 tỷ)"))## [1] "Đã loại bỏ 1 dòng dữ liệu outlier (TTS < 1,000 tỷ)"
## [1] "Số quan sát mới để tính tương quan: 10 năm"
# Thao tác 16: Ma trận Tương quan (trên dữ liệu đã lọc)
print("--- Thao tác 16: Ma trận Tương quan (đã lọc outlier) ---")## [1] "--- Thao tác 16: Ma trận Tương quan (đã lọc outlier) ---"
# cor() là hàm tính Ma trận Tương quan (Correlation Matrix)
cor_matrix <- cor(data_for_cor %>% select(-Nam)) # Bỏ cột 'Nam'
print(round(cor_matrix, 2))## DoanhThu LoiNhuanSauThue TongTaiSan NoPhaiTra
## DoanhThu 1.00 0.70 0.85 0.61
## LoiNhuanSauThue 0.70 1.00 0.57 0.47
## TongTaiSan 0.85 0.57 1.00 0.81
## NoPhaiTra 0.61 0.47 0.81 1.00
## VonChuSoHuu 0.85 0.55 0.97 0.63
## Gia_DongCua_CuoiNam 0.68 0.50 0.83 0.71
## ROE_Nam 0.49 0.94 0.29 0.30
## ROA_Nam 0.51 0.95 0.31 0.28
## TySoNo_Tren_VCSH -0.11 0.05 -0.01 0.58
## DoanhThu_TangTruong_YoY 0.58 0.25 0.43 0.60
## LoiNhuan_TangTruong_YoY -0.28 0.07 -0.14 -0.38
## VonChuSoHuu Gia_DongCua_CuoiNam ROE_Nam ROA_Nam
## DoanhThu 0.85 0.68 0.49 0.51
## LoiNhuanSauThue 0.55 0.50 0.94 0.95
## TongTaiSan 0.97 0.83 0.29 0.31
## NoPhaiTra 0.63 0.71 0.30 0.28
## VonChuSoHuu 1.00 0.78 0.25 0.29
## Gia_DongCua_CuoiNam 0.78 1.00 0.28 0.30
## ROE_Nam 0.25 0.28 1.00 1.00
## ROA_Nam 0.29 0.30 1.00 1.00
## TySoNo_Tren_VCSH -0.27 0.06 0.15 0.10
## DoanhThu_TangTruong_YoY 0.31 0.58 0.16 0.14
## LoiNhuan_TangTruong_YoY -0.01 0.13 0.09 0.13
## TySoNo_Tren_VCSH DoanhThu_TangTruong_YoY
## DoanhThu -0.11 0.58
## LoiNhuanSauThue 0.05 0.25
## TongTaiSan -0.01 0.43
## NoPhaiTra 0.58 0.60
## VonChuSoHuu -0.27 0.31
## Gia_DongCua_CuoiNam 0.06 0.58
## ROE_Nam 0.15 0.16
## ROA_Nam 0.10 0.14
## TySoNo_Tren_VCSH 1.00 0.42
## DoanhThu_TangTruong_YoY 0.42 1.00
## LoiNhuan_TangTruong_YoY -0.48 -0.40
## LoiNhuan_TangTruong_YoY
## DoanhThu -0.28
## LoiNhuanSauThue 0.07
## TongTaiSan -0.14
## NoPhaiTra -0.38
## VonChuSoHuu -0.01
## Gia_DongCua_CuoiNam 0.13
## ROE_Nam 0.09
## ROA_Nam 0.13
## TySoNo_Tren_VCSH -0.48
## DoanhThu_TangTruong_YoY -0.40
## LoiNhuan_TangTruong_YoY 1.00
# Thao tác 17: Trực quan hóa Ma trận Tương quan
print("--- Thao tác 17: Trực quan hóa Ma trận Tương quan ---")## [1] "--- Thao tác 17: Trực quan hóa Ma trận Tương quan ---"
library(corrplot)
# Vẽ biểu đồ, 'method = "number"' để hiển thị con số
corrplot(cor_matrix, method = "number",
title = "Ma trận Tương quan (đã lọc outlier, n=10)",
mar = c(0,0,1,0), # Căn chỉnh lề
tl.cex = 0.8, # Giảm kích thước font chữ
number.cex = 0.5) # Thu nhỏ font các con số trong matix# Thao tác 18: Tương quan chính (LNST & Giá)
print("--- Thao tác 18: Tương quan chính (LNST & Giá) ---")## [1] "--- Thao tác 18: Tương quan chính (LNST & Giá) ---"
# Trích xuất giá trị cụ thể từ ma trận
cor_ln_gia <- cor_matrix["LoiNhuanSauThue", "Gia_DongCua_CuoiNam"]
print(paste("Tương quan (LNST, Giá):", round(cor_ln_gia, 3)))## [1] "Tương quan (LNST, Giá): 0.495"
# Thao tác 19: Tương quan chính (ROE & Giá)
print("--- Thao tác 19: Tương quan chính (ROE & Giá) ---")## [1] "--- Thao tác 19: Tương quan chính (ROE & Giá) ---"
cor_roe_gia <- cor_matrix["ROE_Nam", "Gia_DongCua_CuoiNam"]
print(paste("Tương quan (ROE, Giá):", round(cor_roe_gia, 3)))## [1] "Tương quan (ROE, Giá): 0.276"
Nhận xét: đánh giá mức độ rủi ro (biến động) và mối quan hệ tuyến tính (tương quan) giữa các biến số tài chính và thị trường.
Kết quả cho thấy mức độ rủi ro (biến động) rất cao. Độ lệch chuẩn của Lợi nhuận sau thuế (sd_lnst) là 6,088.62 tỷ VND. Con số này gần như bằng với Lợi nhuận trung bình (mean_lnst_ty = 6,235.94 tỷ VND ở Mục 2.4.1), cho thấy Lợi nhuận của GAS biến động cực kỳ mạnh qua các năm. Tương tự, Độ lệch chuẩn của ROE (sd_roe) là 12.45%, cũng gần bằng với ROE trung bình (mean_roe = 11.94%), khẳng định sự bất ổn định rất lớn trong hiệu quả sinh lời.
Phân tích Tương quan (Thao tác 15-19): Ở thao tác 15 đã được thực hiện loại bỏ 1 năm quan sát bị xác định là outlier (với TongTaiSan < 1,000 tỷ) để đảm bảo kết quả tương quan đáng tin cậy. Ma trận tương quan (cor_matrix, Thao tác 16) trên 10 năm còn lại cho thấy các mối quan hệ nội tại:
Quan hệ nội tại (Hiệu quả): LoiNhuanSauThue có tương quan dương rất mạnh với ROE_Nam (0.94) và ROA_Nam (0.95). Điều này là hợp lý vì chúng đều là thước đo lợi nhuận.
Quan hệ nội tại (Quy mô): DoanhThu, TongTaiSan, và VonChuSoHuu đều có tương quan dương rất mạnh với nhau (từ 0.85 đến 0.97), cho thấy công ty tăng trưởng quy mô một cách đồng đều.
Quan hệ Quy mô - Lợi nhuận: DoanhThu và LoiNhuanSauThue có tương quan dương mạnh (0.70), cho thấy khi quy mô doanh thu tăng, lợi nhuận có xu hướng tăng theo.
Tương quan với Thị trường (Thao tác 18, 19) (trả lời câu hỏi “giá cổ phiếu có phản ánh sức khỏe tài chính không?”):
Tương quan giữa LoiNhuanSauThue và Gia_DongCua_CuoiNam (cor_ln_gia) là 0.495 (dương, mức độ trung bình).
Tương quan giữa ROE_Nam và Gia_DongCua_CuoiNam (cor_roe_gia) là 0.276 (dương, mức độ yếu).
Thị trường (Giá cổ phiếu) dường như phản ứng ở mức độ trung bình với quy mô lợi nhuận tuyệt đối (0.495), nhưng phản ứng khá yếu với hiệu quả sinh lời (0.276). Đáng chú ý hơn, Gia_DongCua_CuoiNam lại tương quan rất mạnh với TongTaiSan (0.83) và VonChuSoHuu (0.78). Điều này có thể cho rằng, trong giai đoạn 10 năm này (sau khi lọc outlier), thị trường có xu hướng định giá cổ phiếu GAS dựa trên quy mô tài sản và vốn chủ sở hữu hơn là dựa trên hiệu quả sinh lời (ROE) hay lợi nhuận (LNST) trong năm đó.
# Thao tác 20: Đọc và Chuẩn hóa Dữ liệu LCTT (Sheet 3)
print("--- Thao tác 20: Đọc và Chuẩn hóa Dữ liệu LCTT ---")## [1] "--- Thao tác 20: Đọc và Chuẩn hóa Dữ liệu LCTT ---"
# Đọc sheet 3 từ file excel
lctt_raw <- read_excel(bctc_path, sheet = 3) # Bảng Lưu chuyển tiền tệ
# Chuẩn hóa cột chỉ tiêu
if ("CHỈ TIÊU" %in% names(lctt_raw)) {
lctt_raw <- lctt_raw %>% rename(ChiTieu = `CHỈ TIÊU`)
}
print("Đã đọc và chuẩn hóa Sheet 3 (LCTT).")## [1] "Đã đọc và chuẩn hóa Sheet 3 (LCTT)."
# Thao tác 21: Bổ sung EPS và Tính toán SL Cổ phiếu
print("--- Thao tác 21: Bổ sung EPS và Tính toán SL Cổ phiếu ---")## [1] "--- Thao tác 21: Bổ sung EPS và Tính toán SL Cổ phiếu ---"
# Trích xuất 1 chỉ tiêu (EPS) từ kqkd_raw (đã đọc ở Mục 1.2)
eps_raw_vec <- extract_row_data(kqkd_raw, "19. Lãi cơ bản trên cổ phiếu")
# Lấy vector LNST (đã trích xuất ở Mục 1.3)
lnst_vec_for_calc <- GAS_data_final$LoiNhuanSauThue
# Làm sạch vector EPS vừa trích xuất (dùng hàm từ Mục 1.3)
eps_vec_cleaned <- clean_numeric(eps_raw_vec)
# TÍNH TOÁN SL Cổ phiếu Lưu hành = Lợi nhuận / EPS
# round() để làm tròn về số nguyên gần nhất
slcplh_calc_vec <- round(lnst_vec_for_calc / eps_vec_cleaned)
print("Đã trích xuất EPS và TÍNH TOÁN SL Cổ phiếu.")## [1] "Đã trích xuất EPS và TÍNH TOÁN SL Cổ phiếu."
# Thêm 2 cột này vào bảng chính
GAS_data_final <- GAS_data_final %>%
mutate(
EPS = eps_vec_cleaned, # Dùng vector EPS đã làm sạch
SL_CoPhieu_LuuHanh = slcplh_calc_vec # Dùng vector SL Cổ phiếu vừa tính toán
)
# Thao tác 22: Tính toán P/E và Vốn hóa
print("--- Thao tác 22: Tính toán P/E và Vốn hóa ---")## [1] "--- Thao tác 22: Tính toán P/E và Vốn hóa ---"
GAS_data_final <- GAS_data_final %>%
mutate(
# Tính toán Vốn hóa (đơn vị: Tỷ VND)
VonHoa_TyVND = (Gia_DongCua_CuoiNam * SL_CoPhieu_LuuHanh) / 1e9,
# Tính toán P/E
P_E_CuoiNam = Gia_DongCua_CuoiNam / EPS
)
# Xử lý P/E (Nếu EPS = 0, P/E sẽ là Inf - Vô cực)
GAS_data_final <- GAS_data_final %>%
mutate(
P_E_CuoiNam = ifelse(is.infinite(P_E_CuoiNam), NA, P_E_CuoiNam)
)
# Thống kê P/E (loại bỏ NA nếu có)
pe_mean <- mean(GAS_data_final$P_E_CuoiNam, na.rm = TRUE)
pe_median <- median(GAS_data_final$P_E_CuoiNam, na.rm = TRUE)
print(paste("P/E trung bình (Mean, 11 năm):", round(pe_mean, 2)))## [1] "P/E trung bình (Mean, 11 năm): 9.93"
## [1] "P/E trung vị (Median, 11 năm): 9.48"
# Thao tác 23: Tính toán Biên Lợi nhuận ròng
print("--- Thao tác 23: Tính toán Biên Lợi nhuận ròng ---")## [1] "--- Thao tác 23: Tính toán Biên Lợi nhuận ròng ---"
GAS_data_final <- GAS_data_final %>%
mutate(
BienLoiNhuanRong_Nam = (LoiNhuanSauThue / DoanhThu) * 100 # Đơn vị %
)
# Thống kê Biên LN Ròng (đã có kết quả từ 1.4.3, nhưng tính lại để xác nhận)
bln_mean <- mean(GAS_data_final$BienLoiNhuanRong_Nam, na.rm = TRUE)
print(paste("Biên Lợi nhuận ròng trung bình (Mean):", round(bln_mean, 2), "%"))## [1] "Biên Lợi nhuận ròng trung bình (Mean): 7.44 %"
# Thao tác 24: Phân tích Chất lượng Lợi nhuận (Dòng tiền)
print("--- Thao tác 24: Phân tích Chất lượng Lợi nhuận (Dòng tiền) ---")## [1] "--- Thao tác 24: Phân tích Chất lượng Lợi nhuận (Dòng tiền) ---"
# Trích xuất Dòng tiền từ HĐKD (CFO) từ lctt_raw
cfo_raw_vec <- extract_row_data(lctt_raw, "Lưu chuyển tiền thuần từ hoạt động kinh doanh")
# Làm sạch dữ liệu CFO
cfo_vec_cleaned <- clean_numeric(cfo_raw_vec)
# Thêm CFO vào bảng chính
GAS_data_final <- GAS_data_final %>%
mutate(CFO = cfo_vec_cleaned)
# Tính toán Tỷ lệ Chuyển đổi Tiền mặt
GAS_data_final <- GAS_data_final %>%
mutate(
TyLe_CFO_Tren_LNST = CFO / LoiNhuanSauThue
)
# Thống kê Tỷ lệ Chuyển đổi
cash_conv_mean <- mean(GAS_data_final$TyLe_CFO_Tren_LNST, na.rm = TRUE)
cash_conv_median <- median(GAS_data_final$TyLe_CFO_Tren_LNST, na.rm = TRUE)
print(paste("Tỷ lệ CFO/LNST trung bình (Mean):", round(cash_conv_mean, 2)))## [1] "Tỷ lệ CFO/LNST trung bình (Mean): 22.16"
## [1] "Tỷ lệ CFO/LNST trung vị (Median): 1.19"
## [1] "Bảng dữ liệu GAS_data_final đã được cập nhật (19 biến)."
## Nam DoanhThu LoiNhuanSauThue TongTaiSan NoPhaiTra
## 1 2014 73393403034088 14122675507937 53791407348105 16112058787504
## 2 2015 64300204038285 298430505873 56714606287288 13825543405185
## 3 2016 59076193175661 152256595845 56753853518438 15910005640211
## 4 2017 64522440976234 252928652205 61889343342437 18617834577626
## 5 2018 75611546239412 254596584934 62614420245293 15747295132679
## 6 2019 75005297175406 183403281712 621787389634 12564256032003
## VonChuSoHuu Gia_DongCua_CuoiNam ROE_Nam ROA_Nam TySoNo_Tren_VCSH
## 1 37679348560601 34154.5 37.4812093 26.2545195 0.4276098
## 2 42889062882103 18128.8 0.6958196 0.5261969 0.3223559
## 3 40843847878227 33089.0 0.3727773 0.2682753 0.3895325
## 4 43271508764811 56311.2 0.5845154 0.4086788 0.4302562
## 5 46867125112614 52231.7 0.5432306 0.4066101 0.3359987
## 6 49614531357631 58209.9 0.3696564 29.4961404 0.2532374
## DoanhThu_TangTruong_YoY LoiNhuan_TangTruong_YoY EPS SL_CoPhieu_LuuHanh
## 1 0.0000000 0.0000000 7140 1977965757
## 2 -12.3896680 -97.8868699 4400 67825115
## 3 -8.1244079 -48.9808874 6748 22563218
## 4 9.2190229 66.1199968 4994 50646506
## 5 17.1864317 0.6594479 5911 43071660
## 6 -0.8017943 -27.9631807 6142 29860515
## VonHoa_TyVND P_E_CuoiNam BienLoiNhuanRong_Nam CFO
## 1 67556.4314 4.783543 19.2424318 16701449198611
## 2 1229.5879 4.120182 0.4641206 9126872112300
## 3 746.5943 4.903527 0.2577292 4942224182550
## 4 2851.9655 11.275771 0.3920011 14385549919558
## 5 2249.7060 8.836356 0.3367165 12421887654437
## 6 1738.1776 9.477353 0.2445204 12680818093290
## TyLe_CFO_Tren_LNST
## 1 1.182598
## 2 30.582906
## 3 32.459836
## 4 56.875921
## 5 48.790472
## 6 69.141719
Nhận xét
Mục này hoàn thiện bộ dữ liệu bằng cách bổ sung các chỉ tiêu từ Bảng KQKD (phụ lục) và Bảng LCTT, cho phép phân tích về định giá thị trường và chất lượng lợi nhuận.
Phân tích Định giá P/E (Thao tác 21-22):
Bằng cách trích xuất EPS (eps_raw_vec)
và sử dụng LoiNhuanSauThue (đã có), bộ dữ liệu đã tự động
tính toán ra SL_CoPhieu_LuuHanh
(slcplh_calc_vec).
Từ đó, chỉ số P/E (P_E_CuoiNam) và Vốn hóa
(VonHoa_TyVND) được tính toán. Kết quả thống kê cho thấy
P/E trung bình (pe_mean) là 9.93 và P/E trung vị
(pe_median) là 9.48.
Hai chỉ số này rất gần nhau, cho thấy P/E của GAS trong 11 năm qua tương đối ổn định và không có các giá trị ngoại lai (outlier) quá lớn. Mức P/E trung bình ~9.5-10 là một mức định giá tương đối hợp lý, cho thấy thị trường định giá GAS ở mức ổn định, không quá đắt cũng không quá rẻ.
Phân tích Chất lượng dòng tiền (Thao tác 24): Thao tác này đã đọc
Bảng LCTT (Sheet 3) và tính Tỷ lệ Chuyển đổi Tiền mặt
(TyLe_CFO_Tren_LNST).
Kết quả cho thấy Tỷ lệ trung bình (cash_conv_mean)
là 22.16, trong khi Tỷ lệ trung vị (cash_conv_median) chỉ
là 1.19.
Sự chênh lệch cực kỳ lớn này cho thấy điều tương tự như
đã thấy với LoiNhuan_TangTruong_YoY: Tồn tại ít nhất một
năm ngoại lai (outlier) với Tỷ lệ CFO/LNST rất cao (ví dụ, LNST rất thấp
nhưng CFO rất cao), làm cho giá trị Mean (22.16) trở nên vô
nghĩa và không đại diện cho hoạt động kinh doanh thông thường.
Ngược lại, Tỷ lệ trung vị (cash_conv_median) là 1.19
là một con số đáng tin cậy và rất tích cực. Nó có nghĩa là: trong một
năm kinh doanh điển hình, cứ mỗi 1 đồng Lợi nhuận sau thuế GAS ghi nhận
trên sổ sách, họ thực sự tạo ra được 1.19 đồng tiền mặt. Tỷ lệ > 1
cho thấy chất lượng lợi nhuận của GAS là rất cao, lợi nhuận được chuyển
đổi thành tiền thật một cách hiệu quả.
# 1. Tải các thư viện trực quan hóa
library(ggplot2) # Nền tảng xây dựng biểu đồ
library(plotly) # Giúp biểu đồ có tính tương tác (động)
library(tidyr) # Dùng để biến đổi dữ liệu (cho biểu đồ xếp chồng)Giới thiệu
Nhóm biểu đồ này trực quan hóa các chỉ số cơ bản nhất về quy mô (Doanh thu, Lợi nhuận, Tài sản) và tốc độ tăng trưởng của chúng.
Phân tích Doanh thu (DT) & Lợi nhuận (LN):
Từ Mục 2.4.1, ta biết mean_dt_ty là 77,207 tỷ và
mean_lnst_ty là 6,236 tỷ. Hai biến này có quy mô quá chênh
lệch, do đó Biểu đồ 1 bắt buộc phải sử dụng 2 trục Y
(dual-axis) để so sánh xu hướng của chúng.
Ta cũng biết tương quan giữa chúng là 0.70 (Mục 2.4.4, đã lọc outlier), vì vậy chúng ta kỳ vọng hai đường này sẽ di chuyển tương đối cùng chiều.
Phân tích Tăng trưởng (Growth):
DoanhThu_TangTruong_YoY (Biên độ: -14.5% đến 27.5%)
và LoiNhuan_TangTruong_YoY (Biên độ: -97.9% đến 4182.9%)
cho thấy sự bất ổn (Mục 2.4.1).
Biểu đồ 2 & 3 sẽ dùng biểu đồ cột (bar
chart) với 2 màu (Âm/Dương) để làm rõ sự biến động này. Đặc biệt,
Biểu đồ 3 sẽ phải xử lý outlier 4182.9%
(năm 2017) để các năm khác có thể được nhìn thấy.
Phân tích Cấu trúc Vốn:
Biểu đồ 4 & 5 sẽ trực quan hóa
TongTaiSan, NoPhaiTra, và
VonChuSoHuu.
Từ Mục 2.4.3, đã xác nhận 1 năm outlier (có
TongTaiSan chỉ 621.79 tỷ, trong khi
mean_tts_ty là 62,421 tỷ). Do đó, bắt buộc phải lọc bỏ
outlier này (TongTaiSan < 1e12) khi vẽ, nếu không toàn
bộ biểu đồ quy mô Bảng Cân Đối Kế Toán sẽ vô nghĩa.
Trực quan hóa và nhận xét:
1. Biểu đồ đường: Xu hướng Doanh thu vs. Lợi nhuận (2 Trục Y)
# 1. Chuẩn bị dữ liệu: Chuyển sang Tỷ VND
p1_data <- GAS_data_final %>%
mutate(
DT_Ty = DoanhThu / 1e9, # Doanh thu (Tỷ VND)
LNST_Ty = LoiNhuanSauThue / 1e9 # Lợi nhuận (Tỷ VND)
)
# 2. Định nghĩa trục Y thứ 2 (cho Lợi nhuận)
y2 <- list(
overlaying = "y", # Đè trục y2 lên trục y1
side = "right", # Đặt ở bên phải
title = "Lợi nhuận (Tỷ VND)", # Tiêu đề trục
showgrid = FALSE # Ẩn lưới
)
# 3. Vẽ biểu đồ plotly (p1)
p1 <- plot_ly(data = p1_data, x = ~Nam,
# Định nghĩa tooltip (hover)
hovertemplate = paste(
"Năm: %{x}<br>",
"%{yaxis.title.text}: %{y:,.0f} Tỷ VND"
)) %>%
# Thêm đường Doanh thu (sử dụng trục y1 mặc định)
add_lines(y = ~DT_Ty, name = "Doanh Thu (Trục trái)", yaxis = "y1") %>%
# Thêm đường Lợi nhuận (sử dụng trục y2)
add_lines(y = ~LNST_Ty, name = "Lợi Nhuận (Trục phải)", yaxis = "y2") %>%
# Áp dụng layout (tiêu đề, 2 trục Y)
layout(
title = "Biểu đồ 1: Xu hướng Doanh thu và Lợi nhuận (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Doanh thu (Tỷ VND)"),
yaxis2 = y2, # Áp dụng trục y2
legend = list(x = 0.1, y = -0.2, orientation = 'h') # Đặt chú thích bên dưới
)
# 4. Hiển thị biểu đồ
p1Nhận xét Biểu đồ 1: Xu hướng Doanh thu vs. Lợi nhuận
Tính bất ổn của Lợi nhuận: Đặc điểm nổi bật nhất là sự sụp đổ của Lợi nhuận (LN - đường màu cam) trong giai đoạn 2015-2017. Trong khi Doanh thu (DT - đường màu xanh) chỉ giảm nhẹ từ ~74k tỷ (2014) xuống đáy ~59k tỷ (2016), thì Lợi nhuận đã rơi tự do từ đỉnh ~14k tỷ (2014) xuống gần như bằng 0 trong suốt 3 năm 2015, 2016, 2017.
Giai đoạn phục hồi: Giai đoạn 2017-2019, DT phục hồi về mốc ~75k tỷ, nhưng LN vẫn giảm nhẹ.
Đỉnh 2022: Giai đoạn 2020-2022 chứng kiến sự tăng trưởng bùng nổ, cả DT và LN đều đạt đỉnh lịch sử. DT đạt ~100k tỷ và LN đạt ~14.8k tỷ.
Kết luận: Biểu đồ này khẳng định LN của GAS có tính chu kỳ và rủi ro cao, biến động mạnh hơn rất nhiều so với Doanh thu, cho thấy sự nhạy cảm lớn với các yếu tố bên ngoài (như giá dầu thế giới).
2. & 3. Biểu đồ Cột: Tăng trưởng Doanh thu và Lợi nhuận (% YoY)
# 1. Chuẩn bị dữ liệu: Thêm cột 'color' (màu sắc)
p2_p3_data <- GAS_data_final %>%
mutate(
# Tạo biến phân loại cho màu sắc
color_dt = ifelse(DoanhThu_TangTruong_YoY > 0, "Tăng", "Giảm"),
color_ln = ifelse(LoiNhuan_TangTruong_YoY > 0, "Tăng", "Giảm")
)
# 2. Định nghĩa màu
colors_growth <- c("Tăng" = "#1f77b4", "Giảm" = "#d62728") # Xanh / Đỏ
# 3. Vẽ Biểu đồ 2: Tăng trưởng Doanh thu (p2)
p2 <- plot_ly(data = p2_p3_data, x = ~Nam, y = ~DoanhThu_TangTruong_YoY,
color = ~color_dt, # Tô màu theo biến color_dt
colors = colors_growth, # Áp dụng màu Xanh/Đỏ
type = "bar",
hovertemplate = paste(
"Năm: %{x}<br>",
"Tăng trưởng DT: %{y:.2f}%"
)) %>%
layout(
title = "Biểu đồ 2: Tăng trưởng Doanh thu (% YoY) (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "% Tăng trưởng")
)
# 4. Vẽ Biểu đồ 3: Tăng trưởng Lợi nhuận (p3)
# LỌC BỎ OUTLIER (4182.9%) để biểu đồ có ý nghĩa
p3_data_filtered <- p2_p3_data %>%
filter(LoiNhuan_TangTruong_YoY < 4000) # Lọc bỏ năm 2017
p3 <- plot_ly(data = p3_data_filtered, x = ~Nam, y = ~LoiNhuan_TangTruong_YoY,
color = ~color_ln, # Tô màu theo biến color_ln
colors = colors_growth, # Áp dụng màu Xanh/Đỏ
type = "bar",
hovertemplate = paste(
"Năm: %{x}<br>",
"Tăng trưởng LN: %{y:.2f}%"
)) %>%
layout(
title = "Biểu đồ 3: Tăng trưởng Lợi nhuận (% YoY) (Đã lọc outlier 2017)",
xaxis = list(title = "Năm"),
yaxis = list(title = "% Tăng trưởng")
)
# 5. Hiển thị biểu đồ
p2Nhận xét Biểu đồ 2: Tăng trưởng Doanh thu (% YoY)
Biểu đồ cột (tô màu ĐỎ/XANH) làm rõ hơn tính chu kỳ của Doanh thu:
Các chu kỳ giảm: Giai đoạn 2015-2016 (cột đỏ) cho thấy sụt giảm liên tiếp. Tuy nhiên, đợt sụt giảm mạnh và sâu nhất về doanh thu là năm 2020 (đáy ~ -14.5%), trùng khớp với thời điểm đại dịch COVID-19 làm ngưng trệ các hoạt động kinh tế.
Các chu kỳ tăng: Giai đoạn phục hồi mạnh nhất là 2021-2022, với đỉnh tăng trưởng vào năm 2022 (đạt ~ +27.5%).
Kết luận: Tăng trưởng doanh thu của GAS không ổn định mà đi theo chu kỳ rõ rệt, với 5 năm tăng trưởng âm (màu đỏ) và 6 năm tăng trưởng dương (màu xanh, tính cả năm 2014 là 0).
Nhận xét Biểu đồ 3: Tăng trưởng Lợi nhuận (% YoY)
(Lưu ý: Biểu đồ này đã lọc bỏ 1 năm outlier có tăng trưởng > 4000% để làm rõ các biến động còn lại).
Biến động khốc liệt: Biểu đồ này cho thấy sự biến động còn dữ dội hơn nhiều so với Doanh thu. Giai đoạn khủng hoảng 2015-2016 được thể hiện rõ: Lợi nhuận sụt giảm gần như toàn bộ vào năm 2015 (đáy ~ -98%) và tiếp tục giảm sâu vào năm 2016 (~ -49%).
Phục hồi mạnh: Các năm phục hồi lợi nhuận mạnh nhất (sau khi lọc outlier) là 2018 (tăng ~ +66%) và 2022 (tăng ~ +70%).
Kết luận: Biểu đồ này tái khẳng định kết luận từ
Mục 2.4.1 và Biểu đồ 1: Lợi nhuận của GAS cực kỳ bất ổn định. Việc
median_growth_ln (trung vị) bằng 0 (kết quả 2.4.1) là hoàn
toàn có cơ sở, vì số năm tăng/giảm gần như bằng nhau và biên độ biến
động rất lớn.
4. & 5. Biểu đồ Đường và Diện tích: Quy mô và Cơ cấu Bảng Cân Đối Kế Toán
# 1. Chuẩn bị dữ liệu: LỌC OUTLIER (TTS < 1e12) và tính Tỷ VND
p4_p5_data <- GAS_data_final %>%
filter(TongTaiSan > 1e12) %>% # Lọc bỏ outlier 621 tỷ
mutate(
TTS_Ty = TongTaiSan / 1e9,
NPT_Ty = NoPhaiTra / 1e9,
VCSH_Ty = VonChuSoHuu / 1e9
)
# 2. Vẽ Biểu đồ 4: Xu hướng Quy mô Bảng CĐKT (p4)
p4 <- plot_ly(data = p4_p5_data, x = ~Nam,
hovertemplate = paste(
"Năm: %{x}<br>",
"%{yaxis.title.text}: %{y:,.0f} Tỷ VND"
)) %>%
# Thêm đường Tổng Tài Sản
add_lines(y = ~TTS_Ty, name = "Tổng Tài Sản") %>%
# Thêm đường Vốn Chủ Sg Hữu
add_lines(y = ~VCSH_Ty, name = "Vốn Chủ Sở Hữu") %>%
# Thêm đường Nợ Phải Trả
add_lines(y = ~NPT_Ty, name = "Nợ Phải Trả") %>%
layout(
title = "Biểu đồ 4: Xu hướng Quy mô Bảng CĐKT (Đã lọc Outlier)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Quy mô (Tỷ VND)"),
legend = list(x = 0.1, y = -0.2, orientation = 'h')
)
# 3. Chuẩn bị dữ liệu cho Biểu đồ 5 (Stacked Area): Dạng "long"
p5_data_long <- p4_p5_data %>%
select(Nam, NPT_Ty, VCSH_Ty) %>% # Chỉ chọn 2 thành phần của nguồn vốn
gather(key = "LoaiNguonVon", value = "GiaTri_Ty", -Nam) # Chuyển từ wide sang long
# 4. Vẽ Biểu đồ 5: Cơ cấu Nguồn vốn (p5)
p5 <- plot_ly(data = p5_data_long, x = ~Nam, y = ~GiaTri_Ty,
color = ~LoaiNguonVon, # Tô màu theo Nợ / VCSH
type = 'scatter',
mode = 'none', # Không vẽ điểm hay đường
stackgroup = 'one', # Quan trọng: xếp chồng lên nhau
hovertemplate = paste(
"Năm: %{x}<br>",
"Loại: %{fullData.name}<br>",
"Giá trị: %{y:,.0f} Tỷ VND"
)) %>%
layout(
title = "Biểu đồ 5: Cơ cấu Nguồn vốn (Nợ vs. Vốn CSH) (Đã lọc Outlier)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Tổng Nguồn vốn (Tỷ VND)")
)
# 5. Hiển thị biểu đồ
p44. & 5. Nhận xét Biểu đồ 4 & 5: Quy mô và Cơ cấu Bảng CĐKT
(Lưu ý: Cả hai biểu đồ đều đã lọc bỏ 1 năm outlier (có TTS 621 tỷ) để trục Y có ý nghĩa).
Cấu trúc tài chính an toàn: Cả hai biểu đồ đều
xác nhận một cấu trúc tài chính an toàn và bảo thủ. Biểu đồ 5 (diện tích
xếp chồng) cho thấy phần Vốn Chủ Sở Hữu (VCSH - màu cam)
luôn chiếm tỷ trọng lớn hơn đáng kể (gấp 2-3 lần) so với
Nợ Phải Trả (NPT - màu xanh).
Tăng trưởng nhờ Vốn chủ: Biểu đồ 4 cho thấy
đường Tổng Tài Sản (TTS - xanh dương) và đường
Vốn Chủ Sở Hữu (VCSH - cam) tăng trưởng gần như song song.
Điều này cho thấy GAS chủ yếu tài trợ cho sự mở rộng quy mô của mình
bằng lợi nhuận giữ lại (tăng vốn chủ), thay vì dùng nợ vay.
Biến động Nợ: Đường Nợ Phải Trả
(NPT - xanh lá) duy trì ở mức thấp và ổn định từ 2014-2020. Nó có một
đợt tăng đột biến vào năm 2021 (đạt đỉnh ~26k tỷ) trước khi giảm trở
lại. Điều này cho thấy trong giai đoạn phục hồi 2021-2022, GAS đã tạm
thời tăng cường đòn bẩy để tài trợ cho hoạt động, nhưng nhanh chóng đưa
về mức an toàn.
Kết luận: GAS duy trì một cấu trúc vốn rất mạnh,
với tỷ lệ đòn bẩy thấp (khẳng định mean_tsn_vcsh = 0.36 ở
Mục 2.4.1).
Giới thiệu:
Nhóm biểu đồ này tập trung vào việc đánh giá “chất lượng” hoạt động
của GAS: khả năng sinh lời (ROE, ROA), hiệu
quả chuyển đổi doanh thu (Biên LN ròng), và cấu trúc rủi ro
(Đòn bẩy).
Phân tích Hiệu suất Sinh lời (ROE & ROA):
Từ Mục 2.4.1 & 2.4.2, ta biết hiệu suất sinh lời rất bất ổn.
mean_roe (11.94%) và sd_roe (12.45%) gần bằng
nhau, cho thấy sự biến động cực lớn.
Biểu đồ 6 sẽ trực quan hóa sự sụt giảm mạnh của ROE/ROA trong giai đoạn 2015-2017 (khi LNST sụt giảm) và sự phục hồi sau đó.
Biểu đồ 7 sẽ sử dụng ngưỡng 15% (gần với
median_roe là 15.87%) để làm nổi bật 6 năm hoạt động hiệu
quả (kết quả từ roe_tren_15 ở 2.4.2).
Phân tích Cấu trúc Tài chính (Đòn bẩy):
TySoNo_Tren_VCSH. Chúng ta biết mean_tsn_vcsh
là 0.36 (thấp) và biểu đồ này bắt buộc phải lọc outlier (năm có
TongTaiSan < 1e12) để cho thấy xu hướng đòn bẩy thực tế
(dự kiến là ổn định và thấp).Phân tích Hiệu quả (Biên Lợi nhuận):
BienLoiNhuanRong_Nam.
Chỉ số này (với bln_mean = 7.44% và bln_median
= 10.04%) đo lường 100 đồng doanh thu tạo ra bao nhiêu đồng lợi nhuận.
Xu hướng của nó được kỳ vọng sẽ theo rất sát xu hướng của Lợi nhuận
(Biểu đồ 1).Phân tích Tác động Đòn bẩy:
TySoNo_Tren_VCSH và
ROE_Nam là rất yếu (chỉ 0.15). Biểu đồ phân tán này sẽ trực
quan hóa mối quan hệ yếu ớt đó.Trực quan hóa và Nhận xét:
6. Biểu đồ Đường: ROE và ROA (%)
# 1. Chuẩn vị dữ liệu
# (ROE_Nam và ROA_Nam đã có đơn vị % từ Mục 1.3)
p6_data <- GAS_data_final
# 2. Vẽ biểu đồ plotly (p6)
p6 <- plot_ly(data = p6_data, x = ~Nam,
# Định nghĩa tooltip (hover)
hovertemplate = paste(
"Năm: %{x}<br>",
"%{fullData.name}: %{y:.2f}%"
)) %>%
# Thêm đường ROE (%)
add_lines(y = ~ROE_Nam, name = "ROE (Tỷ suất LN trên VCSH)") %>%
# Thêm đường ROA (%)
add_lines(y = ~ROA_Nam, name = "ROA (Tỷ suất LN trên Tài sản)") %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 6: Diễn biến ROE và ROA (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Tỷ suất Lợi nhuận (%)"),
legend = list(x = 0.1, y = -0.2, orientation = 'h') # Đặt chú thích bên dưới
)
# 3. Hiển thị biểu đồ
p6Nhận xét Biểu đồ 6: ROE và ROA
Biểu đồ này trực quan hóa một cách rõ nét sự bất ổn trong hiệu suất sinh lời và cũng xác nhận năm 2019 chính là năm dữ liệu ngoại lai (outlier) mà đã phát hiện:
Sự sụp đổ 2015-2018: Tương tự như Biểu đồ 1, cả
ROE (Tỷ suất LN trên VCSH - đường xanh) và ROA
(Tỷ suất LN trên Tài sản - đường cam) đều sụp đổ từ đỉnh 2014 (ROE ~37%,
ROA ~26%) xuống gần như 0% trong suốt 4 năm 2015-2018, tương ứng với
giai đoạn Lợi nhuận sụt giảm.
Phát hiện Outlier 2019: Điểm dị biệt nhất là năm
2019. ROE (xanh) vẫn ở mức 0%, trong khi ROA
(cam) đột ngột tăng vọt lên đỉnh cao nhất (~29.5%).
Phân tích: Điều này xảy ra vì ROA =
LNST / TongTaiSan và ROE =
LNST / VonChuSoHuu.
Dữ liệu từ 2.4.1 cho thấy năm 2019, LNST và
VCSH vẫn bình thường, nhưng TongTaiSan bị ghi
nhận lỗi (chỉ 621 tỷ).
Do đó, ROA (với mẫu số TongTaiSan 621
tỷ) đã bị tính toán sai và tăng vọt. ROE (với mẫu số
VCSH 49k tỷ) vẫn ở mức 0%.
Phục hồi 2020-2024: Từ 2020, khi
TongTaiSan trở lại bình thường, cả hai chỉ số ROE và ROA
đều phục hồi về mức ổn (10-25%).
Kết luận: Biểu đồ này khẳng định sự biến động
của hiệu suất sinh lời và xác nhận 2019 là năm outlier do lỗi dữ liệu
TongTaiSan.
7. Biểu đồ Cột kết hợp Đường: ROE hàng năm với ngưỡng tham chiếu 15%
# 1. Chuẩn bị dữ liệu: Thêm cột Ngưỡng 15%
p7_data <- GAS_data_final %>%
mutate(
Nguong_15 = 15, # Tạo một cột có giá trị 15%
# Tạo biến màu sắc (Tích cực/Tiêu cực)
color_roe = ifelse(ROE_Nam >= Nguong_15, "Trên 15%", "Dưới 15%")
)
# 2. Định nghĩa màu
colors_roe <- c("Trên 15%" = "#1f77b4", "Dưới 15%" = "#d62728") # Xanh / Đỏ
# 3. Vẽ biểu đồ plotly (p7)
p7 <- plot_ly(data = p7_data, x = ~Nam) %>%
# Thêm Biểu đồ Cột cho ROE
add_bars(y = ~ROE_Nam,
name = "ROE Hàng năm",
color = ~color_roe, # Tô màu theo biến color_roe
colors = colors_roe, # Áp dụng màu Xanh/Đỏ
hovertemplate = paste(
"Năm: %{x}<br>",
"ROE: %{y:.2f}%"
)) %>%
# Thêm Đường tham chiếu 15%
add_lines(y = ~Nguong_15,
name = "Ngưỡng tham chiếu 15%",
line = list(color = 'black', dash = 'dash'), # Nét đứt màu đen
hovertemplate = "Ngưỡng tham chiếu: 15%") %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 7: ROE hàng năm so với Ngưỡng 15%",
xaxis = list(title = "Năm"),
yaxis = list(title = "ROE (%)"),
legend = list(x = 0.1, y = -0.2, orientation = 'h')
)
# 4. Hiển thị biểu đồ
p7Nhận xét Biểu đồ 7: ROE hàng năm vs. Ngưỡng 15%
Biểu đồ này phân loại rõ ràng các năm hoạt động hiệu quả và không hiệu quả của GAS:
Phân loại rõ rệt: Biểu đồ cho thấy 2 “trạng thái” rõ rệt của GAS.
Nhóm Hiệu quả (Cột xanh): Gồm 6 năm (2014, 2020,
2021, 2022, 2023, 2024) có ROE vượt trội so với ngưỡng tham
chiếu 15%. Năm 2014 là năm hoàng kim (ROE ~37.5%), và giai đoạn
2020-2024 là giai đoạn phục hồi hiệu quả bền vững.
Nhóm Kém hiệu quả (Cột đỏ): Gồm 5 năm (2015,
2016, 2017, 2018, 2019) có ROE gần như bằng 0.
Kết luận: Trực quan hóa này xác nhận kết quả
roe_tren_15 (Mục 2.4.2) là 6 năm. Nó cho thấy GAS có khả
năng sinh lời rất cao, nhưng cũng tiềm ẩn rủi ro sụt giảm mạnh trong
nhiều năm liên tiếp.
8. Biểu đồ Đường: Diễn biến Đòn bẩy Tài chính (Tỷ số Nợ / VCSH)
# 1. Chuẩn bị dữ liệu: LỌC OUTLIER
p8_data <- GAS_data_final %>%
filter(TongTaiSan > 1e12) # Lọc bỏ outlier 621 tỷ
# 2. Vẽ biểu đồ plotly (p8)
p8 <- plot_ly(data = p8_data, x = ~Nam, y = ~TySoNo_Tren_VCSH,
type = 'scatter', mode = 'lines+markers', # Cả đường và điểm
name = "Tỷ số Nợ / VCSH",
hovertemplate = paste(
"Năm: %{x}<br>",
"Tỷ số Nợ/VCSH: %{y:.2f}"
)) %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 8: Diễn biến Đòn bẩy Tài chính (Đã lọc Outlier)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Tỷ lệ (Lần)")
)
# 3. Hiển thị biểu đồ
p8Nhận xét Biểu đồ 8: Đòn bẩy Tài chính
(Lưu ý: Biểu đồ này đã lọc bỏ năm outlier 2019, nên nó phản ánh đúng xu hướng đòn bẩy trong 10 năm kinh doanh bình thường).
Cấu trúc Nợ an toàn: Biểu đồ cho thấy
Tỷ số Nợ / VCSH (Đòn bẩy) luôn duy trì ở mức rất thấp, toàn
bộ đều dưới 0.52 (tức Nợ luôn ít hơn một nửa Vốn chủ). Điều này khẳng
định cấu trúc tài chính an toàn mà ta đã thấy ở Biểu đồ 4 &
5.
Các điểm biến động:
Đáy 2020: Đòn bẩy chạm đáy vào năm 2020 (chỉ ~0.28). Đây là năm COVID-19, cho thấy GAS đã co về phòng thủ, giảm nợ vay.
Đỉnh 2021: Ngay sau đó, đòn bẩy tăng vọt lên đỉnh cao nhất (~0.51) vào năm 2021.
Kết luận (Kết hợp Biểu đồ 4): Kết hợp với Biểu đồ 4 (cho thấy Nợ Phải Trả cũng đạt đỉnh năm 2021), có thể kết luận: Năm 2021, GAS đã chủ động tăng cường sử dụng nợ vay (tăng đòn bẩy) để tài trợ cho sự phục hồi và tăng trưởng bùng nổ của giai đoạn 2021-2022.
9. Biểu đồ Cột: Diễn biến Biên Lợi nhuận ròng (%)
# 1. Chuẩn bị dữ liệu: Sử dụng biến 'BienLoiNhuanRong_Nam' (từ 2.4.5)
p9_data <- GAS_data_final
# 2. Vẽ biểu đồ plotly (p9)
p9 <- plot_ly(data = p9_data, x = ~Nam, y = ~BienLoiNhuanRong_Nam,
type = "bar",
name = "Biên Lợi nhuận ròng",
hovertemplate = paste(
"Năm: %{x}<br>",
"Biên LN ròng: %{y:.2f}%"
)) %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 9: Diễn biến Biên Lợi nhuận ròng (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Biên Lợi nhuận ròng (%)")
)
# 3. Hiển thị biểu đồ
p9Nhận xét Biểu đồ 9: Diễn biến Biên Lợi nhuận ròng (%)
Phản ánh Lợi nhuận: Vì Biên Lợi nhuận ròng
(LNST / DoanhThu) có cùng tử số
(LNST) với ROE/ROA, không ngạc nhiên khi hình dạng của biểu
đồ này gần như giống hệt Biểu đồ 6 (trừ outlier 2019).
Hai trạng thái: Biểu đồ cho thấy 2 trạng thái rõ rệt:
Giai đoạn Biên lợi nhuận cao (2014, 2020-2024): Đạt đỉnh 2014 (Biên LN ~19%), nghĩa là 100 đồng doanh thu tạo ra 19 đồng lợi nhuận. Giai đoạn 2020-2024 phục hồi ở mức 10-15%.
Giai đoạn Biên lợi nhuận sụp đổ (2015-2019): Biên lợi nhuận gần như bằng 0, cho thấy trong 5 năm này, GAS kinh doanh gần như hòa vốn (doanh thu chỉ đủ bù chi phí, có thể do giá dầu sụt giảm).
Kết luận: Biên lợi nhuận của GAS rất nhạy cảm với các cú sốc bên ngoài.
10. Biểu đồ Phân tán: Phân tích Tác động Đòn bẩy (Nợ/VCSH vs. ROE)
# 1. Chuẩn bị dữ liệu: LỌC OUTLIER
p10_data <- GAS_data_final %>%
filter(TongTaiSan > 1e12) # Lọc bỏ outlier 621 tỷ
# 2. Vẽ biểu đồ ggplot (p10)
# (Sử dụng ggplot vì đây là biểu đồ phân tích, không phải xu hướng)
p10 <- ggplot(data = p10_data,
aes(x = TySoNo_Tren_VCSH, y = ROE_Nam)) +
# Thêm các điểm (size = 3)
geom_point(aes(color = as.factor(Nam)), size = 3) + # 'color' theo 'Nam'
# Thêm nhãn cho các điểm
geom_text(aes(label = Nam), vjust = -0.8, size = 3) +
# Thêm đường xu hướng tuyến tính (lm = linear model)
geom_smooth(method = "lm", se = FALSE, color = "red", linetype = "dashed") +
# Đặt tiêu đề và nhãn trục
labs(
title = "Biểu đồ 10: Tác động của Đòn bẩy lên ROE (Đã lọc Outlier)",
x = "Đòn bẩy Tài chính (Tỷ số Nợ / VCSH)",
y = "Hiệu quả Sinh lời (ROE %)",
caption = "Phân tích 10 năm (2014-2024, đã lọc 1 outlier)",
color = "Năm" # Tiêu đề cho phần chú thích màu
) +
theme_minimal() # Sử dụng theme tối giản
# 3. Hiển thị biểu đồ
p10Nhận xét Biểu đồ 10: Tác động của Đòn bẩy lên ROE
(Lưu ý: Biểu đồ này phân tích 10 năm, đã lọc bỏ outlier 2019).
Tương quan yếu: Đường xu hướng (nét đứt màu đỏ)
dốc lên rất nhẹ. Điều này trực quan hóa chính xác kết quả
cor_roe_gia = 0.276 (Mục 2.4.4) - một mối tương quan dương
nhưng rất yếu.
Phân cụm dữ liệu: Điểm nổi bật nhất của biểu đồ là dữ liệu bị phân tách thành 2 cụm rõ rệt:
Cụm Kém hiệu quả (ROE ~ 0%): Các năm 2015, 2016, 2017, 2018 đều nằm ở đáy, bất kể mức đòn bẩy là bao nhiêu.
Cụm Hiệu quả (ROE > 15%): Gồm 2014, 2020, 2021, 2022, 2023, 2024.
Không có mối quan hệ rõ ràng: Trong “Cụm Hiệu quả”, không có mối liên hệ rõ ràng. Năm có ROE cao nhất (2014) lại dùng đòn bẩy cao (~0.43). Ngược lại, năm có đòn bẩy cao nhất (2021, ~0.51) lại có ROE thấp hơn (chỉ ~17%). Trong khi đó, các năm có ROE rất cao (2022, 2023, 2024) lại dùng đòn bẩy ở mức trung bình-thấp (~0.35).
Kết luận: Biểu đồ này bác bỏ giả thuyết “dùng nhiều nợ hơn sẽ tăng ROE”. Nó cho thấy hiệu quả sinh lời (ROE) của GAS không phụ thuộc vào đòn bẩy tài chính, mà phụ thuộc vào các yếu tố vĩ mô (như giá dầu, nhu cầu thị trường) đã quyết định năm đó “hiệu quả” hay “kém hiệu quả”.
Giới thiệu:
Nhóm biểu đồ này khám phá mối quan hệ giữa các chỉ số tài chính nội tại và các chỉ số thị trường (định giá).
Phân tích Tương quan Lợi nhuận (LNST, ROE) vs. Giá:
Từ Mục 2.4.4, ma trận tương quan (đã lọc outlier) cho thấy mối
tương quan giữa LoiNhuanSauThue và
Gia_DongCua_CuoiNam là trung bình (cor_ln_gia
= 0.495), và tương quan giữa ROE_Nam và
Gia_DongCua_CuoiNam là yếu (cor_roe_gia =
0.276).
Biểu đồ 11 & 12 sẽ trực quan hóa mối quan hệ này bằng biểu đồ phân tán (scatter plot) động. Chúng ta kỳ vọng đường xu hướng (regression line) trên Biểu đồ 11 sẽ dốc hơn Biểu đồ 12.
Phân tích Tương quan Quy mô (Tài sản) vs. Vốn hóa:
Ngược lại, ma trận 2.4.4 cho thấy tương quan rất mạnh giữa
TongTaiSan và Gia_DongCua_CuoiNam (0.83). Biến
VonHoa_TyVND (Vốn hóa) được tính từ Giá, do đó chúng ta
cũng kỳ vọng một mối quan hệ tuyến tính rất mạnh giữa
TongTaiSan và VonHoa_TyVND.
Biểu đồ 13 sẽ vẽ mối quan hệ này. Lưu ý quan
trọng: Biểu đồ này bắt buộc phải lọc outlier năm 2019 (có
TongTaiSan 621 tỷ) để đường xu hướng có ý nghĩa.
Phân tích Xu hướng Định giá (Vốn hóa, P/E):
Biểu đồ 14 sẽ so sánh xu hướng của
VonHoa_TyVND và LoiNhuanSauThue (sử dụng 2
trục Y) để xem vốn hóa thị trường có bám sát lợi nhuận thực tế hay
không.
Biểu đồ 15 sẽ vẽ diễn biến của chỉ số
P_E_CuoiNam (đã tính ở 2.4.5, với pe_mean =
9.93) để xem thị trường đã định giá GAS đắt hay rẻ qua các năm.
Trực quan hóa và Nhận xét:
11. Biểu đồ Phân tán: Lợi nhuận Sau thuế vs. Giá Cổ phiếu
# 1. Chuẩn bị dữ liệu: Chuyển LNST sang Tỷ VND
p11_data <- GAS_data_final %>%
mutate(LNST_Ty = LoiNhuanSauThue / 1e9)
# 2. Vẽ biểu đồ plotly (p11)
p11 <- plot_ly(data = p11_data,
x = ~LNST_Ty, # Trục X: Lợi nhuận
y = ~Gia_DongCua_CuoiNam, # Trục Y: Giá
text = ~Nam, # Hiển thị 'Năm' khi hover
type = 'scatter', mode = 'markers', # Dạng điểm
hovertemplate = paste(
"Năm: %{text}<br>",
"Lợi nhuận: %{x:,.0f} Tỷ VND<br>",
"Giá Cổ phiếu: %{y:,.0f} VND"
)) %>%
# Thêm đường xu hướng tuyến tính
add_trace(type = 'scatter', mode = 'lines',
x = ~LNST_Ty,
# Dùng hàm fitted() để lấy giá trị dự đoán từ 1 mô hình tuyến tính (lm)
y = fitted(lm(Gia_DongCua_CuoiNam ~ LNST_Ty, data = p11_data)),
name = "Đường xu hướng",
hoverinfo = 'none') %>% # Không cần hover cho đường này
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 11: Mối quan hệ LNST vs. Giá Cổ phiếu (2014-2024)",
xaxis = list(title = "Lợi nhuận Sau thuế (Tỷ VND)"),
yaxis = list(title = "Giá Đóng cửa Cuối năm (VND)"),
showlegend = FALSE # Ẩn chú thích
)
# 3. Hiển thị biểu đồ
p11Nhận xét Biểu đồ 11: Mối quan hệ LNST vs. Giá Cổ phiếu
Biểu đồ phân tán này cho thấy một mối quan hệ phức tạp, khẳng định
kết quả tương quan trung bình (cor_ln_gia = 0.495) từ Mục
2.4.4.
Tổng quan: Đường xu hướng (màu cam) có độ dốc dương, cho thấy về tổng thể, lợi nhuận cao hơn có liên quan đến giá cổ phiếu cao hơn.
Phân cụm dữ liệu: Tuy nhiên, các điểm dữ liệu phân tán rất rộng (“nhiễu”), đặc biệt là ở cụm bên trái (Lợi nhuận < 2,000 tỷ). Trong cụm này (tương ứng giai đoạn 2015-2019), giá cổ phiếu dao động rất mạnh, từ mức đáy (năm 2015, ~18k VND) đến mức cao (năm 2018, ~58k VND) dù lợi nhuận gần như bằng 0.
Kết luận: Biểu đồ này chỉ ra rằng Lợi nhuận sau thuế không phải là yếu tố duy nhất hay yếu tố mạnh nhất quyết định giá cổ phiếu. Trong các năm khủng hoảng (LNST thấp), thị trường dường như định giá cổ phiếu dựa trên các yếu tố khác (như tài sản hoặc kỳ vọng phục hồi) thay vì lợi nhuận thực tế.
12. Biểu đồ Phân tán: ROE (%) vs. Giá Cổ phiếu
# 1. Chuẩn bị dữ liệu
p12_data <- GAS_data_final
# 2. Vẽ biểu đồ plotly (p12)
p12 <- plot_ly(data = p12_data,
x = ~ROE_Nam, # Trục X: ROE
y = ~Gia_DongCua_CuoiNam, # Trục Y: Giá
text = ~Nam, # Hiển thị 'Năm' khi hover
type = 'scatter', mode = 'markers',
hovertemplate = paste(
"Năm: %{text}<br>",
"ROE: %{x:.2f}%<br>",
"Giá Cổ phiếu: %{y:,.0f} VND"
)) %>%
# Thêm đường xu hướng tuyến tính
add_trace(type = 'scatter', mode = 'lines',
x = ~ROE_Nam,
y = fitted(lm(Gia_DongCua_CuoiNam ~ ROE_Nam, data = p12_data)),
name = "Đường xu hướng",
hoverinfo = 'none') %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 12: Mối quan hệ ROE vs. Giá Cổ phiếu (2014-2024)",
xaxis = list(title = "ROE (%)"),
yaxis = list(title = "Giá Đóng cửa Cuối năm (VND)"),
showlegend = FALSE
)
# 3. Hiển thị biểu đồ
p12Nhận xét Biểu đồ 12: Mối quan hệ ROE vs. Giá Cổ phiếu
Biểu đồ này cho thấy một mối quan hệ còn yếu hơn so với Biểu đồ 11.
Tương quan yếu: Đường xu hướng (màu cam) gần như
phẳng, trực quan hóa kết quả tương quan rất yếu
(cor_roe_gia = 0.276) từ Mục 2.4.4.
Không có quan hệ rõ ràng: Các điểm dữ liệu nằm rải rác mà không có một quy luật rõ ràng.
Năm có ROE cao nhất (2014, ~37%) lại không có giá
cao nhất (chỉ ~34k VND).
Ngược lại, năm có giá cao nhất (2022, ~70k VND) chỉ có
ROE ở mức khá ( ~24%).
Cụm ROE gần 0% (2015-2019) có mức giá trải dài từ
18k đến 58k.
Kết luận: Biểu đồ này khẳng định mạnh mẽ rằng thị trường không định giá cổ phiếu GAS dựa trên hiệu quả sinh lời (ROE) trong năm đó. Việc ROE cao hay thấp không phải là yếu tố chính dẫn dắt giá cổ phiếu.
13. Biểu đồ Phân tán: Tổng Tài sản vs. Vốn hóa Thị trường
# 1. Chuẩn bị dữ liệu: LỌC OUTLIER 2019 và tính Tỷ VND
p13_data <- GAS_data_final %>%
filter(TongTaiSan > 1e12) %>% # Lọc bỏ outlier 621 tỷ
mutate(
TTS_Ty = TongTaiSan / 1e9, # Đơn vị Tỷ VND
# VonHoa_TyVND đã được tính ở 2.4.5
)
# 2. Vẽ biểu đồ plotly (p13)
p13 <- plot_ly(data = p13_data,
x = ~TTS_Ty, # Trục X: Tổng Tài Sản
y = ~VonHoa_TyVND, # Trục Y: Vốn hóa
text = ~Nam, # Hiển thị 'Năm' khi hover
type = 'scatter', mode = 'markers',
hovertemplate = paste(
"Năm: %{text}<br>",
"Tổng Tài sản: %{x:,.0f} Tỷ VND<br>",
"Vốn hóa: %{y:,.0f} Tỷ VND"
)) %>%
# Thêm đường xu hướng tuyến tính
add_trace(type = 'scatter', mode = 'lines',
x = ~TTS_Ty,
y = fitted(lm(VonHoa_TyVND ~ TTS_Ty, data = p13_data)),
name = "Đường xu hướng",
hoverinfo = 'none') %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 13: Tổng Tài sản vs. Vốn hóa (Đã lọc Outlier)",
xaxis = list(title = "Tổng Tài sản (Tỷ VND)"),
yaxis = list(title = "Vốn hóa Thị trường (Tỷ VND)"),
showlegend = FALSE
)
# 3. Hiển thị biểu đồ
p13Nhận xét Biểu đồ 13: Tổng Tài sản vs. Vốn hóa
(Lưu ý: Biểu đồ này đã lọc bỏ outlier 2019, phân tích trên 10 năm).
Tương quan tuyến tính rất mạnh: Đây là phát hiện quan trọng nhất. Trái ngược với Biểu đồ 11 và 12, các điểm dữ liệu (các năm) trong biểu đồ này bám rất sát vào đường xu hướng tuyến tính.
Quy mô quyết định giá trị: Đường xu hướng dốc
lên mạnh mẽ, cho thấy một mối quan hệ gần như 1:1. Khi
Tổng Tài sản (trục X) tăng lên,
Vốn hóa Thị trường (trục Y) tăng lên một cách tương
ứng.
Kết luận (Kết hợp 11 & 12): Kết quả này giải
đáp cho các biểu đồ trước. Thị trường dường như định giá GAS không phải
dựa trên yếu tố nội tại (LNST hay ROE) mà dựa trên quy mô
(Tổng Tài sản). Đây là đặc điểm định giá thường thấy ở các
công ty Blue-chip (chỉ các công ty lớn, uy tín, đầu ngành, có tài chính
vững mạnh), nơi quy mô tài sản được xem là yếu tố bảo chứng cho giá
trị.
14. Biểu đồ Đường động: Xu hướng Vốn hóa Thị trường vs. Lợi nhuận
# 1. Chuẩn bị dữ liệu: Chuyển LNST sang Tỷ VND
p14_data <- GAS_data_final %>%
mutate(
LNST_Ty = LoiNhuanSauThue / 1e9
# VonHoa_TyVND đã có
)
# 2. Định nghĩa trục Y thứ 2 (cho Lợi nhuận)
y2_p14 <- list(
overlaying = "y",
side = "right",
title = "Lợi nhuận (Tỷ VND)",
showgrid = FALSE
)
# 3. Vẽ biểu đồ plotly (p14)
p14 <- plot_ly(data = p14_data, x = ~Nam,
hovertemplate = paste(
"Năm: %{x}<br>",
"%{yaxis.title.text}: %{y:,.0f} Tỷ VND"
)) %>%
# Thêm đường Vốn hóa (sử dụng trục y1)
add_lines(y = ~VonHoa_TyVND, name = "Vốn hóa (Trục trái)", yaxis = "y1") %>%
# Thêm đường Lợi nhuận (sử dụng trục y2)
add_lines(y = ~LNST_Ty, name = "Lợi Nhuận (Trục phải)", yaxis = "y2") %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 14: Xu hướng Vốn hóa Thị trường và Lợi nhuận (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Vốn hóa (Tỷ VND)"),
yaxis2 = y2_p14, # Áp dụng trục y2
legend = list(x = 0.1, y = -0.2, orientation = 'h')
)
# 4. Hiển thị biểu đồ
p14Nhận xét Biểu đồ 14: Xu hướng Vốn hóa vs. Lợi nhuận
Biểu đồ này làm rõ hơn sự “lệch pha” giữa thị trường và lợi nhuận:
Giai đoạn 1 (2014-2015): Cùng pha: Cả Vốn hóa (xanh) và Lợi nhuận (cam) đều sụt giảm mạnh.
Giai đoạn 2 (2015-2019): Phân kỳ Lớn: Đây là
giai đoạn đáng chú ý nhất. Lợi nhuận (cam) gần như bằng 0
và đi ngang. Tuy nhiên, Vốn hóa (xanh) không sụp đổ về 0,
mà chỉ giảm về đáy rồi bắt đầu phục hồi nhẹ từ 2017, trước khi lợi nhuận
phục hồi.
Giai đoạn 3 (2020-2022): Cùng pha: Cả hai cùng phục hồi mạnh mẽ, đạt đỉnh 2022.
Giai đoạn 4 (2022-2024): Phân kỳ Lần 2:
Lợi nhuận (cam) đạt đỉnh 2022 và sụt giảm. Nhưng
Vốn hóa (xanh) vẫn tiếp tục tăng, đạt đỉnh mới vào
2023-2024.
Kết luận: Biểu đồ này khẳng định thị trường (Vốn hóa) có “tầm nhìn” riêng, không bám sát lợi nhuận ngắn hạn. Sự phân kỳ 2022-2024 cho thấy thị trường tin rằng mức lợi nhuận đỉnh 2022 chỉ là tạm thời (do giá dầu cao), và họ định giá công ty dựa trên tiềm năng dài hạn/quy mô tài sản (như Biểu đồ 13) nên vốn hóa vẫn tiếp tục tăng.
15. Biểu đồ Đường: Chỉ số P/E
# 1. Chuẩn bị dữ liệu:
p15_data <- GAS_data_final
# (P_E_CuoiNam đã được tính và xử lý NA/Inf ở 1.4.5)
# 2. Vẽ biểu đồ plotly (p15)
p15 <- plot_ly(data = p15_data, x = ~Nam, y = ~P_E_CuoiNam,
type = 'scatter', mode = 'lines+markers', # Cả đường và điểm
name = "P/E Cuối năm",
hovertemplate = paste(
"Năm: %{x}<br>",
"P/E: %{y:.2f} (lần)"
)) %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 15: Định giá P/E (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Chỉ số P/E (Lần)")
)
# 3. Hiển thị biểu đồ
p15Nhận xét Biểu đồ 15: Định giá P/E
Biểu đồ này cho thấy sự thay đổi trong kỳ vọng của thị trường:
Giai đoạn 1 (2014-2016): Định giá rẻ: P/E ở mức rất thấp, chỉ ~4-5 lần. Điều này cho thấy thị trường bi quan, đánh giá lợi nhuận 2014 là không bền vững và đang chiết khấu (discount) mạnh (thực tế đã đúng khi LN sụp đổ 2015-2016).
Giai đoạn 2 (2017-2021): Tăng kỳ vọng: P/E tăng mạnh từ ~5 (2016) lên đỉnh ~15 (2021). Giai đoạn này, lợi nhuận vẫn còn thấp (trừ 2020-2021), nhưng thị trường đã trả giá cao hơn cho mỗi đồng lợi nhuận, cho thấy sự kỳ vọng vào sự phục hồi.
Giai đoạn 3 (2022): “Đỉnh Lợi nhuận”: P/E giảm mạnh xuống ~9. Đây là một tín hiệu kinh điển: Khi lợi nhuận đạt đỉnh (LNST 2022 cao nhất lịch sử), thị trường nhận định đây là đỉnh chu kỳ và không bền vững, do đó P/E bị co lại (giảm).
Kết luận: P/E của GAS rất biến động, phản ánh sự
thay đổi trong kỳ vọng của nhà đầu tư. Mức trung bình
pe_mean = 9.93 (Mục 2.4.5) là một con số hợp lý cho một
doanh nghiệp chu kỳ như GAS.
Giới thiệu:
Nhóm biểu đồ cuối cùng này đi sâu vào “chất lượng” của lợi nhuận và kiểm tra lại các giả định về phân phối dữ liệu.
Phân tích Chất lượng Lợi nhuận (CFO vs. LNST):
Từ Mục 2.4.5, chúng ta có một phát hiện quan trọng:
cash_conv_mean (Tỷ lệ CFO/LNST trung bình) là
22.16, trong khi cash_conv_median (trung
vị) chỉ là 1.19.
Điều này 100% khẳng định sự tồn tại của ít nhất một năm outlier nghiêm trọng (năm có LNST rất thấp nhưng CFO rất cao, khiến tỷ lệ này tăng vọt).
Biểu đồ 16 sẽ so sánh xu hướng của Dòng tiền HĐKD (CFO) và Lợi nhuận (LNST) trên hai trục Y.
Biểu đồ 17 (quan trọng nhất) sẽ vẽ Tỷ lệ
CFO/LNST. Bắt buộc phải lọc bỏ (filter) các giá trị outlier (ví
dụ: Tỷ lệ > 10) để biểu đồ có ý nghĩa, nếu không sẽ chỉ
thấy một cột outlier khổng lồ và 10 cột còn lại bằng 0.
Phân tích Phân phối (Violin, Density):
Biểu đồ 18 (Violin plot) là phiên bản nâng cao của Boxplot (Biểu đồ 9, Mục 2.4.2). Nó không chỉ cho thấy các mức phân vị (Q1, Q2, Q3) mà còn cho thấy “hình dạng” phân phối (dày ở đâu, mỏng ở đâu). Ta kỳ vọng sẽ thấy nó “dày” ở hai cụm: một cụm gần 0% và một cụm quanh 15-20%.
Biểu đồ 19 (Density plot) là phiên bản nâng cao
của Histogram (Biểu đồ 10, Mục 2.4.2). Ta bắt buộc phải lọc bỏ
outlier 4182.9% (năm 2017) để xem hình dạng phân phối thực
sự của 10 năm còn lại.
Trực quan hóa Tương quan (Heatmap):
ggplot2) của corrplot (Biểu đồ 17, Mục 2.4.4).
Nó sẽ trực quan hóa cor_matrix (đã lọc outlier 2019) bằng
màu sắc.Trực quan hóa và Nhận xét
16. Biểu đồ Đường: So sánh Dòng tiền HĐKD (CFO) vs. Lợi nhuận (LNST)
# 1. Chuẩn bị dữ liệu: Chuyển sang Tỷ VND
p16_data <- GAS_data_final %>%
mutate(
LNST_Ty = LoiNhuanSauThue / 1e9, # Lợi nhuận (Tỷ VND)
CFO_Ty = CFO / 1e9 # Dòng tiền HĐKD (Tỷ VND)
)
# 2. Định nghĩa trục Y thứ 2 (cho Lợi nhuận)
y2_p16 <- list(
overlaying = "y", # Đè trục y2 lên trục y1
side = "right", # Đặt ở bên phải
title = "Lợi nhuận (Tỷ VND)", # Tiêu đề trục
showgrid = FALSE # Ẩn lưới
)
# 3. Vẽ biểu đồ plotly (p16)
p16 <- plot_ly(data = p16_data, x = ~Nam,
# Định nghĩa tooltip (hover)
hovertemplate = paste(
"Năm: %{x}<br>",
"%{yaxis.title.text}: %{y:,.0f} Tỷ VND"
)) %>%
# Thêm đường CFO (sử dụng trục y1 mặc định)
add_lines(y = ~CFO_Ty, name = "CFO - Dòng tiền HĐKD (Trái)", yaxis = "y1") %>%
# Thêm đường Lợi nhuận (sử dụng trục y2)
add_lines(y = ~LNST_Ty, name = "LNST - Lợi nhuận Sổ sách (Phải)", yaxis = "y2") %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 16: Dòng tiền HĐKD (CFO) vs. Lợi nhuận (LNST) (2014-2024)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Dòng tiền (Tỷ VND)"),
yaxis2 = y2_p16, # Áp dụng trục y2
legend = list(x = 0.1, y = -0.2, orientation = 'h') # Đặt chú thích bên dưới
)
# 4. Hiển thị biểu đồ
p16Nhận xét Biểu đồ 16: Dòng tiền HĐKD (CFO) vs. Lợi nhuận (LNST)
Biểu đồ này cho thấy mối quan hệ tương quan nhưng cũng đầy biến động giữa dòng tiền thực tế và lợi nhuận sổ sách:
Tương quan thuận: Nhìn chung, hai đường
CFO (xanh) và LNST (cam) di chuyển cùng pha:
cùng sụt giảm mạnh 2014-2016 và cùng đạt đỉnh 2022.
Chất lượng tiền tốt trong khủng hoảng: Điểm đáng
chú ý là trong suốt giai đoạn khủng hoảng 2015-2019, LNST
(cam) gần như bằng 0, nhưng CFO (xanh) vẫn duy trì ở mức
dương (đỉnh điểm là 2017, CFO đạt ~14k tỷ trong khi LNST bằng 0). Điều
này cho thấy khả năng thu tiền của GAS vẫn rất tốt ngay cả khi lợi nhuận
kế toán không có, chủ yếu do thu được các khoản phải thu cũ.
Giai đoạn phục hồi (2020-2024): Trong giai đoạn
này, hai đường bám sát nhau hơn, LNST (cam) tăng mạnh,
nhưng CFO (xanh) có xu hướng thấp hơn một chút, cho thấy
lợi nhuận có thể đang nằm một phần ở các khoản phải thu mới.
Kết luận: CFO biến động còn mạnh hơn cả LNST, nhưng việc CFO duy trì mức dương cao trong giai đoạn 2015-2019 là một dấu hiệu tích cực về khả năng quản trị dòng tiền.
17. Biểu đồ Cột: Tỷ lệ Chuyển đổi Tiền mặt (CFO/LNST)
# 1. Chuẩn bị dữ liệu: LỌC OUTLIER NGHIÊM TRỌNG
# Từ 1.4.5, ta biết Mean (22.16) và Median (1.19) lệch nhau rất lớn
# Điều này có nghĩa là có outlier. Ta sẽ lọc bỏ các giá trị quá cao (>10)
# và quá thấp (< -10) để biểu đồ có ý nghĩa
p17_data <- GAS_data_final %>%
filter(TyLe_CFO_Tren_LNST < 10 & TyLe_CFO_Tren_LNST > -10) %>%
mutate(
# Tạo biến màu sắc (Chất lượng Tốt/Xấu)
# Tốt: Tỷ lệ > 1 (Tiền > Lợi nhuận)
color_cash = ifelse(TyLe_CFO_Tren_LNST >= 1, "Tốt (>= 1)", "Kém (< 1)")
)
# 2. Định nghĩa màu
colors_cash <- c("Tốt (>= 1)" = "#1f77b4", "Kém (< 1)" = "#d62728") # Xanh / Đỏ
# 3. Vẽ biểu đồ plotly (p17)
p17 <- plot_ly(data = p17_data, x = ~Nam, y = ~TyLe_CFO_Tren_LNST,
color = ~color_cash, # Tô màu theo biến color_cash
colors = colors_cash, # Áp dụng màu Xanh/Đỏ
type = "bar",
hovertemplate = paste(
"Năm: %{x}<br>",
"Tỷ lệ CFO/LNST: %{y:.2f}"
)) %>%
# Thêm đường tham chiếu (Tỷ lệ = 1)
add_lines(y = 1, name = "Ngưỡng 100% (CFO = LNST)",
line = list(color = 'black', dash = 'dash'),
hoverinfo = 'none') %>%
# Áp dụng layout
plotly::layout(
title = "Biểu đồ 17: Tỷ lệ Chuyển đổi Tiền mặt (Đã lọc Outlier)",
xaxis = list(title = "Năm"),
yaxis = list(title = "Tỷ lệ (CFO / LNST)")
)
# 4. Hiển thị biểu đồ
p17Nhận xét Biểu đồ 17: Tỷ lệ Chuyển đổi Tiền mặt
Biểu đồ này trực quan hóa chất lượng lợi nhuận qua các năm (sau khi đã lọc bỏ các năm 2015-2019, nơi LNST quá thấp khiến tỷ lệ này vô nghĩa):
Kết quả lọc: Biểu đồ chỉ còn lại các năm có lợi nhuận đáng kể (2014, 2020-2024).
Chất lượng lợi nhuận “Tốt” (Cột xanh): Các năm
2014 (Tỷ lệ ~1.19) và 2023 (Tỷ lệ ~1.19) có chất lượng lợi nhuận tuyệt
vời, vượt ngưỡng 100% (đường nét đứt). Điều này có nghĩa là 1 đồng LNST
tạo ra 1.19 đồng tiền mặt. Đây chính là giá trị median
(trung vị) 1.19 mà ta tìm thấy ở Mục 2.4.5.
Chất lượng “Khá” (Cột đỏ): Các năm 2020, 2021, 2022, 2024 có tỷ lệ < 1 (trong khoảng 0.85 - 0.95). Đây vẫn là mức chấp nhận được, cho thấy phần lớn lợi nhuận (85-95%) được hỗ trợ bằng tiền mặt, chỉ một phần nhỏ nằm ở các khoản phải thu.
Kết luận: Biểu đồ này khẳng định
cash_conv_median = 1.19 là một chỉ số đáng tin cậy. Chất
lượng lợi nhuận của GAS trong các năm kinh doanh bình thường là rất cao
(thường > 0.85), và trong các năm điển hình (trung vị) là xuất sắc
(> 1).
18. Biểu đồ Violin kết hợp Boxplot: Phân phối của ROE (%)
# 1. Chuẩn bị dữ liệu: Không cần
p18_data <- GAS_data_final
# 2. Vẽ biểu đồ ggplot (p18)
# (Sử dụng ggplot vì đây là biểu đồ thống kê tĩnh)
p18 <- ggplot(data = p18_data, aes(x = "ROE", y = ROE_Nam)) +
# Thêm biểu đồ Violin (cho thấy hình dạng phân phối)
geom_violin(aes(fill = "ROE"), trim = FALSE) +
# Thêm biểu đồ Boxplot (cho thấy Q1, Q2, Q3)
geom_boxplot(width = 0.1, fill = "white") +
# Thêm các điểm dữ liệu (jitter để tránh chồng chéo)
geom_jitter(width = 0.05, height = 0, alpha = 0.5) +
# Đặt tiêu đề và nhãn trục
labs(
title = "Biểu đồ 18: Phân phối của ROE (2014-2024)",
x = "Chỉ số",
y = "ROE (%)",
caption = "Phân tích 11 năm (Bao gồm cả outlier 2019)"
) +
theme_minimal() + # Sử dụng theme tối giản
theme(legend.position = "none") # Ẩn chú thích
# 3. Hiển thị biểu đồ
p18Nhận xét Biểu đồ 18: Phân phối của ROE
Biểu đồ Violin này là một phiên bản nâng cao của boxplot (ở 2.4.2), cung cấp cái nhìn sâu sắc về hình dạng phân phối của ROE trong 11 năm:
Phân phối hai cực (Bimodal): Đặc điểm nổi bật nhất là hình dạng “con quay” (violin) bị “thắt” ở giữa và “phình” ra ở hai đầu.
Cực 1 (Đáy): Phần phình rộng ở đáy (ROE ~ 0%). Điều này cho thấy có một cụm dữ liệu lớn (5 năm khủng hoảng 2015-2019) tập trung dày đặc ở mức 0%.
Cực 2 (Đỉnh): Phần phình rộng thứ hai ở khu vực 15% - 25%. Đây là cụm 6 năm hoạt động hiệu quả (2014, 2020-2024).
Hộp Boxplot: Hộp boxplot (màu trắng) nằm lọt
thỏm trong “cực 2”, xác nhận rằng median (trung vị) nằm ở
~15.8%, và 75% số năm (Q3) có ROE dưới 17.3%.
Các chấm đó chính là 11 điểm dữ liệu (11 năm) thực tế
Cụm đáy (Khủng hoảng): thấy rõ 5 chấm dữ liệu (tương ứng 5 năm 2015, 2016, 2017, 2018, 2019) bị nén chặt và xếp chồng lên nhau ở mức gần 0%. Cụm chấm này chính là nguyên nhân tạo ra phần “phình” rộng ở đáy của biểu đồ violin.
Cụm đỉnh (Phục hồi): 5 chấm dữ liệu khác (tương ứng 2020, 2021, 2022, 2023, 2024) tụ lại ở cụm trên, trong khoảng 15% đến 25%. Cụm chấm này tạo ra phần “phình” thứ hai của violin và cũng là nơi chứa toàn bộ “hộp” boxplot (từ Q1 đến Q3).
Điểm biệt lập (Max): Quan trọng nhất, có một chấm đơn lẻ (năm 2014) nằm tách biệt ở đỉnh cao nhất, khoảng 37.5%. Đây chính là giá trị Max (đỉnh của râu boxplot), cho thấy năm hoạt động hoàng kim 2014 thực sự là một trường hợp đặc biệt, nằm xa hẳn so với cụm hoạt động hiệu quả (2020-2024).
Kết luận: Biểu đồ này trực quan hóa một cách hoàn hảo sự “phân cực” trong hiệu suất của GAS, GAS không có phân phối chuẩn, mà hoạt động ở hai ‘trạng thái’ rất rõ rệt. Doanh nghiệp này dường như chỉ hoạt động ở 2 trạng thái: “kém hiệu quả” (ROE ~ 0%) hoặc “hiệu quả cao” (ROE > 15%), chứ ít khi ở mức “trung bình” (khu vực 5-10% rất mỏng).
19. Biểu đồ Mật độ (Density plot): Phân phối Tăng trưởng Lợi nhuận (%)
# 1. Chuẩn bị dữ liệu: LỌC OUTLIER (4182.9%)
p19_data <- GAS_data_final %>%
filter(LoiNhuan_TangTruong_YoY < 4000) # Lọc bỏ năm 2017
# 2. Vẽ biểu đồ ggplot (p19)
p19 <- ggplot(data = p19_data, aes(x = LoiNhuan_TangTruong_YoY)) +
# Thêm biểu đồ mật độ (density plot)
geom_density(aes(fill = "Tăng trưởng LN"), alpha = 0.6) +
# Thêm 1 đường gạch tại giá trị 0
geom_vline(xintercept = 0, linetype = "dashed", color = "red") +
# Đặt tiêu đề và nhãn trục
labs(
title = "Biểu đồ 19: Phân phối Tăng trưởng LN (Đã lọc Outlier 2017)",
x = "% Tăng trưởng Lợi nhuận (YoY)",
y = "Mật độ (Density)",
caption = "Phân tích 10 năm (2015-2024, đã lọc 1 outlier)"
) +
theme_minimal() +
theme(legend.position = "none") # Ẩn chú thích
# 3. Hiển thị biểu đồ
p19Nhận xét Biểu đồ 19: Phân phối Tăng trưởng Lợi nhuận
(Lưu ý: Đã lọc bỏ 1 năm outlier 2017 để xem 10 năm còn lại).
Lệch trái: Biểu đồ mật độ cho thấy phân phối bị lệch về bên trái.
Đỉnh phân phối: Đỉnh cao nhất của đường mật độ
(nơi tập trung nhiều năm nhất) nằm ở khoảng -25% đến 0%. Điều này trực
quan hóa kết quả median_growth_ln là 0% (hoặc
-4.87% nếu lọc 2014) từ 1.4.2. Đường nét đứt màu đỏ (tại 0)
cho thấy phần lớn diện tích (xác suất) nằm ở vùng tăng trưởng
âm.
Đuôi dương: Có một “cụm” nhỏ hơn ở phía bên phải, quanh mức 50-70%, đại diện cho các năm phục hồi mạnh mẽ (như 2018, 2022).
Kết luận: Biểu đồ này khẳng định tăng trưởng lợi nhuận của GAS là không ổn định. Một năm điển hình có xu hướng sụt giảm nhẹ, nhưng cũng có một khả năng (nhỏ hơn) là tăng trưởng bùng nổ.
20. Biểu đồ Nhiệt (Heatmap): Ma trận Tương quan (Phiên bản ggplot)
# 1. Tải thư viện để "melt" (chuyển đổi) dữ liệu
library(reshape2)
# 2. Chuẩn bị dữ liệu:
# 2.1. Lấy dữ liệu đã lọc outlier (từ Mục 2.4.4)
data_for_cor_p20 <- GAS_data_final %>%
filter(TongTaiSan > 1e12) %>%
select(-Nam, -EPS, -SL_CoPhieu_LuuHanh, -CFO) # Bỏ các cột không cần thiết
# 2.2. Tính toán ma trận
cor_matrix_p20 <- cor(data_for_cor_p20)
# 2.3. "Melt" (chuyển từ ma trận sang dạng 3 cột: Var1, Var2, value)
melted_cor_matrix <- melt(cor_matrix_p20)
# 3. Vẽ biểu đồ ggplot (p20)
p20 <- ggplot(data = melted_cor_matrix, aes(x = Var1, y = Var2, fill = value)) +
# Sử dụng geom_tile để vẽ các ô vuông
geom_tile() +
# Thêm text giá trị vào giữa ô (làm tròn 2 chữ số)
geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
# Định nghĩa thang màu: Đỏ (Âm) - Trắng (0) - Xanh (Dương)
scale_fill_gradient2(low = "#d62728", high = "#1f77b4", mid = "white",
midpoint = 0, limit = c(-1,1), name = "Tương quan") +
# Xoay nhãn trục X 45 độ cho dễ đọc
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
# Đặt tiêu đề
labs(
title = "Biểu đồ 20: Ma trận Tương quan (Đã lọc Outlier)"
)
# 4. Hiển thị biểu đồ
p20Nhận xét Biểu đồ 20: Ma trận Tương quan (Heatmap)
Biểu đồ nhiệt này là phiên bản trực quan của ma trận ở Mục 2.4.4, nhưng đã bổ sung các biến mới:
Màu xanh đậm (Tương quan dương mạnh > 0.7):
Tái khẳng định các mối quan hệ về Quy mô: TongTaiSan
tương quan mạnh với VonChuSoHuu (0.97),
VonHoa_TyVND (0.83), và Gia_DongCua_CuoiNam
(0.83). Đây là phát hiện “Blue-chip” ở Mục 2.5.3.
Tái khẳng định quan hệ Lợi nhuận: LoiNhuanSauThue
tương quan mạnh với ROE_Nam (0.94), ROA_Nam
(0.95), và BienLoiNhuanRong_Nam (0.97).
Màu đỏ đậm (Tương quan âm mạnh < -0.7):
Phát hiện mới: TyLe_CFO_Tren_LNST
(Tỷ lệ chuyển đổi tiền) có tương quan âm rất mạnh với
LoiNhuanSauThue (-0.89), ROE_Nam (-0.83),
ROA_Nam (-0.88), và BienLoiNhuanRong_Nam
(-0.89).
Giải thích: Điều này nghe có vẻ lạ nhưng hoàn toàn hợp lý. Nó có nghĩa là: trong những năm LNST thấp (như 2015-2019, là các outlier của tỷ lệ này), Tỷ lệ CFO/LNST rất cao (vô cực). Ngược lại, trong những năm LNST cao (như 2014, 2022), Tỷ lệ CFO/LNST thấp hơn (chỉ ~ 1.19 hoặc 0.85). Biểu đồ này khẳng định lại kết quả của Biểu đồ 17.
Màu nhạt (Tương quan yếu):
Tái khẳng định: ROE_Nam (hiệu quả) có tương quan yếu
với Gia_DongCua_CuoiNam (0.28) và VonHoa_TyVND
(0.29).
Tái khẳng định: TySoNo_Tren_VCSH (đòn bẩy) có tương
quan yếu với hầu hết mọi thứ, xác nhận Biểu đồ 10.
Việc phân tích các yếu tố ảnh hưởng đến giá cổ phiếu, đặc biệt trong ngành năng lượng tại các thị trường mới nổi như Việt Nam, đã thu hút sự quan tâm của nhiều nhà nghiên cứu. Một số phát hiện chính từ các nghiên cứu trước bao gồm:
Vai trò của các Yếu tố Vĩ mô: Nhiều nghiên cứu (ví dụ: Nhu Quynh & Huong Linh, 2019; IOSR Journal, 2024) khẳng định các yếu tố vĩ mô như giá dầu thô thế giới, tỷ giá hối đoái, lãi suất, và lạm phát (CPI) có tác động mạnh mẽ đến giá cổ phiếu ngành năng lượng Việt Nam. Cụ thể, giá dầu thường có tác động cùng chiều (nghiên cứu của Scholar DLU, 2023) hoặc ngược chiều (nghiên cứu của Nguyet & Thao, 2013, trích dẫn trong IOSR Journal) tùy thuộc vào vị thế nhập/xuất khẩu ròng của doanh nghiệp và cả nền kinh tế. Sự biến động của các yếu tố vĩ mô này giải thích phần lớn tính chu kỳ và rủi ro cao của ngành.
Yếu tố Nội tại Doanh nghiệp: Bên cạnh các yếu tố vĩ mô, các yếu tố nội tại cũng đóng vai trò quan trọng:
Hiệu quả Sinh lời (EPS, ROA): Các nghiên cứu (ví
dụ: Scholar DLU, 2023; IOSR Journal, 2024; AB Academies, 2021) đều nhất
quán tìm thấy mối tương quan dương giữa Thu nhập trên mỗi cổ
phiếu (EPS) và Tỷ suất sinh lời trên tài sản
(ROA) với giá cổ phiếu. Điều này phù hợp với lý thuyết tài
chính cơ bản: doanh nghiệp làm ăn hiệu quả hơn thì giá cổ phiếu cao
hơn.
Quy mô Doanh nghiệp (SIZE): Yếu tố quy mô (thường đo bằng Logarit của Tổng Tài sản) cũng được xác định là có tác động dương đến giá cổ phiếu (Scholar DLU, 2023; IOSR Journal, 2024). Các công ty lớn hơn thường được thị trường định giá cao hơn.
Đòn bẩy Tài chính (DE - Debt/Equity): Kết quả về đòn bẩy không nhất quán. Nghiên cứu của Scholar DLU (2023) tìm thấy tác động ngược chiều (nợ cao, giá thấp hơn do rủi ro), trong khi nghiên cứu của IOSR Journal (2024) lại tìm thấy tác động cùng chiều (có thể do hiệu ứng lá chắn thuế hoặc tín hiệu về tiềm năng tăng trưởng).
EPS (và do đó là P/E) có ảnh hưởng đến giá, một số phân
tích (ví dụ: Yuanta Việt Nam, 2023; Investing.com VN, 2024 - dù cho
ngành ngân hàng) cho rằng chỉ số Giá trên Giá trị Sổ sách
(P/B - Price To Book Value) cũng là một yếu tố định giá
quan trọng, đặc biệt đối với các doanh nghiệp có tài sản lớn hoặc trong
giai đoạn thị trường bất định. P/B phản ánh giá thị trường đang trả cho
mỗi đồng vốn chủ sở hữu ghi trên sổ sách.Kết quả phân tích dữ liệu khám phá (EDA) trong Mục 2.4 và 2.5 cung cấp những bằng chứng thực nghiệm thú vị khi so sánh với các nghiên cứu trước:
Trái ngược với đa số nghiên cứu trước (khẳng định
EPS và ROA/ROE ảnh hưởng
dương đến giá), phân tích TRÊN lại tìm thấy mối tương quan khá
yếu giữa LoiNhuanSauThue (cor=0.50, Biểu đồ 11) và
đặc biệt là ROE_Nam (cor=0.28, Biểu đồ 12) với
Gia_DongCua_CuoiNam.
Lý giải: Sự khác biệt này có thể đến từ: (1) Đặc thù của GAS là một doanh nghiệp Nhà nước lớn, Blue-chip, khiến cách định giá khác biệt; (2) Giai đoạn phân tích (2014-2024) bao gồm nhiều năm khủng hoảng (LNST~0), làm “nhiễu” mối quan hệ này; (3) Các yếu tố vĩ mô (giá dầu) có thể đã lấn át tác động của hiệu quả nội tại trong giai đoạn này.
Phát hiện quan trọng nhất là mối tương quan cực kỳ mạnh
(cor=0.83) giữa TongTaiSan và
Gia_DongCua_CuoiNam/VonHoa_TyVND (Biểu đồ
13).
Điều này hoàn toàn ủng hộ các nghiên cứu trước về tác
động dương của Quy mô (SIZE) lên giá cổ phiếu (Scholar DLU,
2023; IOSR Journal, 2024) và cũng gián tiếp ủng hộ các phân
tích nhấn mạnh vai trò của P/B (Giá trị Sổ sách - Book
Value, liên quan đến Tài sản và Vốn chủ) trong định giá các doanh nghiệp
lớn, ổn định tại Việt Nam. Kết quả của chúng ta cho thấy thị trường định
giá GAS như một cổ phiếu “Blue-chip” dựa trên quy mô tài sản.
Phân tích biểu đồ 10, Ma trận Tương quan 2.4.4 tìm thấy mối tương
quan rất yếu giữa TySoNo_Tren_VCSH và
ROE_Nam (cor=0.15). Điều này dường như không ủng hộ mạnh mẽ
cả hai luồng ý kiến (âm hoặc dương) từ các nghiên cứu trước.
Lý giải: Có thể là do GAS luôn duy trì đòn bẩy ở
mức rất thấp (mean=0.36), khiến cho sự thay đổi nhỏ trong
tỷ lệ nợ không đủ để tạo ra tác động đáng kể lên ROE.
median CFO/LNST
= 1.19, Biểu đồ 17) là một điểm cộng quan trọng cho GAS, cho thấy lợi
nhuận kế toán được chuyển đổi hiệu quả thành tiền mặt. Đây là một yếu tố
thường được các nhà đầu tư giá trị quan tâm.Kết luận thảo luận: Phân tích EDA cung cấp những góc nhìn thực tế và sâu sắc về GAS. Mặc dù có những điểm tương đồng với các nghiên cứu trước (tính chu kỳ, vai trò của quy mô), phát hiện về mối quan hệ yếu giữa hiệu quả sinh lời và giá cổ phiếu là một điểm khác biệt quan trọng, nhấn mạnh đặc thù định giá của một cổ phiếu Blue-chip như GAS trên thị trường Việt Nam.
GAS thể hiện rõ đặc điểm của một cổ phiếu “Blue-chip”: quy mô tài
sản lớn, cấu trúc tài chính cực kỳ an toàn (đòn bẩy thấp,
mean_tsn_vcsh = 0.36), và tăng trưởng quy mô chủ yếu dựa
vào vốn chủ sở hữu.
Tuy nhiên, hiệu quả hoạt động kinh doanh (Lợi nhuận, ROE, Biên LN ròng) lại mang tính chu kỳ rất cao, biến động mạnh mẽ và phụ thuộc lớn vào các yếu tố vĩ mô (như giá dầu). Phân tích phân phối cho thấy ROE hoạt động ở hai trạng thái rõ rệt: “kém hiệu quả” (ROE ~0%) trong giai đoạn 2015-2019 và “hiệu quả cao” (ROE > 15%) trong giai đoạn còn lại.
Mặc dù lợi nhuận biến động, chất lượng lợi nhuận của GAS (khi
hoạt động hiệu quả) là rất cao, thể hiện qua Tỷ lệ Chuyển đổi Tiền mặt
trung vị (cash_conv_median) đạt 1.19, cho thấy khả năng
chuyển đổi lợi nhuận thành dòng tiền thực tế tốt.
Phát hiện quan trọng nhất và có phần khác biệt so với một số
nghiên cứu trước: Thị trường chứng khoán Việt Nam trong giai đoạn
2014-2024 dường như không định giá cổ phiếu GAS dựa trên hiệu
quả sinh lời (ROE, cor=0.28) hay lợi nhuận ngắn hạn
(LNST, cor=0.50).
Thay vào đó, định giá thị trường (Giá cổ phiếu, Vốn hóa) lại có
mối tương quan tuyến tính rất mạnh với Quy mô Tổng Tài
sản (cor=0.83). Điều này ủng hộ các nghiên cứu về
vai trò của quy mô và phù hợp với hành vi định giá cổ phiếu Blue-chip,
nơi quy mô tài sản được xem là yếu tố bảo chứng cho giá trị dài hạn, bất
chấp biến động lợi nhuận ngắn hạn. Sự phân kỳ giữa Vốn hóa và Lợi nhuận
(Biểu đồ 14) càng củng cố nhận định này.
Vấn đề chất lượng dữ liệu: Phân tích đã phát
hiện và xử lý một điểm dữ liệu ngoại lai (outlier) nghiêm trọng trong
báo cáo tài chính năm 2019, nơi TongTaiSan được ghi nhận ở
mức phi lý (621 tỷ VND). Việc lọc bỏ điểm dữ liệu này là cần thiết để
đảm bảo tính chính xác của các phân tích liên quan đến cấu trúc vốn và
tương quan.
Phạm vi phân tích: Nghiên cứu này chỉ tập trung vào dữ liệu tài chính nội tại và giá cổ phiếu. Việc kết hợp phân tích các yếu tố vĩ mô (giá dầu, tỷ giá, lãi suất) hoặc các yếu tố định tính (chính sách, dự án) có thể cung cấp bức tranh đầy đủ hơn.
Kết luận: GAS là một cổ phiếu Blue-chip điển hình trên thị trường Việt Nam: an toàn về mặt tài chính nhờ quy mô và cấu trúc vốn vững chắc, nhưng hiệu quả kinh doanh lại biến động mạnh theo chu kỳ ngành. Thị trường nhận thức rõ điều này và thể hiện qua việc định giá cổ phiếu dựa trên quy mô tài sản và tiềm năng dài hạn, thay vì phản ứng thái quá với lợi nhuận ngắn hạn. Chất lượng lợi nhuận cao (khả năng tạo tiền tốt) là một điểm cộng quan trọng.
Đề xuất:
Đối với Nhà đầu tư: GAS phù hợp với các nhà đầu tư dài hạn, tìm kiếm sự ổn định tương đối về giá trị tài sản và tiềm năng nhận cổ tức đều đặn (nhờ dòng tiền tốt). Tuy nhiên, nhà đầu tư cần chấp nhận sự biến động mạnh của lợi nhuận và hiệu quả sinh lời theo chu kỳ kinh tế và giá năng lượng thế giới. Việc mua vào nên cân nhắc thực hiện khi định giá P/E hoặc P/B (nếu tính thêm) ở mức thấp hơn trung bình lịch sử hoặc khi có dấu hiệu bắt đầu một chu kỳ phục hồi mới của ngành.
Đối với Nghiên cứu Tương lai: Các nghiên cứu tiếp theo có thể mở rộng mô hình phân tích bằng cách đưa vào các biến số vĩ mô (giá dầu, GDP, lạm phát, lãi suất) để lượng hóa tác động của các yếu tố này lên hiệu quả kinh doanh và giá cổ phiếu của GAS, hoặc so sánh mô hình định giá của GAS với các doanh nghiệp cùng ngành trong khu vực.