CHƯƠNG 1. KHÁM PHÁ VÀ MÔ TẢ DỮ LIỆU (DATA EXPLORATION & DESCRIPTION)

1.1. Tổng quan về Bộ Dữ liệu (Dataset Overview)

1.1.1. Giới thiệu chung và Mục tiêu tiểu luận (Introduction & Objectives)

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ỹ.

1.1.2. Cấu trúc và Đặc điểm bộ Dữ liệu (Structure and Characteristics)

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:

  • Biến định danh:
    • X: chỉ số dòng dữ liệu.
    • company: mã công ty (ví dụ: BAC, JPM, FB…).
    • sector: lĩnh vực hoạt động (BANK, TECH, FMCG, RETAIL…).
  • Biến giao dịch:
    • horizon..days.: số ngày nắm giữ đầu tư.
    • amount: số tiền đầu tư.
    • date_BUY_fix, date_SELL_fix: ngày mua và ngày bán.
    • price_BUY, price_SELL: giá mua và giá bán cổ phiếu.
  • Biến lợi suất và rủi ro:
    • nominal_return: tỷ suất lợi nhuận danh nghĩa.
    • expected_return..yearly.: lợi suất kỳ vọng hàng năm.
    • Volatility_Buy, Volatility_sell: độ biến động giá.
    • Sharpe.Ratio: tỷ suất lợi nhuận điều chỉnh rủi ro.
  • Biến tài chính của doanh nghiệp:
    • PE_ratio, PB_ratio, EPS_ratio, PS_ratio: các tỷ số định giá cơ bản.
    • current_ratio, roa_ratio, roe_ratio: chỉ tiêu thanh khoản và hiệu quả sinh lời.
    • NetProfitMargin_ratio: tỷ suất lợi nhuận ròng.
    • ESG_ranking: xếp hạng bền vững ESG.
    • investment: phân loại kết quả đầu tư (GOOD/BAD).

1.1.3. Tóm tắt cấu trúc tiểu luận (Report Structure Summary)

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:

  1. R Fundamentals – Làm quen cú pháp, cấu trúc dữ liệu, và thao tác cơ bản.

  2. Data Manipulation – Biến đổi, gộp nhóm, lọc và xử lý dữ liệu.

  3. Data Visualization – Trực quan hóa bằng biểu đồ cơ bản và ggplot2.

  4. Statistical Analysis – Phân tích thống kê mô tả và suy luận.

  5. Machine Learning – Xây dựng và đánh giá mô hình học máy cơ bản.

  6. Working with Big Data – Ứng dụng data.table và SparkR.

  7. Reporting and Communication – Tạo báo cáo và dashboard bằng R Markdown.

  8. Advanced R Programming – Viết hàm, vòng lặp, xử lý logic nâng cao.

  9. Specialized Packages and Techniques – Áp dụng các gói mở rộng (lubridate, stringr, caret, …).

  10. Case Studies and Applications – Phân tích tình huống thực tế từ bộ dữ liệu NYSE.

1.2. Kiểm tra cấu trúc và Chất lượng dữ liệu (Data Structure & Quality Check)

1.2.1. Tổng quan dữ liệu sau tiền xử lý sơ bộ (Post-Processing Data Summary)

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.

# Tóm tắt nhanh dữ liệu
skim(nyse)
Data summary
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 ▁▁▁▇▃
# Mô tả các biến định lượng
summary(select_if(nyse, is.numeric))
##        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át25 biến, trong đó có 5 biến định tính (factor)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ể:

  • Lợi suất danh nghĩa (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.
  • Lợi suất kỳ vọng hàng năm (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.
  • Độ biến động giá (Volatility_BuyVolatility_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:

  • PE ratio (Price to Earnings) có giá trị trung bình 30.33, với một số cổ phiếu có PE rất cao (tối đa hơn 1100), biểu thị khả năng định giá cao vượt trội hoặc biến động bất thường.
  • EPS ratio (Earnings per Share) trung bình 3.44, nằm trong vùng hợp lý, nhưng xuất hiện một vài giá trị âm thể hiện doanh nghiệp lỗ.
  • PB ratio (Price to Book) có giá trị trung bình 4.69, với cực đại 47.62, cho thấy có một số công ty được thị trường định giá cao hơn nhiều so với giá trị sổ sách.
  • Net Profit Margin trung bình 9.20%, dao động từ -24.6% đến 62%, chứng tỏ sự khác biệt rõ giữa các doanh nghiệp hiệu quả và doanh nghiệp yếu kém.
  • ROA (Return on Assets)ROE (Return on Equity) có giá trị trung bình lần lượt là 5.6%15.6%, phản ánh hiệu quả sinh lời ở mức trung bình khá.

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.

1.3. Phân tích thống kê mô tả theo Nhóm (Grouped Descriptive Statistics)

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.3.1. Thống kê theo ngành nghề (Analysis by Sector)

# 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
  )
Bảng 1.3.1. Thống kê mô tả theo ngành nghề
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ả.

1.3.2. Thống kê theo phân loại đầu tư (Analysis by Investment Classification)

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
  )
Bảng 1.3.2. Thống kê mô tả theo loại khoản đầu tư
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á.

1.4. Phân tích phân bố và mối quan hệ giữa các biến (Distribution & Relationship Analysis)

1.4.1. Phân tích phân bố tỷ suất Lợi nhuận (Nominal Return Distribution)

# 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)

# Tính các thống kê cơ bản
summary(nyse$nominal_return)
##     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.

1.4.2. So sánh độ biến động giá (Volatility Comparison)

# 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.

1.4.3. Mối quan hệ giữa Hiệu quả Sinh lời (ROA vs ROE Relationship)

# 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.

CHƯƠNG 2: NỀN TẢNG R VÀ CÚ PHÁP CƠ BẢN (R FUNDAMENTALS & BASE R SYNTAX)

2.1. Đọc và kiểm tra dữ liệu ban đầu (Data Loading & Initial Check)

2.1.1. Đọc dữ liệu (Data Loading and Import)

# Đọc dữ liệu
nyse <- read.csv("C:/Users/Admin/Documents/NGÔN NGỮ R/final_transactions_dataset.csv", stringsAsFactors = TRUE, header = TRUE, na.strings = c("", "NA"))

2.1.2. Kiểm tra kích thước và Tổng quan (Dimension and Head Check)

# Kiểm tra kích thước dữ liệu
cat("Số quan sát:", nrow(nyse), "\n")
## Số quan sát: 405258
cat("Số biến:", ncol(nyse), "\n")
## Số biến: 25
# Kiểm tra cấu trúc và 6 dòng đầu
str(nyse)
## '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 ...
head(nyse)

2.2. Các Cấu trúc dữ liệu cơ bản (Fundamental Data Structures)

2.2.1 Cấu trúc Vector và truy cập phần tử (Vector Structure and Indexing)

# 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

2.2.2 Làm việc với dữ liệu nhân tố (Factors) (Working with Factor Data)

# 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

2.3. Thao tác và tính toán cơ bản (Basic Data Manipulation and Calculation)

2.3.1. Truy cập dữ liệu theo tên cột (Column Access by Name)

# 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

2.3.2. Sử dụng các toán tử Logic/So sánh (Logic/Comparison Operators)

# Á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

2.3.3. Lọc Dữ liệu bằng Base R (Base R Data Filtering)

# Lọc dữ liệu bằng Base R
positive_returns <- nyse[nyse$nominal_return > 0 & !is.na(nyse$nominal_return), ]

cat("Số lượng khoản đầu tư có lợi nhuận dương:", nrow(positive_returns), "\n")
## Số lượng khoản đầu tư có lợi nhuận dương: 241064

2.4. Ứng dụng hàm thống kê và Biến đổi kiểu dữ liệu (Statistical Functions & Data Type Conversion)

2.4.1 Sử dụng các hàm thống kê cơ bản (Basic Statistical Functions)

# 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
cat("Độ lệch chuẩn Lợi suất danh nghĩa:", round(sd_return, 4), "\n")
## Độ lệch chuẩn Lợi suất danh nghĩa: 0.2988

2.4.2 Thao tác và Chuyển đổi dữ liệu thời gian (Time Data Manipulation and Conversion)

# 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
cat("Phạm vi ngày mua:", as.character(range(nyse$date_BUY_fix_DATE, na.rm = TRUE)), "\n")
## 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

2.5. Kiểm tra chất lượng dữ liệu cơ bản (Basic Data Quality Check)

2.5.1 Kiểm tra bản ghi trùng lặp (Duplicate Records Check)

# 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

2.5.2 Kiểm tra giá trị Khuyết thiếu (NA) (Missing Value (NA) Check)

# 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
print(na_count_per_column[na_count_per_column > 0])
## named numeric(0)

CHƯƠNG 3: THAO TÁC VÀ CHUẨN BỊ DỮ LIỆU (DATA MANIPULATION & PREPARATION)

3.1. Làm sạch và chọn lọc tập dữ liệu chính (Cleaning and Core Selection)

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ữ).

3.2. Chuẩn hóa và tạo biến giá trị (Normalization and Feature Engineering)

3.2.1. Chuẩn hóa tỷ suất định giá (Log Transformation)

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
summary(nyse_clean$log_PE)
##    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.

  1. Phân bố ban đầu (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_ratiocự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.
  1. Phân bố sau khi chuẩn hóa (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.

3.2.2. Tạo biến đòn bẩy tài chính (Leverage Ratio)

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ả

  1. Mức độ Sử dụng Đòn bẩy (Min > 1):
  • 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ố.

  1. Phân bố Đòn bẩy:
  • 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.

  1. Giá trị Ngoại lai (Outliers) và Giá trị khuyết thiếu (NA’s):
  • 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.

3.3. Thao tác với dữ liệu thời gian và phân loại chiến lược (Time & Strategy Feature Engineering)

3.3.1. Phân loại khoản đầu tư theo thời gian nắm giữ

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.

3.3.2. Trích xuất chu kỳ thời gian (Quý và Năm)

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)
cat("Phạm vi Năm mua:", range(nyse_clean$Buy_Year, na.rm = TRUE), "\n")
## Phạm vi Năm mua: 2013 2018

Nhận xét

  1. Ý 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ìnhrủ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).

  2. Ý 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.

3.3.3. Ghép dữ liệu lạm phát và tính lợi suất thực tế

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):
nyse_clean %>%
  select(Buy_Year, Inflation_Rate, nominal_return, Real_Return) %>%
  head(5)
cat("\nThống kê Lợi suất thực tế (Real_Return):\n")
## 
## Thống kê Lợi suất thực tế (Real_Return):
summary(nyse_clean$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

  1. Phân tích kết quả (5 hàng đầu tiên)
  • 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.

  1. Phân tích thống kê lợi suất thực tế (Real_Return)
  • 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.

3.4. Tổng hợp, lọc và tạo biến trễ (Aggregation, Filtering & Lagged Variables)

3.4.1. Lọc và sắp xếp dữ liệu theo nhiều tiêu chí

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

  1. Ý nghĩa chiến lược lọc

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ế.

  1. Phân tích Kết quả Lọc

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.

3.4.2. Tổng hợp và xếp hạng hiệu suất theo chu kỳ

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:
nyse_summary_annual %>%
  filter(Buy_Year == 2017) %>%
  arrange(Rank_by_Year)

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.

  1. Phân tích xu hướng ngành theo thời gian
  • 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.

  1. Phân tích tương quan lợi suất – rủi ro
  • 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.

  1. Phân tích xếp hạng tương đối (Rank_by_Year)

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):

    • Cả AUTO (−3.58%) và BANK (−2.97%) đều có lợi suất âm, cho thấy chúng là những ngành dễ bị ảnh hưởng bởi suy thoái kinh tế. Ngành nào có Rank tốt hơn trong năm này sẽ là ngành “tổn thất ít nhất”.

3.4.3. Tạo biến trễ (Lagged Return)

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.

3.5. Chuyển đổi dạng dữ liệu cho trực quan hóa (Pivot Longer)

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

3.5.1. Trực quan hoá so sánh phân bố: Biểu đồ Boxplot

# 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)

    • Cả ba tỷ suất đều cho thấy phạm vi lớn (ngay cả khi đã lọc outliers), đặc biệt là PE_ratio và PB_ratio, chứng tỏ sự phân tán lớn trong định giá của các công ty trên sàn.

** 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.

3.6. Lưu trữ dữ liệu đã xử lý

  • 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.

CHƯƠNG 4: TRỰC QUAN HÓA DỮ LIỆU (DATA VISUALIZATION)

4.1. Tổng quan về nguyên lý trực quan hóa (Introduction to Visualization Principles)

# 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.

4.1.1. Giới thiệu gói ggplot2 (Grammar of Graphics).

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:

  1. Dữ liệu (Data): Tập dữ liệu cần trực quan hóa (nyse_clean).

  2. Á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).

  3. Đố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).

  4. Các lớp phụ trợ (Scales, Coordinates, Facets, Themes):

    • Scales: Kiểm soát cách dữ liệu được ánh xạ (ví dụ: scale_y_continuous để định dạng trục Y).
    • Facets: Phân chia biểu đồ thành nhiều ô con dựa trên một biến phân loại (facet_wrap).

4.1.2. Mục tiêu trực quan hóa trong phân tích dữ liệu đầu tư

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?

4.2. Trực quan hóa phân bố và tần suất (Distribution and Frequency)

4.2.1. Phân bố lợi suất thực tế (Real_Return) và lợi suất danh nghĩa

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).

4.2.2. Phân bố thời gian nắm giữ (Holding_Period)

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.

4.2.3. Phân bố định giá chuẩn hóa (log_PE)

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.

4.3. Trực quan hóa mối quan hệ giữa các biến (Relationship Visualization)

**4.3.1. Phân tán giữa lợi suất và rủi ro (Return vs. Volatility)

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.

4.4. Trực quan hóa So sánh Theo Nhóm và Chu kỳ (Grouped Comparison and Time Series)

4.4.1. So sánh hiệu suất (Real_Return) theo Ngành nghề (Sector)

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

4.4.2. Phân tích Chuỗi thời gian Lợi suất Trung bình theo Năm

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).

4.4.3. Trực quan hóa Xếp hạng Tương đối của Ngành (Ranked Sector Chart)

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.

4.5. Trực quan hóa Nâng cao (Advanced Visualization)

4.5.1. So sánh Tỷ suất Định giá theo Loại Đầu tư

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ư.

4.5.2. Biểu đồ Heatmap Tương quan giữa các biến định lượng

# 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”.