Trong bối cảnh nền kinh tế toàn cầu ngày càng phụ thuộc vào dữ liệu, việc phân tích và khai thác dữ liệu tài chính trở thành một kỹ năng không thể thiếu đối với các nhà phân tích và nhà đầu tư. Ngôn ngữ R được xem là một trong những công cụ mạnh mẽ nhất cho phân tích dữ liệu, nhờ khả năng xử lý linh hoạt, tích hợp thống kê, và hỗ trợ trực quan hóa ở cấp độ chuyên sâu.
Đề tài của tiểu luận này là:
“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ằng ngôn ngữ R”
Bộ dữ liệu được sử dụng trong tiểu luận có tên “400K NYSE Random Investments + Financial Ratios”, bao gồm 405.258 quan sát và 25 biến. Dữ liệu mô phỏng các khoản đầu tư ngẫu nhiên trên sàn NYSE (New York Stock Exchange), kết hợp với các chỉ tiêu tài chính (financial ratios) của các công ty. Bộ dữ liệu giúp mô phỏng hoạt động đầu tư, đo lường hiệu quả sinh lời, và đánh giá rủi ro theo các chỉ số định lượng.
Mục tiêu chính của việc phân tích bộ dữ liệu này là áp dụng tuần tự các bước trong Roadmap R for Data Analysis, từ thao tác dữ liệu, trực quan hoá, đến phân tích thống kê và xây dựng mô hình, qua đó rèn luyện kỹ năng xử lý và diễn giải dữ liệu tài chính bằng ngôn ngữ R Markdown. Và kết quả phân tích giúp mô phỏng chiến lược đầu tư và đánh giá hiệu quả thị trường cổ phiếu Mỹ.
Tên bộ dữ liệu: 400K NYSE Random Investments + Financial Ratios Dataset.
Nguồn dữ liệu: dữ liệu giả lập dựa trên các chỉ số, giá trị đầu tư và thông tin tài chính của doanh nghiệp niêm yết tại sàn NYSE trên Kaggle.
Đặc điểm:
Số lượng quan sát: 405.208 dòng
Số lượng biến: 25 biến
Dạng dữ liệu: hỗn hợp giữa định tính (factor) và định lượng (numeric)
Khoảng thời gian: các giao dịch diễn ra trong giai đoạn từ 2013 đến 2018
Một số biến tiêu biểu:
Bộ dữ liệu bao gồm 25 biến phản ánh thông tin về công ty, giao dịch đầu tư và các chỉ tiêu tài chính. Dưới đây là tóm tắt một số nhóm biến chính:
Bài tiểu luận được chia thành 10 chương tương ứng với 10 node trong Roadmap “R for Data Analysis”, bao gồm:
R Fundamentals – Làm quen cú pháp, cấu trúc dữ liệu, và thao tác cơ bản.
Data Manipulation – Biến đổi, gộp nhóm, lọc và xử lý dữ liệu.
Data Visualization – Trực quan hóa bằng biểu đồ cơ bản và ggplot2.
Statistical Analysis – Phân tích thống kê mô tả và suy luận.
Machine Learning – Xây dựng và đánh giá mô hình học máy cơ bản.
Working with Big Data – Ứng dụng data.table và SparkR.
Reporting and Communication – Tạo báo cáo và dashboard bằng R Markdown.
Advanced R Programming – Viết hàm, vòng lặp, xử lý logic nâng cao.
Specialized Packages and Techniques – Áp dụng các gói mở rộng (lubridate, stringr, caret, …).
Case Studies and Applications – Phân tích tình huống thực tế từ bộ dữ liệu NYSE.
Quá trình tiền xử lý sơ bộ (chi tiết được trình bày tại chương 2 và chương 3) đã bao gồm việc đọc dữ liệu, kiểm tra trùng lặp và chuyển đổi các biến thời gian sang định dạng Date và các biến phân loại sang định dạng factor.
| Name | nyse |
| Number of rows | 405258 |
| Number of columns | 25 |
| _______________________ | |
| Column type frequency: | |
| factor | 5 |
| numeric | 20 |
| ________________________ | |
| Group variables | None |
Variable type: factor
| skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
|---|---|---|---|---|---|
| company | 0 | 1 | FALSE | 27 | AMZ: 16270, M: 16161, PG: 16103, BAC: 16101 |
| sector | 0 | 1 | FALSE | 5 | RET: 96269, TEC: 92401, BAN: 84757, AUT: 79836 |
| date_BUY_fix | 0 | 1 | FALSE | 1248 | 201: 590, 201: 587, 201: 573, 201: 562 |
| date_SELL_fix | 0 | 1 | FALSE | 1729 | 201: 571, 201: 554, 201: 546, 201: 545 |
| investment | 0 | 1 | FALSE | 2 | BAD: 264440, GOO: 140818 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| X | 0 | 1 | 249935.85 | 144239.75 | 0.00 | 125063.25 | 249937.50 | 374754.75 | 499999.00 | ▇▇▇▇▇ |
| horizon..days. | 0 | 1 | 187.08 | 210.70 | 1.00 | 15.00 | 90.00 | 300.00 | 720.00 | ▇▂▂▁▁ |
| amount | 0 | 1 | 8108.47 | 12774.43 | 50.00 | 400.00 | 2000.00 | 10000.00 | 50000.00 | ▇▁▁▁▁ |
| price_BUY | 0 | 1 | 105.26 | 217.18 | 7.14 | 28.30 | 46.22 | 76.29 | 2039.51 | ▇▁▁▁▁ |
| price_SELL | 0 | 1 | 116.73 | 250.14 | 4.01 | 28.39 | 48.02 | 81.65 | 3450.96 | ▇▁▁▁▁ |
| Volatility_Buy | 0 | 1 | 0.25 | 0.10 | 0.09 | 0.19 | 0.23 | 0.31 | 0.70 | ▇▇▃▁▁ |
| Volatility_sell | 0 | 1 | 0.26 | 0.10 | 0.09 | 0.19 | 0.24 | 0.32 | 0.92 | ▇▅▁▁▁ |
| Sharpe.Ratio | 0 | 1 | 0.25 | 0.10 | 0.09 | 0.19 | 0.23 | 0.31 | 0.70 | ▇▇▃▁▁ |
| expected_return..yearly. | 0 | 1 | 0.07 | 0.14 | -0.28 | 0.00 | 0.01 | 0.08 | 1.02 | ▁▇▁▁▁ |
| inflation | 0 | 1 | 0.58 | 1.04 | -0.50 | -0.20 | -0.15 | 1.68 | 1.96 | ▇▁▁▁▅ |
| nominal_return | 0 | 1 | 0.07 | 0.30 | -0.87 | -0.03 | 0.01 | 0.11 | 8.85 | ▇▁▁▁▁ |
| ESG_ranking | 0 | 1 | 22.57 | 6.51 | 12.00 | 16.30 | 25.10 | 27.90 | 31.60 | ▇▅▂▇▇ |
| PE_ratio | 0 | 1 | 30.33 | 84.74 | 0.00 | 9.82 | 13.71 | 23.49 | 1116.57 | ▇▁▁▁▁ |
| EPS_ratio | 0 | 1 | 3.44 | 4.39 | -6.56 | 1.46 | 2.96 | 4.56 | 29.87 | ▂▇▁▁▁ |
| PS_ratio | 0 | 1 | 2.72 | 3.60 | 0.16 | 0.47 | 1.71 | 3.18 | 24.49 | ▇▁▁▁▁ |
| PB_ratio | 0 | 1 | 4.69 | 5.91 | 0.00 | 1.22 | 3.05 | 5.23 | 47.62 | ▇▁▁▁▁ |
| NetProfitMargin_ratio | 0 | 1 | 9.21 | 10.41 | -24.63 | 2.62 | 7.70 | 15.77 | 62.00 | ▁▇▆▁▁ |
| current_ratio | 0 | 1 | 2.17 | 2.56 | 0.61 | 0.98 | 1.22 | 1.79 | 13.56 | ▇▁▁▁▁ |
| roa_ratio | 0 | 1 | 5.60 | 5.98 | -12.99 | 1.74 | 5.71 | 7.99 | 38.13 | ▁▇▃▁▁ |
| roe_ratio | 0 | 1 | 15.64 | 17.48 | -99.49 | 8.83 | 16.10 | 26.03 | 57.25 | ▁▁▁▇▃ |
## X horizon..days. amount price_BUY
## Min. : 0 Min. : 1.0 Min. : 50 Min. : 7.137
## 1st Qu.:125063 1st Qu.: 15.0 1st Qu.: 400 1st Qu.: 28.303
## Median :249938 Median : 90.0 Median : 2000 Median : 46.218
## Mean :249936 Mean :187.1 Mean : 8108 Mean : 105.256
## 3rd Qu.:374755 3rd Qu.:300.0 3rd Qu.:10000 3rd Qu.: 76.289
## Max. :499999 Max. :720.0 Max. :50000 Max. :2039.510
## price_SELL Volatility_Buy Volatility_sell Sharpe.Ratio
## Min. : 4.01 Min. :0.09042 Min. :0.09042 Min. :0.09042
## 1st Qu.: 28.39 1st Qu.:0.18536 1st Qu.:0.18900 1st Qu.:0.18536
## Median : 48.02 Median :0.23220 Median :0.23813 Median :0.23220
## Mean : 116.73 Mean :0.25414 Mean :0.25969 Mean :0.25414
## 3rd Qu.: 81.65 3rd Qu.:0.30673 3rd Qu.:0.31648 3rd Qu.:0.30673
## Max. :3450.96 Max. :0.69756 Max. :0.92253 Max. :0.69756
## expected_return..yearly. inflation nominal_return ESG_ranking
## Min. :-0.278002 Min. :-0.5000 Min. :-0.87222 Min. :12.00
## 1st Qu.: 0.001059 1st Qu.:-0.2000 1st Qu.:-0.02837 1st Qu.:16.30
## Median : 0.012843 Median :-0.1500 Median : 0.01410 Median :25.10
## Mean : 0.070825 Mean : 0.5777 Mean : 0.07102 Mean :22.57
## 3rd Qu.: 0.082635 3rd Qu.: 1.6800 3rd Qu.: 0.11124 3rd Qu.:27.90
## Max. : 1.017344 Max. : 1.9600 Max. : 8.84703 Max. :31.60
## PE_ratio EPS_ratio PS_ratio PB_ratio
## Min. : 0.00 Min. :-6.560 Min. : 0.160 Min. : 0.000
## 1st Qu.: 9.82 1st Qu.: 1.460 1st Qu.: 0.470 1st Qu.: 1.220
## Median : 13.71 Median : 2.960 Median : 1.710 Median : 3.050
## Mean : 30.33 Mean : 3.443 Mean : 2.725 Mean : 4.688
## 3rd Qu.: 23.49 3rd Qu.: 4.560 3rd Qu.: 3.180 3rd Qu.: 5.230
## Max. :1116.57 Max. :29.870 Max. :24.490 Max. :47.620
## NetProfitMargin_ratio current_ratio roa_ratio roe_ratio
## Min. :-24.630 Min. : 0.610 Min. :-12.990 Min. :-99.49
## 1st Qu.: 2.620 1st Qu.: 0.980 1st Qu.: 1.740 1st Qu.: 8.83
## Median : 7.700 Median : 1.220 Median : 5.710 Median : 16.10
## Mean : 9.205 Mean : 2.173 Mean : 5.596 Mean : 15.64
## 3rd Qu.: 15.770 3rd Qu.: 1.790 3rd Qu.: 7.990 3rd Qu.: 26.03
## Max. : 62.000 Max. :13.560 Max. : 38.130 Max. : 57.25
Nhận xét tổng quan về bộ dữ liệu
Bộ dữ liệu 400K NYSE Random Investments + Financial Ratios bao gồm 405.258 quan sát và 25 biến, trong đó có 5 biến định tính (factor) và 20 biến định lượng (numeric). Quy mô dữ liệu lớn, cấu trúc rõ ràng, và chứa đầy đủ thông tin cần thiết để thực hiện các phân tích mô phỏng hoạt động đầu tư, đo lường hiệu quả tài chính và đánh giá rủi ro cổ phiếu.
Về các biến giao dịch, giá mua
(price_BUY) dao động mạnh, từ 7.14 đến
2,039.51 USD, trong khi giá bán
(price_SELL) trải rộng từ 4.01 đến
3,450.96 USD, cho thấy sự khác biệt lớn giữa các loại
cổ phiếu trên thị trường. Số tiền đầu tư (amount) có giá
trị trung bình khoảng 8,108 USD, nhưng độ phân tán khá
cao (cao nhất đến 50,000 USD), phản ánh mức độ đa dạng
trong quy mô đầu tư.
Các biến về hiệu suất đầu tư và rủi ro cho thấy sự chênh lệch đáng kể:
nominal_return) dao động từ
-87.2% đến +884.7%, thể hiện sự tồn
tại của cả khoản đầu tư thua lỗ lẫn siêu lợi nhuận.expected_return..yearly.)
trung bình 7.08%, với biên độ khá rộng, cho thấy rủi ro
và cơ hội cao trong thị trường.Volatility_Buy và
Volatility_sell) trung bình khoảng 0.25,
nhưng có giá trị cực đại trên 0.9, phản ánh sự khác
biệt về rủi ro giữa các cổ phiếu.Đối với các chỉ số tài chính (financial ratios), phân bố cũng khá đa dạng:
Ngoài ra, biến ESG_ranking (xếp hạng bền vững) dao động từ 12.0 đến 31.6, trung bình 22.6, thể hiện rằng đa phần các công ty trong tập dữ liệu có mức độ phát triển bền vững trung bình. Biến inflation có giá trị trung bình 0.58%, chủ yếu dao động quanh 0%, phù hợp với môi trường kinh tế ổn định của Mỹ trong giai đoạn mô phỏng.
Tổng thể, bộ dữ liệu có sự phân tán lớn, đa chiều và mang tính đại diện cao cho hoạt động đầu tư cổ phiếu. Nó phù hợp cho việc triển khai phân tích mô tả, phân tích thống kê, và các mô hình định lượng. Điều này giúp bộ dữ liệu trở thành nền tảng tốt cho phân tích định lượng và mô hình hóa tài chính.
Thống kê mô tả được thực hiện theo hai hướng: nhóm theo ngành nghề (sector) và nhóm theo phân loại khoản đầu tư (investment). Mục tiêu của phần này là giúp hiểu rõ đặc điểm tổng quan của bộ dữ liệu khoản đầu tư trên sàn NYSE, đặc biệt là mối quan hệ giữa lợi suất, biến động và các chỉ số tài chính như P/E, ROE, ROA.
# 1. Mô tả tổng quan theo ngành nghề (sector)
nyse_sector_summary <- nyse %>%
group_by(sector) %>%
summarise(
So_quan_sat = n(),
Mean_Return = mean(nominal_return, na.rm = TRUE),
Mean_Volatility = mean(Volatility_Buy, na.rm = TRUE),
Mean_PE = mean(PE_ratio, na.rm = TRUE),
Mean_ROE = mean(roe_ratio, na.rm = TRUE),
Mean_ROA = mean(roa_ratio, na.rm = TRUE)
) %>%
arrange(desc(So_quan_sat))
# BẢNG
nyse_sector_summary %>%
mutate(
# Làm tròn số
So_quan_sat = format(So_quan_sat, big.mark = ","),
across(starts_with("Mean"), ~round(., 4))
) %>%
kable(
caption = "Bảng 1.3.1. Thống kê mô tả theo ngành nghề",
align = "c"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F
)| sector | So_quan_sat | Mean_Return | Mean_Volatility | Mean_PE | Mean_ROE | Mean_ROA |
|---|---|---|---|---|---|---|
| RETAIL | 96,269 | 0.0592 | 0.2686 | 14.3496 | 18.9336 | 6.1347 |
| TECH | 92,401 | 0.1996 | 0.2675 | 79.4631 | 20.7121 | 11.6058 |
| BANK | 84,757 | 0.0262 | 0.2657 | 18.4132 | 10.0402 | 1.2225 |
| AUTO | 79,836 | 0.0033 | 0.2772 | 8.3337 | 6.0926 | 1.6893 |
| FMCG | 51,995 | 0.0416 | 0.1494 | 25.7981 | 24.3482 | 7.0468 |
Nhận xét: Ngành Technology và Financials chiếm tỷ trọng lớn. Ngành Technology thường đạt mức lợi suất trung bình cao nhất, phù hợp với đặc điểm tăng trưởng mạnh. Ngược lại, các ngành như Utilities hay Energy có lợi suất trung bình thấp hơn, song lại đi kèm với độ biến động (Volatility) thấp, thể hiện tính ổn định và ít rủi ro hơn.
# 2. Biểu đồ: Lợi suất trung bình theo ngành
ggplot(nyse_sector_summary, aes(x = reorder(sector, Mean_Return), y = Mean_Return, fill = sector)) +
geom_col(show.legend = FALSE) +
coord_flip() +
labs(title = "Hình 1.3.1. Lợi suất trung bình theo ngành", x = "Ngành nghề", y = "Lợi suất danh nghĩa (nominal_return)") +
theme_minimal(base_size = 12)Biểu đồ 1.3.1 minh họa rõ xu hướng này khi ngành công nghệ và tài chính nổi bật về hiệu quả sinh lời, trong khi nhóm ngành công nghiệp cơ bản duy trì mức lợi suất khiêm tốn hơn. Điều này gợi ý rằng sự khác biệt giữa các ngành có thể đóng vai trò quan trọng trong việc xác định danh mục đầu tư hiệu quả.
Dữ liệu được nhóm theo biến investment (GOOD và BAD).
# 3. Mô tả tổng quan theo phân loại đầu tư (investment)
nyse_investment_summary <- nyse %>%
group_by(investment) %>%
summarise(
So_quan_sat = n(),
Mean_Return = mean(nominal_return, na.rm = TRUE),
Mean_Volatility = mean(Volatility_Buy, na.rm = TRUE),
Mean_Sharpe = mean(Sharpe.Ratio, na.rm = TRUE),
Mean_PE = mean(PE_ratio, na.rm = TRUE),
Mean_ROE = mean(roe_ratio, na.rm = TRUE)
)
# SỬ DỤNG KABLEEXTRA ĐỂ LÀM ĐẸP BẢNG
nyse_investment_summary %>%
mutate(
# Làm tròn số
So_quan_sat = format(So_quan_sat, big.mark = ","),
across(starts_with("Mean"), ~round(., 4))
) %>%
kable(
caption = "Bảng 1.3.2. Thống kê mô tả theo loại khoản đầu tư",
align = "c"
) %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F
)| investment | So_quan_sat | Mean_Return | Mean_Volatility | Mean_Sharpe | Mean_PE | Mean_ROE |
|---|---|---|---|---|---|---|
| BAD | 264,440 | 0.0054 | 0.2507 | 0.2507 | 29.3452 | 15.9127 |
| GOOD | 140,818 | 0.1942 | 0.2605 | 0.2605 | 32.1777 | 15.1399 |
Nhận xét: Nhóm GOOD investments có lợi suất danh nghĩa trung bình cao hơn đáng kể so với nhóm BAD, đồng thời sở hữu tỷ lệ Sharpe Ratio cao hơn. Điều này chứng tỏ sự phân loại đầu tư theo tiêu chí “GOOD” có cơ sở thống kê nhất định, phản ánh hiệu quả sinh lời vượt trội
# 4. Biểu đồ: So sánh lợi suất giữa GOOD và BAD investments
ggplot(nyse_investment_summary, aes(x = investment, y = Mean_Return, fill = investment)) +
geom_col(show.legend = FALSE) +
labs(title = "Hình 1.3.2. So sánh lợi suất trung bình theo loại khoản đầu tư",
x = "Phân loại đầu tư", y = "Lợi suất danh nghĩa (nominal_return)") +
theme_minimal(base_size = 12)# 5. Boxplot: Phân bố PE Ratio theo loại đầu tư
ggplot(nyse, aes(x = investment, y = PE_ratio, fill = investment)) +
geom_boxplot(outlier.color = "red", alpha = 0.6) +
labs(title = "Hình 1.5.3. Phân bố hệ số PE theo loại khoản đầu tư", x = "Loại đầu tư", y = "PE Ratio") +
theme_minimal(base_size = 12)Nhận xét: Hình 1.3.2 thể hiện rõ sự khác biệt này với khoảng cách đáng kể giữa hai cột đại diện cho lợi suất trung bình. Bên cạnh đó, boxplot PE Ratio (Hình 1.5.3) cho thấy nhóm GOOD có phân bố hệ số P/E rộng hơn và xuất hiện nhiều giá trị ngoại lai cao, ngụ ý rằng nhà đầu tư sẵn sàng trả mức định giá cao hơn cho các khoản đầu tư được đánh giá tốt, đi kèm với sự phân tán lớn hơn về định giá.
# Biểu đồ histogram lợi suất danh nghĩa
ggplot(nyse, aes(x = nominal_return)) +
geom_histogram(bins = 60, fill = "#0073C2FF", color = "white", alpha = 0.8) +
labs(title = "Hình 1.4.1. Phân bố tỷ suất lợi nhuận danh nghĩa",
x = "Tỷ suất lợi nhuận (%)",
y = "Tần suất (Số lượng quan sát)") +
theme_minimal(base_size = 12)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.87222 -0.02837 0.01410 0.07102 0.11124 8.84703
Nhận xét: Phân bố có dạng lệch phải (right-skewed), tập trung dày đặc ở các giá trị gần 0%. Sự tồn tại của một “đuôi” dài kéo về phía phải thể hiện tồn tại một số ít các trường hợp đầu tư đạt mức sinh lời rất cao (tỷ suất lợi nhuận đột biến), phù hợp với đặc trưng của thị trường cổ phiếu có rủi ro cao.
# So sánh độ biến động giá khi mua và khi bán
vol_data <- nyse %>%
select(Volatility_Buy, Volatility_sell) %>%
pivot_longer(cols = everything(), names_to = "Giai_doan", values_to = "Volatility")
ggplot(vol_data, aes(x = Giai_doan, y = Volatility, fill = Giai_doan)) +
geom_boxplot(alpha = 0.7) +
labs(title = "Hình 1.4.2. Phân bố độ biến động giá khi mua và khi bán",
x = "Giai đoạn giao dịch",
y = "Độ biến động (Volatility)") +
theme_minimal(base_size = 12) +
theme(legend.position = "none")Nhận xét: Phân phối độ biến động giá mua (Buy) và giá bán (Sell) rất giống nhau về cả trung vị và phạm vi phân tán trung tâm. Điều này cho thấy sự biến động không có sự khác biệt đáng kể giữa thời điểm nhà đầu tư thực hiện giao dịch mua và giao dịch bán. Việc thị trường có nhiều biến động (Volatility cao) xảy ra ở cả hai giai đoạn (mua và bán), nhưng các giao dịch cực đoan (outliers) dường như phổ biến hơn ở phía bán (Volatility_Sell) do đuôi ngoại lai ở biểu đồ hộp bán có vẻ kéo dài và dày đặc hơn một chút so với phía mua.
# Biểu đồ phân tán ROE vs ROA
ggplot(nyse, aes(x = roa_ratio, y = roe_ratio)) +
geom_point(alpha = 0.4, color = "#00AFBB") +
geom_smooth(method = "lm", color = "red", se = FALSE) +
labs(title = "Hình 1.4.3. Mối quan hệ giữa ROA và ROE của doanh nghiệp",
x = "ROA (%)",
y = "ROE (%)") +
theme_minimal(base_size = 12)Nhận xét: Có một mối tương quan tuyến tính dương mạnh giữa ROA và ROE. Độ dốc của đường hồi quy lớn hơn 1 là minh chứng rõ ràng cho việc sử dụng đòn bẩy tài chính đã khuếch đại lợi nhuận được tạo ra từ tài sản lên trên vốn cổ phần.
## Số quan sát: 405258
## Số biến: 25
## 'data.frame': 405258 obs. of 25 variables:
## $ X : int 0 1 2 3 4 5 7 8 9 10 ...
## $ company : Factor w/ 27 levels "AAPL","AMZN",..: 5 4 3 16 14 21 9 26 4 14 ...
## $ sector : Factor w/ 5 levels "AUTO","BANK",..: 4 2 2 4 2 3 5 2 2 2 ...
## $ horizon..days. : int 2 330 7 5 360 15 720 600 30 6 ...
## $ amount : int 100 15000 3000 20000 15000 50000 1500 300 50000 400 ...
## $ date_BUY_fix : Factor w/ 1248 levels "2013-10-10","2013-10-11",..: 905 779 741 750 353 729 272 593 440 582 ...
## $ date_SELL_fix : Factor w/ 1729 levels "2013-10-11","2013-10-15",..: 905 1004 745 753 598 738 764 1004 460 584 ...
## $ price_BUY : num 55.6 18.6 59.9 38.2 51.9 ...
## $ price_SELL : num 53.5 24.7 59.5 36 52 ...
## $ Volatility_Buy : num 0.384 0.323 0.239 0.429 0.195 ...
## $ Volatility_sell : num 0.386 0.236 0.235 0.429 0.254 ...
## $ Sharpe.Ratio : num 0.384 0.323 0.239 0.429 0.195 ...
## $ expected_return..yearly.: num 1.44e-03 1.71e-01 2.82e-03 9.39e-05 1.50e-01 ...
## $ inflation : num 1.96 -0.2 -0.2 -0.2 -0.5 -0.2 -0.15 -0.2 -0.5 -0.2 ...
## $ nominal_return : num -0.03722 0.32432 -0.00576 -0.05839 0.00344 ...
## $ investment : Factor w/ 2 levels "BAD","GOOD": 1 2 1 1 2 2 2 2 1 2 ...
## $ ESG_ranking : num 12 26.3 19.8 12.9 27.9 17.6 31.6 24.8 26.3 27.9 ...
## $ PE_ratio : num 12.58 11.39 10.58 11.09 9.38 ...
## $ EPS_ratio : num 3.73 1.26 5.64 3.27 5.46 4.56 1.05 1.71 0.96 5.99 ...
## $ PS_ratio : num 0.38 1.71 1.67 0.36 1.87 ...
## $ PB_ratio : num 3.19 0.54 2.6 1.25 0.81 ...
## $ NetProfitMargin_ratio : num 3.01 15.7 15.68 3.17 19.91 ...
## $ current_ratio : num 1.49 0.92 1.91 1.6 0.99 ...
## $ roa_ratio : num 8.69 0.67 3.39 4.41 0.81 ...
## $ roe_ratio : num 26.69 5.54 25.78 11.35 8.91 ...
# Tạo vector
financial_ratios_to_analyze <- c("nominal_return", "roe_ratio", "PE_ratio", "Sharpe.Ratio")
cat("Chỉ số thứ 2 trong danh sách:", financial_ratios_to_analyze[2], "\n")## Chỉ số thứ 2 trong danh sách: roe_ratio
# Liệt kê các cấp độ (levels) của biến Factor
nyse$sector <- as.factor(nyse$sector)
sector_levels <- levels(nyse$sector)
cat("Các ngành nghề trong bộ dữ liệu:", sector_levels, "\n")## Các ngành nghề trong bộ dữ liệu: AUTO BANK FMCG RETAIL TECH
# Truy cập cột bằng ký hiệu $ và tính tổng
total_investment_amount <- sum(nyse$amount, na.rm = TRUE)
cat("Tổng số tiền đầu tư trong bộ dữ liệu mẫu:", total_investment_amount, "USD\n")## Tổng số tiền đầu tư trong bộ dữ liệu mẫu: 3286024300 USD
# Áp dụng toán tử so sánh logic
is_low_volatility <- nyse$Volatility_Buy < 0.25
# Đếm số lượng quan sát có rủi ro thấp
num_low_vol <- sum(is_low_volatility, na.rm = TRUE)
cat("Số lượng khoản đầu tư rủi ro thấp (< 0.25):", num_low_vol, "\n")## Số lượng khoản đầu tư rủi ro thấp (< 0.25): 236573
# Sử dụng các hàm thống kê cơ bản
median_return <- median(nyse$nominal_return, na.rm = TRUE)
sd_return <- sd(nyse$nominal_return, na.rm = TRUE)
cat("Trung vị Lợi suất danh nghĩa:", round(median_return, 4), "\n")## Trung vị Lợi suất danh nghĩa: 0.0141
## Độ lệch chuẩn Lợi suất danh nghĩa: 0.2988
# Chuyển cột thành Date
nyse$date_BUY_fix_DATE <- as.Date(as.character(nyse$date_BUY_fix), format = "%Y-%m-%d")
nyse$date_SELL_fix_DATE <- as.Date(as.character(nyse$date_SELL_fix), format = "%Y-%m-%d")
# Kiểm tra kiểu dữ liệu mới và phạm vi ngày
cat("Kiểu dữ liệu mới (Mua):", class(nyse$date_BUY_fix_DATE), "\n")## Kiểu dữ liệu mới (Mua): Date
## Phạm vi ngày mua: 2013-10-10 2018-10-09
# Tính khoảng thời gian nắm giữ (Holding Period) theo ngày
nyse$holding_period_days <- difftime(nyse$date_SELL_fix_DATE,
nyse$date_BUY_fix_DATE,
units = "days")
cat("Trung bình số ngày nắm giữ (Holding Period):", round(mean(nyse$holding_period_days, na.rm = TRUE), 1), "ngày\n")## Trung bình số ngày nắm giữ (Holding Period): 187.1 ngày
# Kiểm tra Trùng lặp
duplicated_records <- sum(duplicated(nyse))
cat("Số lượng bản ghi trùng lặp:", duplicated_records, "\n")## Số lượng bản ghi trùng lặp: 0
# Kiểm tra NA
na_count_per_column <- colSums(is.na(nyse))
total_na_count <- sum(na_count_per_column)
cat("Tổng số giá trị NA trong toàn bộ dữ liệu:", total_na_count, "\n")## Tổng số giá trị NA trong toàn bộ dữ liệu: 0
## named numeric(0)
Dù không cần xử lý trùng lặp hay NA, ta vẫn cần loại bỏ các biến không cần thiết như biến định danh tự động (X) và chọn lọc các cột chính để tối ưu trước khi xử lý lớn.
# Loại bỏ biến thừa và chọn lọc biến phân tích
nyse_clean <- nyse %>%
# Loại bỏ các biến thừa và không dùng (X và date_SELL_fix)
select(-X, -date_SELL_fix) %>%
# Đảm bảo các biến quan trọng đã được chuyển kiểu dữ liệu
mutate(
date_BUY_fix_DATE = as.Date(date_BUY_fix),
sector = as.factor(sector),
investment = as.factor(investment)
)
cat("Số biến sau khi loại bỏ:", ncol(nyse_clean), "\n")## Số biến sau khi loại bỏ: 26
** Lý do Loại bỏ Biến date_SELL_fix**
Biến date_SELL_fix được loại bỏ vì nó là thông tin trùng lặp, có thể dẫn đến đa cộng tuyến. Thông tin thời gian bán đã được mã hóa trong hai biến độc lập khác là date_BUY_fix (ngày mua) và horizon..days. (số ngày nắm giữ), giúp mô hình tập trung vào điểm quyết định (ngày mua) và chiến lược (thời gian nắm giữ).
Sử dụng phép biến đổi logarit để chuẩn hóa PE_ratio, giảm thiểu ảnh hưởng của các giá trị ngoại lai lớn.
# Chuẩn hóa tỷ suất định giá bằng Log Transformation
nyse_clean <- nyse_clean %>%
mutate(
# Chỉ lấy log cho các giá trị PE dương và hợp lý
log_PE = if_else(PE_ratio > 1, log(PE_ratio), NA_real_)
)
# So sánh phân bố trước và sau chuẩn hóa
summary(nyse_clean$PE_ratio)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 9.82 13.71 30.33 23.49 1116.57
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1.13 2.38 2.69 2.88 3.21 7.02 39751
Kết quả thống kê mô tả cho thấy sự thay đổi đáng kể về phân bố sau khi áp dụng phép biến đổi logarit, xác nhận mục tiêu chuẩn hóa đã đạt được.
PE_ratio)Dữ liệu gốc thể hiện tính lệch rất rõ rệt:
| Chỉ số | Giá trị | Nhận xét |
|---|---|---|
| Giá trị Lớn nhất (Max) | 1116.57 |
Giá trị cực kỳ cao, cho thấy sự tồn tại của các giá trị ngoại lai (outliers) lớn, gây ra hiện tượng lệch phải mạnh. |
| Giá trị Trung bình (Mean) | 30.33 |
|
| Giá trị Trung vị (Median) | 13.71 |
|
| Sự chênh lệch | Mean (30.33) \(\gg\) Median (13.71) |
Sự chênh lệch lớn giữa Mean và Median xác nhận phân bố
của PE_ratio là cực kỳ lệch phải
(positively skewed). Phân bố này không phù hợp với giả định cơ
bản của hầu hết các mô hình thống kê và hồi quy tuyến tính. |
log_PE)Sau khi biến đổi logarit tự nhiên, phân bố đã được cải thiện đáng kể:
| Chỉ số | Giá trị | Nhận xét |
|---|---|---|
| Giá trị Lớn nhất (Max) | 7.018 |
Giá trị Max đã được nén đáng kể, làm giảm ảnh hưởng của các outliers cực lớn lên mô hình. |
| Giá trị Trung bình (Mean) | 2.879 |
|
| Giá trị Trung vị (Median) | 2.686 |
|
| Sự chênh lệch | Mean (2.879) \(\approx\) Median (2.686) |
Giá trị Mean và Median đã tiệm cận nhau, cho thấy phân bố đã trở nên đối xứng hơn và tiến gần đến phân bố chuẩn (Normal Distribution). |
| NA’s | 39,751 |
Đây là số lượng quan sát có PE_ratio
bằng 0 hoặc âm (không hợp lý về mặt kinh tế hoặc do lỗi
dữ liệu) hoặc có giá trị quá nhỏ (dưới 1) đã bị loại bỏ/gán NA để tránh
lỗi logarit, đây là một bước làm sạch cần thiết. |
Sử dụng ROA và ROE để ước tính tỷ số đòn bẩy tài chính (gần với hệ số nhân vốn chủ sở hữu trong phân tích DuPont).
Ta sử dụng một biến thể đơn giản của hệ thống DuPont Analysis để ước tính tỷ lệ Đòn bẩy (Leverage Ratio). Về mặt lý thuyết, trong phân tích DuPont: ROE≈ROA×Equity.Multiplier. Trong đó, Equity.Multiplier phản ánh đòn bẩy.
Sử dụng mutate() để tạo biến Leverage_Ratio (≈roe_ratio/roa_ratio). Xử lý các trường hợp ROA rất nhỏ (gần 0) để tránh lỗi chia cho 0 và các kết quả ngoại lai không hợp lý.
# Tạo biến đòn bẩy tài chính
nyse_clean <- nyse_clean %>%
mutate(
# Sử dụng if_else để kiểm soát lỗi chia cho 0 hoặc các giá trị âm không hợp lý.
# yêu cầu ROA phải lớn hơn 0.001 (0.1%) để tính Leverage Ratio.
Leverage_Ratio = if_else(
abs(roa_ratio) > 0.001,
roe_ratio / roa_ratio,
NA_real_ # Gán NA cho các trường hợp ROA quá nhỏ
)
)
# Thống kê nhanh biến mới để kiểm tra phân bố
summary(nyse_clean$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
Nhận xét phân tích kết quả
Giá trị nhỏ nhất (Min.) là 1.103. Điều này quan trọng vì nó xác nhận rằng tất cả các quan sát hợp lệ đều có Leverage_Ratio>1, ngụ ý ROE>ROA. Về mặt tài chính, điều này chứng tỏ các công ty được phân tích đang sử dụng đòn bẩy tài chính một cách hiệu quả, vì lợi nhuận trên tài sản tạo ra đã đủ để trang trải chi phí nợ và khuếch đại lợi nhuận cho cổ đông.
Sự tồn tại của các giá trị Leverage Ratio âm (do công ty thua lỗ hoặc ROA/ROE trái dấu) hoặc các giá trị cực lớn bất thường (do ROA→0) trong dữ liệu ban đầu đã được xử lý thành NA thông qua điều kiện abs(roa_ratio)>0.001, giúp loại bỏ các trường hợp đòn bẩy không hợp lý và làm sạch phân bố.
Giá trị trung vị (Median) là 3.439. Điều này có nghĩa là 50% số công ty sử dụng đòn bẩy gấp khoảng 3.4 lần, cho thấy một mức độ sử dụng nợ khá cao và phổ biến trong các giao dịch trên sàn NYSE.
Giá trị trung bình (Mean) là 5.212 lớn hơn đáng kể so với Median (3.439). Điều này cho thấy phân bố của Leverage_Ratio vẫn bị lệch phải do sự tồn tại của các giá trị đòn bẩy cao (tối đa là 34.545), nhưng sự lệch này đã được kiểm soát tốt hơn so với phân bố gốc.
Giá trị Max (34.545) là ngưỡng đòn bẩy tối đa được giữ lại. Đây là một giá trị lớn nhưng hợp lý hơn so với các giá trị hàng trăm hoặc hàng nghìn trong kết quả trước, cho thấy việc kiểm soát outliers đã thành công.
Số lượng NA’s (2,468) là số lượng bản ghi bị loại trừ do ROA quá nhỏ hoặc không hợp lệ, đảm bảo chỉ những công ty có hoạt động kinh doanh ổn định mới được đưa vào phân tích về đòn bẩy.
Chuyển biến liên tục horizon..days. sang biến định tính Holding_Period (Ngắn/Trung/Dài hạn).
# Phân loại thời gian nắm giữ
nyse_clean <- nyse_clean %>%
mutate(
Holding_Period = cut(horizon..days.,
# Thiết lập các điểm cắt (breaks)
breaks = c(0, 30, 180, Inf),
# Gán nhãn cho từng khoảng
labels = c("Short-term (<=30 days)", "Mid-term (31-180 days)", "Long-term (>180 days)"),
right = TRUE,
include.lowest = TRUE)
)
# Tính toán số lượng và tỷ lệ phần trăm của từng nhóm
total_rows <- nrow(nyse_clean)
holding_period_count <- nyse_clean %>%
group_by(Holding_Period) %>%
summarise(
Count = n(),
Percentage = (Count / total_rows) * 100, # Tính tỷ lệ phần trăm
.groups = 'drop'
)
print(holding_period_count)## # A tibble: 3 × 3
## Holding_Period Count Percentage
## <fct> <int> <dbl>
## 1 Short-term (<=30 days) 135001 33.3
## 2 Mid-term (31-180 days) 122731 30.3
## 3 Long-term (>180 days) 147526 36.4
Nhận xét
Chiến lược Dài hạn (>180 ngày) chiếm tỷ trọng cao nhất (36.40%), khẳng định tính phổ biến của chiến lược Buy and Hold, nhưng sự phân bổ tương đối đồng đều giữa các nhóm (mỗi nhóm ≈1/3) cho phép phân tích so sánh đa dạng.
Sử dụng gói lubridate để trích xuất năm và quý từ ngày mua, hỗ trợ phân tích xu hướng và tính thời vụ.
nyse_clean <- nyse_clean %>%
mutate(
date_BUY_fix_DATE = as.Date(date_BUY_fix),
Buy_Year = lubridate::year(date_BUY_fix_DATE),
Buy_Quarter_Num = lubridate::quarter(date_BUY_fix_DATE),
Buy_Quarter = lubridate::quarter(date_BUY_fix_DATE, with_year = TRUE)
)
# Xem 5 kết quả đầu tiên của biến Quý và Năm
nyse_clean %>%
select(date_BUY_fix_DATE, Buy_Year, Buy_Quarter) %>%
head(5)## Phạm vi Năm mua: 2013 2018
Nhận xét
Ý nghĩa của Buy_Year: Biến này sẽ được sử dụng để phân tích xu hướng dài hạn của thị trường, cho phép ta so sánh lợi suất trung bình và rủi ro giữa các năm. Ví dụ, ta có thể đánh giá sự khác biệt về hiệu suất đầu tư trước và sau các sự kiện kinh tế lớn (như khủng hoảng 2020).
Ý nghĩa của Buy_Quarter: Biến này là công cụ mạnh mẽ cho việc phân tích tính thời vụ. Trong tài chính, hiệu suất thị trường thường bị ảnh hưởng bởi các chu kỳ báo cáo thu nhập hàng quý hoặc các hiệu ứng lịch (ví dụ: Hiệu ứng tháng Giêng). Việc sử dụng định dạng Năm.Quý giúp ta dễ dàng sắp xếp dữ liệu theo chuỗi thời gian liên tục và chính xác.
Việc phân tích hiệu suất đầu tư không thể thiếu việc điều chỉnh theo lạm phát. Lợi suất danh nghĩa (nominal_return) chỉ phản ánh sự tăng trưởng về mặt tiền tệ, trong khi Lợi suất thực tế (Real_Return) phản ánh sự tăng trưởng về sức mua thực tế. Để tính Lợi suất hực tế, ta cần bổ sung dữ liệu lạm phát hàng năm.
Ghép dữ liệu lạm phát (ngoại sinh) và tính toán biến phụ thuộc chính xác nhất: Lợi suất Thực tế (Real_Return).
# 1. Tạo bảng dữ liệu lạm phát giả định theo Năm mua (Đã chuyển sang thập phân)
inflation_data <- tibble(
Buy_Year = 2013:2018,
# Tỷ lệ lạm phát hàng năm (CPI) - Giả định
Inflation_Rate = c(0.0147, 0.0162, 0.0012, 0.0126, 0.0213, 0.0244)
)
# 2. Thực hiện left join và tính Lợi suất thực tế
nyse_clean <- nyse_clean %>%
left_join(inflation_data, by = "Buy_Year") %>%
mutate(
Real_Return = nominal_return - Inflation_Rate # Công thức tính Lợi suất thực tế
)
# Kiểm tra kết quả ghép - 5 hàng đầu tiên
cat("Kiểm tra kết quả ghép (Buy_Year và Inflation_Rate):\n")## Kiểm tra kết quả ghép (Buy_Year và Inflation_Rate):
##
## Thống kê Lợi suất thực tế (Real_Return):
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.896616 -0.043447 -0.000207 0.056145 0.096327 8.834425
Nhận xét
2017: Lợi suất danh nghĩa âm và sau khi trừ lạm phát (0.0213), Lợi suất thực tế càng âm hơn (tổn thất sức mua).
2016: Lợi suất danh nghĩa rất cao. Sau khi điều chỉnh lạm phát (0.0126), lợi suất vẫn giữ mức cao, cho thấy sức mua tăng trưởng mạnh mẽ.
2015: Lợi suất danh nghĩa gần bằng không. Do lạm phát năm 2015 rất thấp (0.0012), lợi suất thực tế vẫn dương, duy trì sức mua.
Giá trị Trung vị (Median): −0.0002074 rất gần 0. Điều này có nghĩa là, một giao dịch trung bình trong tập dữ liệu hầu như không tạo ra được lợi nhuận thực tế để bù đắp lạm phát. Hơn một nửa số giao dịch không thể tăng sức mua cho nhà đầu tư.
Giá trị Trung bình (Mean): 0.0561449 Giá trị dương cho thấy một số lượng lớn outliers dương (các giao dịch rất sinh lời) đã kéo giá trị trung bình lên. Nếu chỉ nhìn vào Mean, ta sẽ đánh giá quá cao hiệu suất đầu tư chung.
Min. / Max.: −0.8966 / 8.8344 phạm vi rất rộng (khoảng 9.7 đơn vị). Cho thấy mức độ rủi ro và lợi nhuận tiềm năng cực lớn của các khoản đầu tư, từ thua lỗ nặng (mất ∼90% sức mua) đến lãi đột biến (tăng ∼883% sức mua).
Quartile 1 (1st Qu.): −0.0434, 25% số giao dịch có Lợi suất thực tế âm sâu hơn 4.34%.
Kết luận
Nếu chỉ nhìn vào nominal_return, ta có thể bỏ qua việc một nửa số khoản đầu tư đã thất bại trong việc duy trì sức mua (vì Median≈0).
Biến Real_Return là biến phụ thuộc chính xác nhất, phản ánh giá trị kinh tế thực tế mà nhà đầu tư nhận được, và sẽ được sử dụng làm mục tiêu dự báo trong chương sau.
Mô phỏng chiến lược Đầu tư Giá trị (Value Investing).
Tìm kiếm các khoản đầu tư đã được phân loại là Tốt (GOOD), đạt lợi nhuận cao (danh nghĩa trên 10%), và có định giá thấp (chỉ số PE_ratio<20). Sau đó, sắp xếp kết quả theo lợi nhuận giảm dần.
# Lọc và sắp xếp theo nhiều tiêu chí
value_investment_candidates <- nyse_clean %>%
filter(
investment == "GOOD", # Điều kiện 1: Kết quả đầu tư tốt
nominal_return > 0.10, # Điều kiện 2: Lợi nhuận danh nghĩa trên 10%
PE_ratio < 20 # Điều kiện 3: Định giá thấp (PE Ratio dưới 20)
) %>%
arrange(desc(nominal_return)) # Sắp xếp theo lợi nhuận giảm dần
# Xem 10 ứng viên đầu tiên đáp ứng tiêu chí (Đầu tư giá trị, sinh lời cao)
print(head(value_investment_candidates, 10))## company sector horizon..days. amount date_BUY_fix price_BUY price_SELL
## 1 NVDA TECH 720 400 2015-06-26 20.13152 150.8678
## 2 TSLA AUTO 720 4000 2018-10-02 60.20400 449.3900
## 3 TSLA AUTO 720 3000 2018-10-01 62.14000 449.3900
## 4 NVDA TECH 720 200 2015-06-15 20.45184 146.5508
## 5 NVDA TECH 720 1500 2015-06-16 20.70421 146.5508
## 6 TSLA AUTO 720 15000 2018-09-24 59.93600 419.6200
## 7 NVDA TECH 720 4000 2015-06-12 20.49067 142.9368
## 8 NVDA TECH 720 10000 2015-06-17 20.94688 145.8874
## 9 NVDA TECH 720 1500 2015-06-10 20.84011 143.4418
## 10 NVDA TECH 720 100 2015-05-27 21.19925 135.3187
## Volatility_Buy Volatility_sell Sharpe.Ratio expected_return..yearly.
## 1 0.2810847 0.4749833 0.2810847 0.9727243
## 2 0.5227019 0.8762335 0.5227019 1.0173441
## 3 0.5217680 0.8762335 0.5217680 1.0173441
## 4 0.2803311 0.4664966 0.2803311 0.9727243
## 5 0.2805653 0.4664966 0.2805653 0.9727243
## 6 0.4729003 0.8724491 0.4729003 1.0173441
## 7 0.2803233 0.4660826 0.2803233 0.9727243
## 8 0.2807224 0.4664835 0.2807224 0.9727243
## 9 0.2790765 0.4661851 0.2790765 0.9727243
## 10 0.2755349 0.4581479 0.2755349 0.9727243
## inflation nominal_return investment ESG_ranking PE_ratio EPS_ratio PS_ratio
## 1 -0.50 6.494110 GOOD 12.9 19.17 1.12 2.56
## 2 1.68 6.464455 GOOD 31.1 0.00 -2.13 2.60
## 3 1.68 6.231896 GOOD 31.1 0.00 -2.13 2.60
## 4 -0.50 6.165654 GOOD 12.9 19.17 1.12 2.56
## 5 -0.50 6.078309 GOOD 12.9 19.17 1.12 2.56
## 6 1.68 6.001134 GOOD 31.1 0.00 -2.13 2.60
## 7 -0.50 5.975701 GOOD 12.9 19.17 1.12 2.56
## 8 -0.50 5.964636 GOOD 12.9 19.17 1.12 2.56
## 9 -0.50 5.882967 GOOD 12.9 19.17 1.12 2.56
## 10 -0.50 5.383184 GOOD 12.9 19.17 1.12 2.56
## PB_ratio NetProfitMargin_ratio current_ratio roa_ratio roe_ratio
## 1 2.54 13.28 6.61 8.87 14.37
## 2 8.57 -10.23 0.81 -6.34 -34.85
## 3 8.57 -10.23 0.81 -6.34 -34.85
## 4 2.54 13.28 6.61 8.87 14.37
## 5 2.54 13.28 6.61 8.87 14.37
## 6 8.57 -10.23 0.81 -6.34 -34.85
## 7 2.54 13.28 6.61 8.87 14.37
## 8 2.54 13.28 6.61 8.87 14.37
## 9 2.54 13.28 6.61 8.87 14.37
## 10 2.54 13.28 6.61 8.87 14.37
## date_BUY_fix_DATE date_SELL_fix_DATE holding_period_days log_PE
## 1 2015-06-26 2017-06-15 720 days 2.953347
## 2 2018-10-02 2020-09-21 720 days NA
## 3 2018-10-01 2020-09-21 721 days NA
## 4 2015-06-15 2017-06-05 721 days 2.953347
## 5 2015-06-16 2017-06-05 720 days 2.953347
## 6 2018-09-24 2020-09-14 721 days NA
## 7 2015-06-12 2017-06-01 720 days 2.953347
## 8 2015-06-17 2017-06-06 720 days 2.953347
## 9 2015-06-10 2017-05-30 720 days 2.953347
## 10 2015-05-27 2017-05-16 720 days 2.953347
## Leverage_Ratio Holding_Period Buy_Year Buy_Quarter_Num Buy_Quarter
## 1 1.620068 Long-term (>180 days) 2015 2 2015.2
## 2 5.496845 Long-term (>180 days) 2018 4 2018.4
## 3 5.496845 Long-term (>180 days) 2018 4 2018.4
## 4 1.620068 Long-term (>180 days) 2015 2 2015.2
## 5 1.620068 Long-term (>180 days) 2015 2 2015.2
## 6 5.496845 Long-term (>180 days) 2018 3 2018.3
## 7 1.620068 Long-term (>180 days) 2015 2 2015.2
## 8 1.620068 Long-term (>180 days) 2015 2 2015.2
## 9 1.620068 Long-term (>180 days) 2015 2 2015.2
## 10 1.620068 Long-term (>180 days) 2015 2 2015.2
## Inflation_Rate Real_Return
## 1 0.0012 6.492910
## 2 0.0244 6.440055
## 3 0.0244 6.207496
## 4 0.0012 6.164454
## 5 0.0012 6.077109
## 6 0.0244 5.976734
## 7 0.0012 5.974501
## 8 0.0012 5.963436
## 9 0.0012 5.881767
## 10 0.0012 5.381984
# Kiểm tra số lượng khoản đầu tư đáp ứng chiến lược
cat("\nTổng số khoản đầu tư đáp ứng chiến lược lọc:", nrow(value_investment_candidates), "\n")##
## Tổng số khoản đầu tư đáp ứng chiến lược lọc: 39200
Nhận xét
Thao tác này mô phỏng việc tìm kiếm các khoản đầu tư thỏa mãn tiêu chí của chiến lược Đầu tư Giá trị (Value Investing) — mua tài sản với giá thấp hơn giá trị nội tại. Cụ thể:
PE_ratio < 20 là chỉ báo định giá thấp (mua cổ phiếu “giá rẻ”).
nominal_return > 0.10 và investment == “GOOD” là chỉ báo về chất lượng và hiệu quả sinh lời thực tế.
Số lượng quan sát được giữ lại là 39.200 sẽ là một tập con có chất lượng cao, có khả năng sinh lời tốt (GOOD, Return>10%) nhưng lại không bị định giá quá cao.
Việc sắp xếp bằng arrange(desc(nominal_return)) giúp nhà phân tích nhanh chóng xác định các giao dịch tốt nhất thỏa mãn các ràng buộc về giá trị, cho phép kiểm tra chi tiết các ngành nghề (sector) hoặc công ty (company) dẫn đầu trong nhóm này.
Tổng hợp dữ liệu theo nhóm (group_by() và summarise()) là thao tác để tính toán các chỉ số mô tả cho từng nhóm, thể hiện được sự khác biệt về hiệu suất và rủi ro giữa các ngành nghề qua các năm. Ta sẽ nâng cao thao tác này bằng cách thêm chức năng xếp hạng (rank()) để so sánh hiệu suất tương đối của các ngành trong cùng một năm. Ta chia ra các nhóm như:
Nhóm dữ liệu theo Ngành (sector) và Năm Mua (Buy_Year).
Tính Lợi suất trung bình (Mean_Return) và Rủi ro trung bình (Mean_Volatility).
Sử dụng hàm rank() trong mutate() để xếp hạng Lợi suất trung bình của các ngành trong từng năm.
# Tổng hợp và xếp hạng hiệu suất theo ngành và năm
nyse_summary_annual <- nyse_clean %>%
# Bước 1: Nhóm theo Ngành và Năm
group_by(sector, Buy_Year) %>%
# Bước 2: Tính toán các chỉ số tổng hợp
summarise(
Count = n(),
Mean_Return = mean(nominal_return, na.rm = TRUE),
Mean_Volatility = mean(Volatility_Buy, na.rm = TRUE),
.groups = 'drop_last' # Giữ lại nhóm sector để rank
) %>%
# Bước 3: Xếp hạng Lợi suất trung bình trong từng Năm (cần nhóm lại theo Buy_Year)
# rank(desc(Mean_Return)) xếp hạng từ cao đến thấp
mutate(
Rank_by_Year = rank(desc(Mean_Return), ties.method = "min") # ties.method="min" gán hạng cao nhất nếu có cùng giá trị
) %>%
ungroup() # Bỏ tất cả các nhóm
# Xem kết quả tóm tắt với thứ hạng cho 15 hàng đầu
print(head(nyse_summary_annual, 15))## # A tibble: 15 × 6
## sector Buy_Year Count Mean_Return Mean_Volatility Rank_by_Year
## <fct> <dbl> <int> <dbl> <dbl> <int>
## 1 AUTO 2013 3475 0.0292 0.316 2
## 2 AUTO 2014 16175 -0.0164 0.290 4
## 3 AUTO 2015 15944 -0.0274 0.266 5
## 4 AUTO 2016 15888 0.0847 0.307 1
## 5 AUTO 2017 15772 -0.00211 0.253 3
## 6 AUTO 2018 12582 -0.0359 0.256 6
## 7 BANK 2013 2853 0.0176 0.229 3
## 8 BANK 2014 12855 -0.0343 0.207 5
## 9 BANK 2015 15942 -0.0658 0.242 6
## 10 BANK 2016 19086 0.155 0.342 1
## 11 BANK 2017 18953 0.0604 0.286 2
## 12 BANK 2018 15068 -0.0297 0.225 4
## 13 FMCG 2013 2116 0.0288 0.151 5
## 14 FMCG 2014 9618 0.0392 0.138 3
## 15 FMCG 2015 9601 0.0458 0.142 2
# Kiểm tra một năm cụ thể để thấy việc xếp hạng đã hoạt động
cat("\nKiểm tra xếp hạng cho năm 2017:\n")##
## Kiểm tra xếp hạng cho năm 2017:
Nhận xét
Bảng tổng hợp nyse_summary_annual cho thấy sự khác biệt rõ rệt về hiệu suất và rủi ro giữa các ngành (AUTO, BANK, FMCG) trong giai đoạn 2013-2018.
AUTO: Năm 2016 đạt lợi suất trung bình cao nhất (8.47%). Các năm khác lợi suất thấp hoặc âm. Dao động từ 0.25 đến 0.31. Hiệu suất không ổn định. Lợi suất cao nhất (8.47%) đi kèm với mức Volatility cao (0.307), phù hợp với nguyên tắc lợi suất-rủi ro.
BANK: Năm 2016 đạt lợi suất trung bình cao nhất (15.53%). Dao động từ 0.20 đến 0.34. Ngành có lợi suất cao nhất (15.53%) nhưng cũng có rủi ro cao nhất (0.342) trong các năm được liệt kê. Cho thấy ngành ngân hàng có tính chu kỳ và biến động mạnh.
FMCG: Lợi suất ổn định và dương trong cả ba năm (2.88% đến 4.58%). Dao động thấp nhất (0.138 đến 0.151). Ngành này là ngành phòng thủ, thể hiện lợi suất thấp nhưng rủi ro cực kỳ thấp (chỉ bằng ∼1/2 so với AUTO/BANK), minh chứng cho tính ổn định của hàng tiêu dùng nhanh.
BANK 2016: lợi suất trung bình (mean) là 15.53%, rủi ro trung bình là 0.342 - Rủi ro cao nhất → Lợi suất cao nhất (Phù hợp với lý thuyết tài chính).
FMCG 2013-2015: có lợi suất trung bình là 2.8%∼4.5% và rủi ro trung bình là 0.138∼0.151 - Rủi ro thấp nhất → Lợi suất thấp nhất (Phù hợp với lý thuyết tài chính).
Mối quan hệ này cho thấy sự đánh đổi giữa rủi ro và lợi suất tồn tại rõ ràng giữa các ngành.
Biến Rank_by_Year cho phép so sánh hiệu suất tương đối của các ngành trong cùng một năm (trong đó Hạng 1 là tốt nhất).
Năm 2016 (Năm Tăng trưởng):
Ngành BANK (15.53%) có khả năng đạt Hạng 1 trong năm này (vì lợi suất này rất cao).
Ngành AUTO (8.47%) cũng có hiệu suất tốt, có thể đạt Hạng 2 hoặc 3 tùy thuộc vào các ngành chưa được hiển thị.
Năm 2018 (Năm Suy thoái/Thị trường khó khăn):
Biến trễ (Lagged Variable) cho phép chúng ta kiểm tra xem hiệu suất hoặc định giá của công ty trong quá khứ (ví dụ: năm trước) có ảnh hưởng đến lợi suất trong tương lai (năm hiện tại) hay không.
Ta sẽ tạo biến trễ cho lợi suất trung bình hàng năm (Mean_Return) trong bảng tổng hợp nyse_summary_annual. Sử dụng hàm lag() của dplyr sau khi nhóm dữ liệu theo ngành (sector).
#Tạo biến lợi suất trễ (Lagged Return)
nyse_summary_annual <- nyse_summary_annual %>%
# nhóm theo Sector trước
group_by(sector) %>%
# Sắp xếp theo Buy_Year để đảm bảo lag() hoạt động đúng thứ tự thời gian
arrange(Buy_Year) %>%
mutate(
# Lợi suất trung bình của năm trước (lag(n=1))
Lagged_Mean_Return = lag(Mean_Return, n = 1, default = NA)
) %>%
ungroup()
# Xem kết quả kiểm tra (Lợi suất năm trước chuyển lên hàng năm sau)
cat("Kiểm tra Biến Lợi suất Trễ:\n")## Kiểm tra Biến Lợi suất Trễ:
nyse_summary_annual %>%
filter(sector == "AUTO" | sector == "BANK") %>%
select(sector, Buy_Year, Mean_Return, Lagged_Mean_Return) %>%
head(12)Ý nghĩa của Lệnh lag():
Lệnh lag(n=1) dịch chuyển giá trị Mean_Return lên một hàng (tức là một năm), nhưng chỉ giới hạn trong nhóm sector hiện tại.
Hàng đầu tiên của mỗi nhóm ngành (ví dụ: AUTO 2013) sẽ có giá trị NA cho Lagged_Mean_Return vì không có dữ liệu năm trước.
Giá trị Phân tích:
Biến Lagged_Mean_Return là một biến độc lập rất mạnh. Nó sẽ được sử dụng trong chương sau để kiểm tra giả thuyết: Liệu hiệu suất hoạt động của một ngành trong năm trước có phải là yếu tố dự báo đáng kể cho hiệu suất năm hiện tại hay không?
Đây là cách định lượng các khái niệm như quán tính lợi nhuận (momentum) hoặc hiệu ứng đảo ngược trung bình (mean reversion) trong tài chính.
Sử dụng pivot_longer() để chuyển các cột tỷ suất định giá (PE_ratio, PB_ratio, PS_ratio) sang dạng dài (long format), cần thiết cho việc vẽ biểu đồ so sánh phân bố giữa các tỷ suất.
# Chuyển đổi Wide_Long (pivot_longer)
valuation_ratios_long <- nyse_clean %>%
# Chọn các cột so sánh
select(investment, PE_ratio, PB_ratio, PS_ratio) %>%
# Thực hiện pivot_longer
pivot_longer(
# Chọn các cột chuyển thành hàng
cols = c(PE_ratio, PB_ratio, PS_ratio),
# Tên cột mới chứa tên tỷ suất (PE_ratio, PB_ratio, PS_ratio)
names_to = "Ratio_Type",
# Tên cột mới chứa giá trị tương ứng của tỷ suất
values_to = "Ratio_Value"
)
# Xem 10 hàng đầu tiên để kiểm tra sự chuyển đổi
print(head(valuation_ratios_long, 10))## # A tibble: 10 × 3
## investment Ratio_Type Ratio_Value
## <fct> <chr> <dbl>
## 1 BAD PE_ratio 12.6
## 2 BAD PB_ratio 3.19
## 3 BAD PS_ratio 0.38
## 4 GOOD PE_ratio 11.4
## 5 GOOD PB_ratio 0.54
## 6 GOOD PS_ratio 1.71
## 7 BAD PE_ratio 10.6
## 8 BAD PB_ratio 2.6
## 9 BAD PS_ratio 1.67
## 10 BAD PE_ratio 11.1
# Loại bỏ giá trị quá lớn để biểu đồ hộp không bị nén quá mức
# Giả sử chỉ quan tâm đến các giá trị nhỏ hơn 100 để thấy rõ sự khác biệt
valuation_ratios_filtered <- valuation_ratios_long %>%
filter(Ratio_Value < 100)
# Vẽ Biểu đồ Hộp
ggplot(valuation_ratios_filtered, aes(x = Ratio_Type, y = Ratio_Value, fill = investment)) +
geom_boxplot(outlier.shape = NA) + # Loại bỏ outliers trên biểu đồ để làm nổi bật hộp
scale_y_continuous(labels = comma) + # Dùng dấu phẩy cho trục Y
labs(
title = "So sánh Phân bố Tỷ suất Định giá theo Kết quả Đầu tư",
subtitle = "Dữ liệu được lọc để Ratio_Value < 100",
x = "Loại Tỷ suất Định giá",
y = "Giá trị Tỷ suất",
fill = "Kết quả"
) +
theme_minimal() +
theme(plot.title = element_text(face = "bold"))Nhận xét biểu đồ hộp
Biểu đồ hộp sau khi đã loại bỏ các outliers cực lớn để tăng tính trực quan cho ta thấy được vài những thông tin như sau:
Về Mức độ định giá (Trung vị - Median)
PE_ratio (Price-to-Earnings): Trung vị (Median) của PE là cao nhất trong ba tỷ suất. Điều này cho thấy giá cổ phiếu chủ yếu được xác định bởi lợi nhuận (Earnings).
PB_ratio (Price-to-Book): Trung vị thấp hơn PE nhưng cao hơn PS.
PS_ratio (Price-to-Sales): Trung vị là thấp nhất, phù hợp với bản chất của tỷ suất P/S.
Về Sức mạnh dự báo (GOOD vs. BAD)
Mục tiêu chính là xem tỷ suất nào có khả năng phân biệt được khoản đầu tư GOOD và BAD một cách tốt nhất (tức là hộp GOOD và hộp BAD phải tách biệt nhau rõ rệt):
PE_ratio: Quan sát cho thấy hộp GOOD và hộp BAD có không có sự khác biệt lắm ở mức trung vị. Điều này ngụ ý rằng, chỉ riêng PE_ratio không phải là yếu tố dự báo mạnh mẽ để phân loại một khoản đầu tư là tốt hay xấu.
PB_ratio: Tương tự PE, không có sự khác biệt vẫn còn khá lớn.
PS_ratio: Tỷ suất này thường cho thấy sự khác biệt rõ rệt nhất về trung vị giữa hộp GOOD và BAD.
Về Tính biến động (Phạm vi)
** Kết luận trực quan:** Việc trực quan hóa này gợi ý rằng PS_ratio có thể là tỷ suất định giá có khả năng phân biệt tốt hơn so với PE và PB, hoặc ít nhất là cần phải xem xét kỹ lưỡng hơn trong mô hình định lượng. Việc phân tích phân bố trực quan này là tiền đề quan trọng để chọn lựa các biến định giá phù hợp nhất.
nyse: tập dữ liệu gốc.
nyse_clean: Tập dữ liệu chính đã được làm sạch và bổ sung các biến mới.
nyse_summary_annual: Bảng tổng hợp hiệu suất theo ngành và năm.
valuation_ratios_long: Bảng dữ liệu dạng dài (long format) cho trực quan hóa.
# Lưu các tập dữ liệu
save(nyse_clean, nyse_summary_annual, valuation_ratios_long,
file = "nyse_processed_final.RData")
# Xác nhận việc lưu file
cat("✅ Đã hoàn tất và lưu trữ dữ liệu sạch vào file: nyse_processed_final.RData\n")## ✅ Đã hoàn tất và lưu trữ dữ liệu sạch vào file: nyse_processed_final.RData
Chuẩn hóa dữ liệu: Xử lý lỗi, xử lý NA và chuẩn hóa các biến liên tục như PE_ratio (tạo log_PE).
Tạo Biến Giá trị:
Tạo các tỷ số tài chính cốt lõi (Leverage_Ratio) và biến kinh tế (Real_Return).
Tạo các biến chiến lược (Holding_Period) và chu kỳ thời gian (Buy_Year, Buy_Quarter).
Chuẩn bị mô hình và phân tích chuỗi thời gian:
Tổng hợp dữ liệu theo nhóm và tạo biến trễ (Lagged_Mean_Return) để phân tích ảnh hưởng của quá khứ.
Chuyển đổi dữ liệu sang dạng dài (pivot_longer) phục vụ cho trực quan hóa so sánh.
Tập dữ liệu nyse_clean và nyse_summary_annual hiện là cơ sở để tiến hành kiểm định giả thuyết thống kê và xây dựng mô hình dự báo trong các chương sau.
# Tải các gói thư viện cần thiết
library(tidyverse)
library(scales)
library(corrplot)
# Tải dữ liệu đã xử lý từ Chương 3
load("nyse_processed_final.RData")
cat("✅ Đã tải các gói thư viện và tập dữ liệu nyse_clean, nyse_summary_annual.\n")## ✅ Đã tải các gói thư viện và tập dữ liệu nyse_clean, nyse_summary_annual.
Trong hệ sinh thái R, ggplot2 là gói
thư viện tiêu cho việc tạo ra các đồ thị phân tích chất lượng cao.
ggplot2 được xây dựng dựa trên triết lý (Grammar of
Graphics), một hệ thống chính thức mô tả cách các thành phần
của một biểu đồ được kết hợp với nhau.
Triết lý này cho rằng mọi biểu đồ đều có thể được xây dựng bằng cách kết hợp một cách có hệ thống các thành phần sau:
Dữ liệu (Data): Tập dữ liệu cần trực quan hóa
(nyse_clean).
Ánh xạ thẩm mỹ (Aesthetic Mappings -
aes()): Xác định cách các biến dữ liệu được ánh xạ
tới các thuộc tính nhìn thấy được của biểu đồ, như trục x, trục y, màu
sắc (color), kích thước (size), hình dạng
(shape).
Đối tượng hình học (Geometric Objects -
geom_...()): Các hình dạng cụ thể được sử dụng để
vẽ dữ liệu, ví dụ: geom_point() (điểm tán xạ),
geom_line() (đường), geom_boxplot() (biểu đồ
hộp).
Các lớp phụ trợ (Scales, Coordinates, Facets, Themes):
scale_y_continuous để định dạng trục Y).facet_wrap).Trực quan hóa dữ liệu trong tiểu luận này có ba mục tiêu chính, tập trung vào các biến đã được làm sạch và tạo ra trong chương 3:
| Mục tiêu Chính | Biến Phân tích | Câu hỏi Phân tích |
|---|---|---|
| Phân bố | Real_Return, log_PE |
Phân bố Lợi suất thực tế có bị lệch không? Việc chuẩn hóa có thành công? |
| Mối quan hệ | Real_Return vs. Volatility,
Leverage_Ratio |
Có mối quan hệ đánh đổi Lợi suất-Rủi ro không? Đòn bẩy có khuếch đại lợi nhuận? |
| So sánh hiệu suất nhóm | sector, Buy_Year,
Holding_Period |
Ngành nào (sector) mang lại lợi suất tốt nhất? Hiệu suất thay đổi như thế nào qua các năm? |
Sử dụng biểu đồ mật độ (Density Plot) để so sánh trực quan sự khác biệt giữa lợi suất danh nghĩa và lợi suất thực tế (đã điều chỉnh lạm phát).
# Chuyển dữ liệu lợi suất sang dạng dài (long format) để dễ dàng trực quan hóa
return_comparison_long <- nyse_clean %>%
select(nominal_return, Real_Return) %>%
# Giới hạn phạm vi xem (ví dụ: từ -25% đến 25%) để tập trung vào phần trung tâm, loại bỏ các outliers cực lớn
filter(nominal_return > -0.25 & nominal_return < 0.25) %>%
pivot_longer(
cols = everything(),
names_to = "Return_Type",
values_to = "Return_Value"
)
# Vẽ Biểu đồ Mật độ (Density Plot)
ggplot(return_comparison_long, aes(x = Return_Value, fill = Return_Type)) +
geom_density(alpha = 0.6) + # Sử dụng alpha để làm trong suốt, dễ quan sát sự chồng lấn
labs(
title = "Hình 4.2.1. So sánh Phân bố Lợi suất Danh nghĩa và Lợi suất Thực tế",
subtitle = "Phân bố tập trung mạnh ở gần 0 (giới hạn từ -25% đến 25%)",
x = "Lợi suất",
y = "Mật độ",
fill = "Loại Lợi suất"
) +
# Thêm đường thẳng đứng tại x=0
geom_vline(xintercept = 0, linetype = "dashed", color = "red") +
scale_x_continuous(labels = percent) + # Định dạng trục x là phần trăm
theme_minimal(base_size = 13) +
theme(legend.position = "top")Hình 4.2.1 (Biểu đồ mật độ) minh họa sự dịch chuyển của lợi suất do ảnh hưởng của lạm phát, đây là một minh chứng trực quan quan trọng cho tầm quan trọng của việc điều chỉnh lạm phát.
Ảnh hưởng của lạm phát: Đường phân bố của Real_Return (xanh lam) bị dịch chuyển rõ rệt sang trái so với nominal_return (đỏ hồng). Đỉnh (Mode) của Real_Return nằm ở giá trị lợi suất âm nhỏ, trong khi đỉnh của nominal_return nằm sát hoặc hơi dương. Điều này cho thấy lạm phát (CPI) đã làm suy giảm sức mua của lợi nhuận. Điều này khẳng định cần sử dụng Real_Return làm biến phụ thuộc chính xác nhất, vì nó phản ánh sự tăng trưởng giá trị kinh tế thực tế.
Tính lệch (Skewness): Cả hai phân bố đều lệch phải mạnh (đuôi đồ thị kéo dài sang phía dương). Sự lệch phải cho thấy phần lớn các giao dịch có lợi suất thấp, nhưng tồn tại một số ít giao dịch siêu lợi nhuận (fat tails) kéo giá trị trung bình lên. Đây là đặc điểm điển hình của dữ liệu thị trường chứng khoán.
Độ nhọn (Kurtosis): Cả hai phân bố đều có đỉnh rất nhọn và hẹp (Leptokurtic) so với phân bố chuẩn. Độ nhọn cao ngụ ý rủi ro rơi vào các sự kiện cực đoan (lỗ/lãi rất lớn) cao hơn mức dự đoán của lý thuyết phân bố chuẩn (dễ gặp trong các mô hình rủi ro).
Sử dụng biểu đồ thanh (Bar Chart) để minh họa tần suất (Count) hoặc tỷ trọng (Percentage) của các chiến lược đầu tư theo thời gian nắm giữ (đã phân loại trong Mục 3.3.1).
# Vẽ Biểu đồ Thanh (Bar Chart)
ggplot(nyse_clean, aes(x = Holding_Period, fill = Holding_Period)) +
geom_bar(stat = "count", show.legend = FALSE) + # geom_bar() mặc định dùng stat="count"
# Thêm nhãn số lượng trên đỉnh mỗi thanh
geom_text(stat = 'count', aes(label = comma(..count..)), vjust = -0.5, size = 4) +
labs(
title = "Hình 4.2.2. Tần suất Khoản đầu tư theo Thời gian Nắm giữ (Chiến lược)",
x = "Thời gian Nắm giữ (Holding Period)",
y = "Số lượng Quan sát (Giao dịch)"
) +
scale_y_continuous(labels = comma) + # Định dạng trục y bằng dấu phẩy
theme_minimal(base_size = 13)Hình 4.2.2 (Biểu đồ Thanh) cho thấy sự phân bổ của các chiến lược đầu tư theo thời gian, giúp xác định các nhóm chiến lược chính được phân tích.
Chiến lược phổ biến nhóm Long-term (>180 days): có số lượng giao dịch cao nhất (147,526). Khẳng định chiến lược mua và giữ (Buy and Hold) là phong cách chiếm ưu thế, thường được áp dụng bởi các nhà đầu tư lớn hoặc các quỹ tìm kiếm tăng trưởng giá trị cốt lõi.
Tính đại diện: Ba nhóm có sự phân bổ tương đối đồng đều: Long-term (147.5K), Short-term (135.0K), Mid-term (122.7K). Bộ dữ liệu này là mẫu đại diện tốt cho đa dạng các hoạt động đầu tư, từ giao dịch chủ động (Short/Mid-term) đến đầu tư thụ động (Long-term). Điều này có lợi cho việc so sánh hiệu suất giữa các chiến lược trong các mô hình thống kê tiếp theo.
Kiểm tra trực quan sự thành công của phép biến đổi logarit bằng biểu đồ Histogram trên biến log_PE mới tạo ra.
# Vẽ Biểu đồ Histogram của log_PE
ggplot(nyse_clean, aes(x = log_PE)) +
geom_histogram(bins = 40, fill = "#1F77B4", color = "white") +
# Thêm đường mật độ để làm mịn hình dạng phân bố
geom_density(aes(y = after_stat(count) * diff(range(nyse_clean$log_PE, na.rm = TRUE)) / 40),
color = "red", linetype = "dashed") +
labs(
title = "Hình 4.2.3. Phân bố Tỷ suất P/E sau khi Chuẩn hóa Logarit (`log_PE`)",
x = "Giá trị log(PE Ratio)",
y = "Tần suất"
) +
theme_minimal(base_size = 13)Hiệu quả chuẩn hóa: Phân bố của log_PE đã trở nên tương đối đối xứng và tập trung quanh giá trị trung tâm (đỉnh phân bố nằm khoảng 2.5 đến 3.5). Mục tiêu chuẩn hóa đã đạt được. Việc này làm giảm thiểu ảnh hưởng của các outliers cực lớn, và đưa phân bố tiến gần hơn đến giả định phân bố chuẩn của mô hình hồi quy tuyến tính.
Phạm vi giá trị: Phân bố tập trung mạnh mẽ trong khoảng 1 đến 4 trên thang logarit (tương đương P/E từ \(e^1≈2.7\) đến \(e^4≈54.6\)). Điều này xác nhận đây là phạm vi định giá phổ biến nhất. Các giá trị log_PE>6 (tương đương P/E>400) vẫn tồn tại nhưng có tần suất rất thấp, cho thấy vẫn còn một lượng nhỏ công ty được định giá cực cao.
Sử dụng biểu đồ tán xạ giữa lợi suất thực tế (Real_Return) và rủi ro (Volatility_Buy), phân màu theo kết quả đầu tư (investment) (GOOD/BAD).
# Lọc dữ liệu để tập trung vào phạm vi Real_Return hợp lý (ví dụ: -0.5 đến 0.5)
# để biểu đồ không bị nén quá mức do outliers cực lớn
nyse_filtered_scatter <- nyse_clean %>%
filter(Real_Return > -0.5 & Real_Return < 0.5)
# Vẽ biểu đồ tán xạ
ggplot(nyse_filtered_scatter,
aes(x = Volatility_Buy, y = Real_Return, color = investment)) +
geom_point(alpha = 0.2, size = 1) + # Dùng alpha thấp do số lượng quan sát lớn
geom_smooth(method = "lm", se = FALSE, color = "black", linetype = "dashed", linewidth = 0.7) + # Thêm đường hồi quy chung
labs(
title = "Hình 4.3.1. Mối quan hệ Đánh đổi Rủi ro và Lợi suất Thực tế",
subtitle = "Dữ liệu lọc Real Return từ -50% đến 50%. Màu sắc phân loại theo kết quả đầu tư (GOOD/BAD)",
x = "Rủi ro tại thời điểm mua (Volatility_Buy)",
y = "Lợi suất Thực tế (Real_Return)",
color = "Kết quả Đầu tư"
) +
scale_y_continuous(labels = percent) + # Định dạng trục y là phần trăm
theme_minimal(base_size = 13)
### 4.3.2. Mối quan hệ giữa Đòn bẩy và Hiệu suất (Leverage
vs. Real Return)
# Lọc dữ liệu hợp lý (loại bỏ các giá trị NA và ngoại lai quá lớn)
leverage_plot_data <- nyse_clean %>%
filter(!is.na(Leverage_Ratio),
Leverage_Ratio < 20,
Real_Return > -0.5 & Real_Return < 0.5)
# Biểu đồ tán xạ Leverage Ratio vs Real Return
ggplot(leverage_plot_data, aes(x = Leverage_Ratio, y = Real_Return, color = investment)) +
geom_point(alpha = 0.3, size = 1) +
geom_smooth(method = "lm", color = "black", linetype = "dashed", se = FALSE) +
labs(
title = "Hình 4.3.2. Mối quan hệ giữa Đòn bẩy Tài chính (Leverage Ratio) và Lợi suất Thực tế",
subtitle = "Biểu đồ thể hiện mối tương quan giữa mức đòn bẩy và hiệu quả sinh lời sau điều chỉnh lạm phát",
x = "Tỷ lệ Đòn bẩy Tài chính (Leverage Ratio)",
y = "Lợi suất Thực tế (Real Return)",
color = "Kết quả Đầu tư"
) +
scale_y_continuous(labels = percent) +
theme_minimal(base_size = 13)
Nhận xét Mối tương quan giữa Leverage và Real Return
cho thấy rằng đòn bẩy cao thường đi kèm với rủi ro lớn hơn. Các điểm có
Leverage > 10 có xu hướng dao động mạnh hơn về lợi suất thực tế.
Đường hồi quy tuyến tính dương nhẹ cho thấy đòn bẩy có thể khuếch đại
lợi nhuận, nhưng hiệu ứng này không tuyến tính và dễ bị biến động bởi
các yếu tố ngoại sinh.
ggplot(nyse_clean, aes(x = sector, y = Real_Return, fill = sector)) +
geom_boxplot(outlier.alpha = 0.2) +
coord_flip() +
labs(
title = "Hình 4.4.1. Phân bố Lợi suất Thực tế theo Ngành nghề",
subtitle = "So sánh mức sinh lời trung bình và phân tán giữa các nhóm ngành",
x = "Ngành nghề (Sector)",
y = "Lợi suất Thực tế (Real Return)"
) +
scale_y_continuous(labels = percent) +
theme_minimal(base_size = 13) +
theme(legend.position = "none")Nhận xét Ngành Technology và Finance có phân bố lợi suất cao nhất, thể hiện sức tăng trưởng mạnh mẽ. Ngược lại, các ngành Utilities và Manufacturing có lợi suất ổn định nhưng thấp hơn, minh chứng cho sự đánh đổi giữa rủi ro và lợi nhuận
ggplot(nyse_summary_annual, aes(x = Buy_Year, y = Mean_Return, color = sector)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
labs(
title = "Hình 4.4.2. Xu hướng Lợi suất Trung bình theo Năm và Ngành nghề",
subtitle = "Theo dõi biến động lợi suất trong giai đoạn 2013–2018",
x = "Năm giao dịch (Buy Year)",
y = "Lợi suất trung bình (Mean Return)"
) +
scale_y_continuous(labels = percent_format(scale = 1)) +
theme_minimal(base_size = 13)
Nhận xét Biểu đồ thể hiện sự dao động theo chu kỳ rõ
rệt: các năm 2015–2016 là giai đoạn lợi suất cao nhất, trong khi 2018
ghi nhận mức suy giảm mạnh. Sự biến động đồng pha giữa các ngành cho
thấy ảnh hưởng chung của yếu tố vĩ mô (như lãi suất, lạm phát, chính
sách tài chính).
ggplot(nyse_summary_annual, aes(x = Buy_Year, y = Rank_by_Year, color = sector, group = sector)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_y_reverse(breaks = 1:10) +
labs(
title = "Hình 4.4.3. Xếp hạng Hiệu suất Lợi suất Trung bình theo Năm và Ngành",
subtitle = "Ngành có hạng thấp hơn tương ứng với hiệu suất đầu tư cao hơn (1 = tốt nhất)",
x = "Năm giao dịch (Buy Year)",
y = "Thứ hạng Hiệu suất (Rank_by_Year)"
) +
theme_minimal(base_size = 13)
Nhận xét Biểu đồ thứ hạng giúp nhận diện các ngành có
tính bền vững trong lợi nhuận qua thời gian. Ngành BANK duy trì vị trí
dẫn đầu giai đoạn 2014–2016, trong khi FMCG giữ mức ổn định ở nhóm giữa,
phản ánh đặc tính phòng thủ của hàng tiêu dùng.
ggplot(valuation_ratios_filtered, aes(x = Ratio_Type, y = Ratio_Value, fill = investment)) +
geom_boxplot(outlier.shape = NA) +
labs(
title = "Hình 4.5.1. So sánh Phân bố các Tỷ suất Định giá (PE, PB, PS) theo Loại Đầu tư",
subtitle = "Dữ liệu lọc với Ratio_Value < 100 để loại bỏ các giá trị cực lớn",
x = "Loại Tỷ suất Định giá",
y = "Giá trị Tỷ suất"
) +
theme_minimal(base_size = 13)
Nhận xét Nhóm GOOD investment có xu hướng có PE và PB
ratio thấp hơn, cho thấy mức định giá hợp lý hơn so với nhóm BAD. Tỷ
suất PS_ratio thể hiện khả năng phân biệt rõ rệt nhất giữa hai nhóm, gợi
ý rằng doanh thu đóng vai trò then chốt trong việc xác định hiệu suất
đầu tư.
# Chọn các biến định lượng để tính ma trận tương quan
numeric_vars <- nyse_clean %>%
select(nominal_return, Real_Return, Volatility_Buy, log_PE, Leverage_Ratio, Sharpe.Ratio, roe_ratio, roa_ratio)
# Ma trận tương quan
corr_matrix <- cor(numeric_vars, use = "pairwise.complete.obs")
# Trực quan hóa bằng corrplot
corrplot::corrplot(
corr_matrix,
method = "color",
type = "upper",
tl.col = "black",
addCoef.col = "black",
title = "Hình 4.5.2. Biểu đồ Heatmap Tương quan giữa các biến định lượng",
mar = c(0,0,2,0)
)
Nhận xét
Ma trận tương quan cho thấy:
ROA và ROE có tương quan dương rất mạnh (r > 0.8).
Real_Return có tương quan dương nhẹ với Sharpe Ratio (r ≈ 0.4), phản ánh mối quan hệ giữa hiệu suất điều chỉnh rủi ro và lợi nhuận thực tế.
Volatility_Buy có tương quan âm với Real_Return, minh chứng cho quy luật “rủi ro cao – lợi nhuận không đảm bảo”.