ĐỀ TÀI: LẬP TRÌNH DỮ LIỆU VỚI GÓI GGPLOT2 TRÊN R PROGRAMMING

1 CHƯƠNG 1: GIỚI THIỆU VỀ TRỰC QUAN HÓA DỮ LIỆU VỚI GGPLOT2.

1.1 Đặt vấn đề

Trong thời đại 4.0, việc phân tích dữ liệu trở nên phổ biến ở hầu hết mọi lĩnh vực bao gồm tài chính, y tế, xã hội, khoa học… và được đa số quốc gia trên thế giới đặc biệt quan tâm đến việc phát triển chuyên môn và đào tạo nguồn nhân lực. Các ngành nghề liên quan có thể kể đến như là data science, data anlalyst, data engineer… Trong đó, việc trục quan hóa dữ liệu là không thể thiếu đối với những ngành nghề này. Ngoài ra, trực quan hóa dữ liệu là một phần không thể thiếu của nghiên cứu khoa học và trực quan hóa hiệu quả cho phép một nhà khoa học vừa hiểu dữ liệu của chính họ vừa truyền đạt những hiểu biết của họ cho những người khác (Waskom,2021). Trực quan hóa dữ liệu liên quan đến việc trình bày dữ liệu ở dạng đồ họa hoặc hình ảnh làm cho thông tin dễ hiểu, điều đó giúp giải thích mối liên hệ giữa các biến có trong biểu đồ và xác định phương hướng hành động tiếp theo (Sadiku và cộng sự, 2016). Trực quan hóa dữ liệu sẽ có lợi cho bất kỳ lĩnh vực nào của nghiên cứu đòi hỏi sự sáng tạo để trình bày thông tin lớn và phức tạp. Bài tiểu luận này trình bày một giới thiệu ngắn gọn về trực quan hóa dữ liệu.

Nhằm đáp ứng cho nhu cầu phân tích dữ liệu, gói ggplot2 ra đời. Khác với những gói vẽ đồ thị khác, ggplot2 cho phép chúng ta vẽ những đồ thị phức tạp với chất lượng hình ảnh cao và chúng ta có thê tích hợp cùng lúc nhiều thông tin trên đồ thị.

1.2 Mục tiêu và câu hỏi nghiên cứu

Mục tiêu nghiên cứu

  • Mục tiêu tổng quát: Nghiên cứu nhằm cho thấy tiềm năng của gói ggplot2 trong việc trực quan hóa dữ liệu.

  • Mục tiêu chi tiết: Nghiên cứu sử dụng package ggplot2 trong việc trực quan hóa dữ liệu các dataset có sẵn. Ngoài ra chúng tôi còn vẽ biểu đồ Việt Nam và với số liệu về tình hình dân số, mật độ dân số, tình hình COVID-19. Hơn nữa, chúng tôi còn vẽ biểu đồ thể hiện xu hướng giá của chứng khoán…

Câu hỏi nghiên cứu:

  • Package ggplot2 giúp cho biểu đồ trực quan như thế nào?

  • Package ggplot2 giúp cho việc phân tích dữ liệu trở nên dễ dàng hơn hay không?

1.3 Đối tượng nghiên cứu.

Chúng tôi thực hiện vẽ biểu đồ trực quan của các dataset có sẵn như là penguins, dữ liệu giá chứng khoán, dữ liệu dân số Việt Nam, dữ liệu COVID-19…

1.3.1 Dataset penguins

Dữ liệu penguins được cung cấp bởi Tiến sĩ Kristen Gorman và Trạm Palmer, Nam Cực. Dữ liệu thu thập các đặc điểm của các loài chim cánh cụt sống ở Nam Cực. Dữ liệu này được tích hợp trong package “palmerpenguins” bao gồm 8 biến:

  • species: các loại chim cánh cụt

  • island : hòn đảo chim cánh cụt sinh sống

  • bill_length_mm: chiều dài mỏ chim cánh cụt

  • bill_depth_mm: độ sâu mỏ chim cánh cụt

  • body_mass_g: khối lượng cơ thể chim cánh cụt

  • sex: giống (gồm đực và cái)

  • flipper_length_mm: độ dài cánh của chim cánh cụt

  • year: năm thu thập số liệu

Xử lý dữ liệu

library(palmerpenguins)

penguins <- na.omit(penguins)

1.3.2 Dataset iris

Bộ dữ liệu “iris” được nhà thực vật học và nhà phân loại học nổi tiếng người Anh Sir Ronald Aylmer Fisher sử dụng lần đầu tiên trong bài báo khoa học “The Use of Multiple Measurements in Taxonomic Problems” năm 1936. Bộ dữ liệu này là một phần của nghiên cứu về sự phân loại các loài hoa iris (cẩm chướng). Bao gồm có 5 biến như sau:

  • Sepal.Length: Độ dài đài hoa (sepal) trong cm.

  • Sepal.Width: Độ rộng đài hoa (sepal) trong cm.

  • Petal.Length: Độ dài cánh hoa (petal) trong cm.

  • Petal.Width: Độ rộng cánh hoa (petal) trong cm.

  • Species: Loài hoa iris, bao gồm ba loài “setosa”, “versicolor” và “virginica”

Xử lý dữ liệu:

iris <- na.omit(iris)

1.4 Phương pháp nghiên cứu

Chúng tôi sử dụng gói ggplot2 để vẽ biểu đồ scatter, biểu đồ cột, biểu đồ đường, biểu đồ tròn và các biểu đồ khác nhằm trực quan hóa một số biến có trong dataset được chọn và giải thích các kết quả trực quan.

1.5 Dự kiến đóng góp

Nghiên cứu sẽ đóng góp như là nguồn tài liệu tham khảo cho những ai đã và đang học tập về phần mềm Rstudio. Ngoài ra, nghiên cứu này còn cho mọi người có cái nhìn khái quát hơn về “ggplot2”

2 CHƯƠNG 2: TỔNG QUAN VỀ GGPLOT2

2.1 Các hàm geom_ vẽ 1 biến trên đồ thị

Trong R, cụ thể là gói ggplot2, hàm geom_ vẽ 1 biến biểu diễn và trực quan hóa 1 biến trên đồ thị.

2.1.1 Geom_density()

geom_density là một biểu đồ dùng để biểu diễn mật độ phân bố của một biến liên tục. Biểu đồ mật độ cung cấp cái nhìn tổng quan về phân bố của biến trong dữ liệu và cho phép bạn xác định sự tập trung của giá trị xung quanh các điểm dữ liệu.

Dưới đây là cú pháp cơ bản để sử dụng geom_density trong ggplot2:

library(ggplot2)

ggplot(data, aes(x = x_variable, color = group_variable, fill = group_variable, alpha = 0.5)) +
  geom_density(
   bw = 0.2,                    # Độ rộng của hạt nhân (bandwidth)
   adjust = 1,                  # Tham số điều chỉnh bandwidth
   kernel = "gaussian",         # Loại hạt nhân (kernel) sử dụng: "gaussian", "epanechnikov", "rectangular",...
   trim = FALSE,                # Cắt bỏ các giá trị ngoài biên của dữ liệu
   na.rm = FALSE,               # Bỏ qua các giá trị NA
   mapping = aes(group = NULL)  # Ánh xạ dữ liệu (nếu không sử dụng một group_variable)

) + labs(title = “Biểu đồ mật độ”, x = “Biến x”, y = “Mật độ”, color = “Nhóm”, fill = “Nhóm”)

Trong đó:

data: là tập dữ liệu bạn muốn trình bày.

x_variable: là tên cột trong tập dữ liệu, biểu thị trục x của biểu đồ mật độ.

group_variable: là tên cột trong tập dữ liệu, biểu thị nhóm dữ liệu (nếu có) để tô màu các đường mật độ khác nhau.

bw: Độ rộng của hạt nhân (bandwidth) xác định độ mịn của biểu đồ mật độ. Giá trị càng nhỏ thì biểu đồ càng chi tiết nhưng dễ bị nhiễu.

adjust: Tham số điều chỉnh độ rộng hạt nhân. Giá trị 1 tương ứng với hạt nhân Gaussian.

kernel: Loại hạt nhân (kernel) sử dụng cho ước tính mật độ. Một số loại hạt nhân phổ biến bao gồm “gaussian”, “epanechnikov”, “rectangular”, v.v.

trim: Nếu TRUE, sẽ cắt bỏ các giá trị ngoài biên của dữ liệu khi vẽ biểu đồ mật độ.

na.rm: Nếu TRUE, sẽ bỏ qua các giá trị NA trong dữ liệu.

mapping: Ánh xạ dữ liệu (nếu không sử dụng group_variable), cho phép bạn chỉ định một loạt các yếu tố thêm cho biểu đồ, ví dụ như linetype, shape, v.v.

Sau đây là 1 ví dụ cụ thể cho hàm này:

library(ggplot2)
# Tạo đối tượng ggplot với bộ dữ liệu iris và mở rộng aes cho các biến x và fill cho biến Species
p <- ggplot(iris, aes(x = Sepal.Length, fill = Species))

# Thêm lớp biểu đồ mật độ với các tùy chọn tùy chỉnh
p + 
  geom_density(
    bw = 0.2,                    # Độ rộng của hạt nhân (bandwidth)
    adjust = 1,                  # Tham số điều chỉnh bandwidth
    kernel = "gaussian",         # Loại hạt nhân (kernel) sử dụng: "gaussian", "epanechnikov", "rectangular",...
    trim = FALSE,                # Cắt bỏ các giá trị ngoài biên của dữ liệu
    na.rm = FALSE,               # Bỏ qua các giá trị NA
    alpha = 0.5,                 # Độ trong suốt của biểu đồ mật độ
    position = "identity"        # Vị trí hiển thị biểu đồ
  ) +
  labs(title = "Biểu đồ mật độ",
       x = "Độ dài đài hoa (cm)",
       y = "Mật độ",
       fill = "Loài hoa")

Trong đó:

bw: Độ rộng của hạt nhân (bandwidth) xác định độ mịn của biểu đồ mật độ. Giá trị càng nhỏ thì biểu đồ càng chi tiết nhưng dễ bị nhiễu.

adjust: Tham số điều chỉnh độ rộng hạt nhân. Giá trị 1 tương ứng với hạt nhân Gaussian.

kernel: Loại hạt nhân (kernel) sử dụng cho ước tính mật độ. Một số loại hạt nhân phổ biến bao gồm “gaussian”, “epanechnikov”, “rectangular”, v.v.

trim: Nếu TRUE, sẽ cắt bỏ các giá trị ngoài biên của dữ liệu khi vẽ biểu đồ mật độ.

na.rm: Nếu TRUE, sẽ bỏ qua các giá trị NA trong dữ liệu.

alpha: Độ trong suốt của biểu đồ mật độ, cho phép bạn điều chỉnh mức độ hiển thị màu nền của các đường mật độ.

position: Xác định vị trí hiển thị biểu đồ mật độ. Giá trị “identity” sẽ hiển thị biểu đồ mật độ theo dạng chồng chất (mặc định) và “stack” sẽ hiển thị chồng chất các đường mật độ.

Dựa vào kết quả biểu đồ, ta nhận thấy biểu đồ mật độ (density plot) với dữ liệu “iris” được vẽ bằng geom_density() trong ggplot2 sẽ biểu diễn phân phối của độ dài đài hoa (Sepal.Length) của ba loài hoa iris khác nhau: “setosa”, “versicolor” và “virginica”.

2.1.2 Geom_dotplot()

geom_dotplot là một hàm được sử dụng để vẽ biểu đồ chấm (dot plot). Biểu đồ chấm thể hiện phân phối của dữ liệu liên tục thông qua việc đặt một chấm hoặc điểm cho mỗi quan sát trên trục x. Nếu có nhiều quan sát có cùng giá trị trên trục x, các chấm sẽ được chồng chất với nhau và hiển thị dưới dạng một dòng dọc.

Dưới đây là cú pháp cơ bản để sử dụng geom_dotplot trong ggplot2:

library(ggplot2)
ggplot(data, aes(x = group, y = value)) +
  geom_dotplot(binaxis = "y",              # Chiều của bin, có thể là "x" hoặc "y"
           binwidth = 0.2,            # Độ rộng của bin (ngăn) dữ liệu
           stackdir = "center",       # Hướng chồng chất các chấm, có thể là "up", "down", "center", hoặc     "centerwhole"
           method = "histodot",       # Phương pháp tính số lượng chấm trong mỗi bin, có thể là "histodot" hoặc "dotdensity"
           dotsize = 0.5,             # Kích thước của chấm
           stackgroups = TRUE,        # Chồng chất các nhóm dữ liệu khi có nhiều nhóm
           binpositions = "all",      # Vị trí các bin trên trục x, có thể là "bygroup" hoặc "all"
           dotcolor = "blue",         # Màu của các chấm
           fill = "red",              # Màu nền của các chấm
           alpha = 0.7,               # Độ trong suốt của các chấm
           jitter = 0.2,              # Độ nhòe (jitter) của các chấm trong bin, để tạo hiệu ứng phân tán dữ liệu
           binpositions = "all",      # Vị trí các bin trên trục x, có thể là "bygroup" hoặc "all"
           position = position_dodge(0.6) # Xác định vị trí hiển thị biểu đồ chấm, ở đây sử dụng dodge để tách biệt các nhóm

) + labs(title = “Biểu đồ chấm”, x = “Nhóm”, y = “Giá trị”)

Trong đó:

binaxis: Chiều của bin, có thể là “x” hoặc “y”, xác định hướng chồng chất các chấm.

binwidth: Độ rộng của bin (ngăn) dữ liệu, ảnh hưởng đến sự tách biệt và độ mịn của biểu đồ chấm.

stackdir: Hướng chồng chất các chấm, có thể là “up”, “down”, “center”, hoặc “centerwhole”.

dotsize: Kích thước của chấm.

method: Phương pháp tính số lượng chấm trong mỗi bin, có thể là “histodot” hoặc “dotdensity”.

stackgroups: Chồng chất các nhóm dữ liệu khi có nhiều nhóm.

dotcolor: Màu của các chấm.

fill: Màu nền của các chấm.

alpha: Độ trong suốt của các chấm.

jitter: Độ nhòe (jitter) của các chấm trong bin, để tạo hiệu ứng phân tán dữ liệu.

position: Xác định vị trí hiển thị biểu đồ chấm, ở đây sử dụng position_dodge(0.6) để tách biệt các nhóm.

Lấy ví dụ cụ thể với data iris

library(ggplot2)
# Vẽ biểu đồ chấm cho độ dài đài hoa (Sepal.Length)
ggplot(iris, aes(x = Sepal.Length)) +
  geom_dotplot(binwidth = 0.1,         # Độ rộng của bin
               dotsize = 1,          # Kích thước của chấm
               fill = "blue",          # Màu nền của các chấm
               alpha = 0.7,           # Độ trong suốt của các chấm
              
  ) +
  labs(title = "Biểu đồ chấm cho độ dài đài hoa",
       x = "Độ dài đài hoa (cm)",
       y = "Số lượng chấm")

Biểu đồ chấm (dot plot) trên dataset iris, sử dụng geom_dotplot trong ggplot2, hiển thị phân phối của độ dài đài hoa (Sepal.Length) của các loài hoa iris.

2.1.3 Geom_freqpoly()

geom_freqpoly là một trong những hàm dùng để tạo biểu đồ tần số đa giác (frequency polygon) trong ggplot2. Biểu đồ tần số đa giác là một biểu đồ sử dụng các đoạn thẳng nối các điểm dữ liệu trên một trục số để thể hiện tần suất xuất hiện của các giá trị riêng lẻ trong một biến số.

Dưới đây là cú pháp cơ bản để sử dụng geom_freqpoly trong ggplot2:

 library(ggplot2)
 ggplot(data, aes(x = variable)) +
   geom_freqpoly(
   mapping = aes(y = after_stat(count)), # Ánh xạ y cho tần số đếm sau khi thống kê
   binwidth = 0.5,                       # Độ rộng của bin (ngăn) dữ liệu
   color = "red",                        # Màu của đường đa giác
   size = 1.5,                           # Độ dày của đường đa giác
   linetype = "dashed",                  # Kiểu đường của đa giác
   alpha = 0.7                           # Độ trong suốt của đa giác

) + labs(title = “Biểu đồ tần số đa giác”, x = “Biến X”, y = “Tần số đếm”)

Trong đó:

mapping: Thiết lập các aesthetic mappings (các ánh xạ thẩm mỹ) cho biểu đồ, bao gồm cả trục x và y. Trong ví dụ trên, chúng ta sử dụng after_stat(count) để ánh xạ tần số đếm đã được tính sau khi thống kê.

binwidth: Độ rộng của bin (ngăn) dữ liệu, ảnh hưởng đến độ mịn và độ chi tiết của biểu đồ.

color: Màu của đường đa giác.

size: Độ dày của đường đa giác.

linetype: Kiểu đường của đa giác.

alpha: Độ trong suốt của đa giác

Dưới đây là 1 ví dụ về sử dụng geom_freqpoly với dataset iris:

library(ggplot2)
ggplot(data = iris, aes(x = Sepal.Length)) +
  geom_freqpoly(
    aes(y = after_stat(count)),  # Ánh xạ y cho tần số đếm sau khi thống kê
    binwidth = 0.1,              # Độ rộng của bin (ngăn) dữ liệu
    color = "red",               # Màu của đường đa giác
    size = 1.5,                  # Độ dày của đường đa giác
    linetype = "dashed",         # Kiểu đường của đa giác
    alpha = 0.7                  # Độ trong suốt của đa giác
  ) +
  labs(title = "Biểu đồ tần số đa giác",
       x = "Độ dài đài hoa (cm)",
       y = "Tần số đếm")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Từ kết quả, ta nhận thấy biểu đồ tần số đa giác (frequency polygon) cho độ dài đài hoa (Sepal.Length) trong dataset iris hiển thị phân phối của dữ liệu và tần suất xuất hiện của các giá trị riêng lẻ.

2.1.4 Geom_histogram

geom_histogram được sử dụng để tạo biểu đồ histogram. Biểu đồ histogram thể hiện tần suất xuất hiện của các khoảng giá trị (bin) của một biến số liên tục. Biểu đồ này giúp hiển thị phân phối của biến số và là công cụ hữu ích trong việc khám phá dữ liệu.

Dưới đây là cú pháp cơ bản để sử dụng geom_histogram trong ggplot2:

library(ggplot2)

ggplot(data = iris, aes(x = Sepal.Length)) +

geom_histogram(

  mapping = aes(y = after_stat(count)),  # Ánh xạ y cho tần số đếm sau khi thống kê

  binwidth = 0.1,                       # Độ rộng của bin (ngăn) dữ liệu
  
  color = "blue",                       # Màu của đường biểu đồ histogram
 
  fill = "lightblue",                   # Màu nền của các bin

  alpha = 0.7,                          # Độ trong suốt của các bin
  
  position = "dodge",                   # Tách biệt các bin của các nhóm dữ liệu
 
  boundary = 5,                         # Giới hạn xác định điểm biên giữa các bin
  
  closed = "right",                     # Biên giới hạn bên phải của bin

  pad = TRUE,                           # Tự động thêm bin rỗng vào cận trái và cận phải của dữ liệu
 
  na.rm = TRUE,                         # Bỏ qua các giá trị NA trong dữ liệu
  
  show.legend = TRUE                    # Hiển thị hướng dẫn

)

Sau đây là 1 ví dụ khi sử dụng geom_histogram với iris:

library(ggplot2)
ggplot(data = iris, aes(x = Sepal.Length)) +
  geom_histogram(
    aes(y = after_stat(count)),  # Ánh xạ y cho tần số đếm sau khi thống kê
    binwidth = 0.2,              # Độ rộng của bin (ngăn) dữ liệu
    color = "blue",              # Màu đường biểu đồ histogram
    fill = "lightblue",          # Màu nền của các bin
    alpha = 0.7,                 # Độ trong suốt của các bin
    position = "identity",       # Hiển thị các bin theo tọa độ thực
    show.legend = TRUE           # Hiển thị hướng dẫn
  ) +
  labs(title = "Biểu đồ histogram độ dài đài hoa (Sepal.Length)",
       x = "Độ dài đài hoa (cm)",
       y = "Tần số đếm")

Biểu đồ histogram vẽ độ dài đài hoa (Sepal.Length) trong dataset iris cho thấy phân phối của biến số này.

Nhận xét về kết quả:

  1. Biểu đồ histogram cho thấy độ dài đài hoa (Sepal.Length) có phân phối tương đối chuẩn với một đỉnh (peak) nằm gần giá trị khoảng 4.8 đến 5 cm. Điều này cho thấy rằng độ dài đài hoa tập trung chủ yếu vào khoảng này.

  2. Độ rộng của bin (ngăn) dữ liệu được đặt là 0.2, giúp biểu đồ có độ mịn và chi tiết hơn. Kích thước của bin ảnh hưởng đến sự hiển thị của biểu đồ và bạn có thể điều chỉnh binwidth tùy thuộc vào mục tiêu trình bày dữ liệu.

Tổng quan, biểu đồ histogram cung cấp cái nhìn tổng quan về phân phối của biến độ dài đài hoa trong bộ dữ liệu iris, giúp hiểu rõ hơn về phân phối và tập trung của các giá trị dữ liệu.

2.2 Các hàm geom_ vẽ 2 biến trên đồ thị

Trong gói ggplot2 của R, hàm geom_ là một tập hợp các hàm được sử dụng để vẽ các hình học (geometric layers) trên biểu đồ. Các hàm geom_ này là các hình học cơ bản để biểu diễn dữ liệu trong các biểu đồ theo các loại đồ thị khác nhau như biểu đồ phân tán, đường, cột, hình hộp, điểm và nhiều hình học khác.

2.2.1 Geom_bar()

geom_bar là một trong những thành phần quan trọng trong gói ggplot2 của R để tạo biểu đồ cột (bar chart). Nó giúp biểu diễn các biểu đồ dạng cột, với chiều rộng của cột tương ứng với giá trị của dữ liệu.

Dưới đây là cú pháp cơ bản để sử dụng geom_bar trong ggplot2:

library(ggplot2)

ggplot(data = your_data) +

  geom_bar(mapping = aes(x = x_variable, y = y_variable),

  stat = "count",

  other_arguments) +

  other_layers

Trong đó:

your_data: là data frame chứa dữ liệu của bạn.

x_variable: là tên biến mà bạn muốn đưa vào trục x của biểu đồ cột.

y_variable: là tên biến mà bạn muốn đưa vào trục y của biểu đồ cột. Trong trường hợp không cần xác định, ggplot2 sẽ tự động tính toán và hiển thị số lượng đếm (count) của các giá trị trong <x_variable>.

stat = "count": chỉ định rằng chúng ta muốn tính toán số lượng (count) của mỗi giá trị trong <x_variable>.

other_arguments: là các đối số bổ sung như fill (màu sắc của cột), alpha (độ mờ của cột), color (màu của đường viền),…

other_layer: các lớp biểu đồ khác mà ta vẽ thêm.

Bạn cần cung cấp dữ liệu, xác định biến phù hợp để đưa vào trục x và y, sau đó sử dụng các đối số bổ sung như fill, alpha, color để tùy chỉnh biểu đồ cột theo ý muốn.

Dưới đây là một ví dụ đơn giản về việc sử dụng geom_bar: Ta sử dụng dataset penguins tích hợp trong package palmerpenguins vẽ biểu đồ cột về số lượng chim cánh cụt như sau:

library(utf8)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.1     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ lubridate 1.9.2     ✔ tibble    3.2.1
## ✔ purrr     1.0.1     ✔ tidyr     1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
penguins |> ggplot(aes(x=island))+geom_bar(fill="brown",stat="count",color="black")+
  labs(x="Nơi sinh sống",y="số cá thể")

Dựa vào biểu đồ cột, ta thấy rằng có hơn 150 cá thể chim cánh cụt sống ở Biscoe, khoảng 120 cá thể sống ở Dream và gần 50 cá thế sống ở ToTorgersen.

2.2.2 geom_jitter

Hàm geom_jitter() trong ggplot2 được sử dụng để tạo biểu đồ phân tán của dữ liệu bằng cách đưa các điểm dữ liệu lên xuống theo trục x (hoặc y) để tránh trùng lắp.

Khi có nhiều điểm dữ liệu có cùng giá trị trên trục x (hoặc y), chúng sẽ bị trùng lắp và không thể nhìn thấy được số lượng thực sự. geom_jitter() giúp giải quyết vấn đề này bằng cách di chuyển các điểm dữ liệu lên xuống ngẫu nhiên trên trục x (hoặc y).

Dưới đây là cú pháp cơ bản để sử dụng geom_jitter() trong ggplot2 mục đích là để tạo biểu đồ phân tán với jitter

ggplot(data, aes(x = variable, y = value)) +
    geom_jitter()

Trong đó:

data là tập dữ liệu bạn muốn trình bày.

variablevalue là tên cột trong tập dữ liệu, biểu thị cho trục x và y của biểu đồ phân tán, tương ứng.

geom_jitter() có thể được sử dụng cùng với các lớp khác như geom_point() hoặc geom_smooth() để biểu diễn dữ liệu chi tiết hơn.

Dưới đây là một ví dụ cụ thể:

# Tạo một tập dữ liệu đơn giản
data <- data.frame(
  category = rep(c("A", "B", "C"), each = 20),    # sử dụng hàm rep() để lặp lại ba giá trị "A", "B", và "C" mỗi lần lặp 20 lần, tổng cộng tạo ra 60 giá trị.
  value = c(rnorm(20, 10, 2), rnorm(20, 15, 3), rnorm(20, 8, 1)) # đối số đầu tiên là số quan sát, đồi số 
)

# Vẽ biểu đồ phân tán với jitter
ggplot(data, aes(x = category, y = value)) +
  geom_jitter(width = 0.2, height = 0,color="red") +  # Chỉ jitter theo trục x
  labs(title = "Biểu đồ phân tán với geom_jitter")

Trong mã R trên, chúng ta tạo một tập dữ liệu đơn giản bằng cách sử dụng hàm data.frame() để tạo một khung dữ liệu mới. Tập dữ liệu này sẽ bao gồm hai cột: “category” và “value”.

Dưới đây là chi tiết của tập dữ liệu được tạo:

category: Đây là cột chứa thông tin về các nhóm dữ liệu. Trong tập dữ liệu này, ta sử dụng hàm rep() để lặp lại ba giá trị “A”, “B”, và “C” mỗi lần lặp 20 lần, tổng cộng tạo ra 60 giá trị. Điều này nghĩa là có 20 mẫu thuộc nhóm “A”, 20 mẫu thuộc nhóm “B”, và 20 mẫu thuộc nhóm “C”.

value: Đây là cột chứa giá trị dữ liệu tương ứng với mỗi nhóm “A”, “B”, “C”. Để tạo giá trị cho cột “value”, chúng ta sử dụng hàm rnorm() để tạo ngẫu nhiên các giá trị có phân phối chuẩn. Đối số đầu tiên của hàm rnorm() là số lượng mẫu (20 trong trường hợp này), tiếp theo là giá trị trung bình (10 cho nhóm “A”, 15 cho nhóm “B”, và 8 cho nhóm “C”), và cuối cùng là độ lệch chuẩn (2 cho nhóm “A”, 3 cho nhóm “B”, và 1 cho nhóm “C”). Điều này sẽ tạo ra 20 giá trị ngẫu nhiên có phân phối chuẩn cho mỗi nhóm.

Kết quả là tập dữ liệu data bây giờ chứa thông tin về các nhóm “A”, “B”, và “C”, mỗi nhóm có 20 giá trị ngẫu nhiên theo phân phối chuẩn tương ứng. Tập dữ liệu này có 60 hàng và 2 cột. Ta có thể sử dụng ggplot2 và geom_jitter() như ở ví dụ trước để vẽ biểu đồ phân tán của các giá trị dữ liệu theo từng nhóm “A”, “B”, “C”.

So sánh khi sử dụng với geom_point()

# Vẽ biểu đồ phân tán với geom_point
ggplot(data, aes(x = category, y = value)) +
  geom_point(color="red") +  # Chỉ jitter theo trục x
  labs(title = "Biểu đồ phân tán với geom_point")

Ta thấy với cùng một dataset, geom_jitter() sẽ giúp cho các điểm trên đồ thị di chuyển qua lại cho dễ nhìn hơn, tránh được những điểm lặp nhau. Còn geom_point thì không tự di chuyển được các điểm, và nếu có 2 điểm trùng nhau thì 2 điểm đó sẽ xếp đè lên nhau.

2.2.3 geom_quantile()

geom_quantile() được sử dụng để vẽ các đường đồ thị của các giá trị phân vị (quantiles) trong biểu đồ dựa trên dữ liệu của bạn. Hàm này thực chất là một hình dạng đặc biệt của geom_line(), và nó tính toán các giá trị phân vị từ dữ liệu và sau đó vẽ các đường đồ thị của chúng.

Dưới đây là cú pháp cơ bản để sử dụng geom_quantile() trong ggplot2:

library(ggplot2)

ggplot(data, aes(x = x_variable, y = y_variable)) +
  geom_point() +
  geom_quantile(quantiles = c(0.25, 0.5, 0.75))
ggplot(penguins, aes(x = flipper_length_mm, y = body_mass_g)) +
  geom_point(color="brown") +
  geom_quantile(quantiles = c(0.25, 0.5, 0.75), color = "orange", method = "rqss") +
  labs(title = "Biểu đồ phân tán với đường đồ thị phân vị",x="Độ dài cánh",y="Khối lượng cơ thể")
## Smoothing formula not specified. Using: y ~ qss(x, lambda = 1)
## Warning in rq.fit.sfn(x, y, tau = tau, rhs = rhs, control = control, ...): tiny diagonals replaced with Inf when calling blkfct

Trong ví dụ này, chúng ta đã cài đặt gói palmerpenguins để có tập dữ liệu penguins, và cài đặt gói ggplot2 để vẽ biểu đồ. Tiếp theo, chúng ta nhập các gói đã cài đặt và sử dụng ggplot() để tạo biểu đồ phân tán của flipper_length_mm và body_mass_g với geom_point(). Sau đó, sử dụng geom_quantile() để tính và vẽ các đường đồ thị của các giá trị phân vị (0.25, 0.5, 0.75) cho cả hai biến theo trục x và y.

Biểu đồ sẽ hiển thị các điểm dữ liệu của flipper_length_mm và body_mass_g, cùng với các đường đồ thị của các giá trị phân vị. Màu đỏ được sử dụng để biểu thị các đường đồ thị phân vị.

2.2.4 geom_point()

Trong gói ggplot2 của R, geom_point() là một hàm dùng để vẽ các điểm trên biểu đồ phân tán.

Hàm geom_point() là một lớp hình học (geometric layer) trong ggplot2, cho phép bạn hiển thị dữ liệu dưới dạng các điểm trên biểu đồ phân tán. Điểm thường được sử dụng để biểu diễn các quan sát đơn lẻ, mỗi điểm thể hiện một cặp giá trị (x, y) của dữ liệu.

Dưới đây là cú pháp cơ bản để sử dụng geom_point() trong ggplot2:

library(ggplot2)

ggplot(data, aes(x = x_variable, y = y_variable)) +
  geom_point()

Bạn có thể tùy chỉnh biểu đồ điểm bằng cách sử dụng các tham số bổ sung như size, shape, color, … Trong geom_point().

ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm, color = species)) +
  geom_point() +
  labs(title = "Biểu đồ phân tán độ dài mỏ và độ sâu mỏ theo từng loài chim cánh cụt",x="Độ dài mỏ",y="Độ sâu mỏ")

Trong phần này chúng tôi sử dụng ggplot() để tạo biểu đồ phân tán giữa bill_length_mm và bill_depth_mm theo từng loài penguins với geom_point(). Màu sắc của từng điểm dữ liệu sẽ được mã hóa theo loài penguins thông qua tham số color = species.

Biểu đồ sẽ hiển thị một biểu diễn phân tán của các điểm dữ liệu của bill_length_mm và bill_depth_mm, với mỗi loài penguins được biểu diễn bằng một màu khác nhau.

2.2.5 geom_smooth()

geom_smooth() là một lớp hình học (geometric layer) trong gói ggplot2 của R, dùng để thêm đường cong điều chỉnh (trend line) vào biểu đồ phân tán. Chức năng này giúp hiển thị xu hướng hoặc mối quan hệ chung giữa hai biến trên biểu đồ phân tán.

Hàm geom_smooth() thường được sử dụng để vẽ các đường cong phù hợp, như đường cong hồi quy (regression line) hoặc đường cong mật độ (density line), để mô tả xu hướng của dữ liệu dưới dạng biểu đồ phân tán.

Dưới đây là cú pháp cơ bản để sử dụng geom_smooth() trong ggplot2:

library(ggplot2)
ggplot(data, aes(x = x_variable, y = y_variable)) +
  geom_point() +
  geom_smooth(method = "lm")   # Ví dụ: Sử dụng phương pháp hồi quy tuyến tính

Dưới đây là ví dụ về việc sử dụng geom_smooth()

penguins%>%ggplot(aes(x=flipper_length_mm,y=body_mass_g))+geom_point(aes(color=species,na.rm=T))+
  geom_smooth(aes(color=species),formula=y~x,method='lm',na.rm = T,se=F)+
  facet_wrap(~species)+
  labs(x="Độ dài cánh",y="Khối lượng cơ thể")
## Warning in geom_point(aes(color = species, na.rm = T)): Ignoring unknown
## aesthetics: na.rm

penguins: là tập dữ liệu penguins.

aes(x = flipper_length_mm, y = body_mass_g): định nghĩa trục x và y cho biểu đồ.

geom_point(): dùng để vẽ các điểm dữ liệu.

geom_smooth(method = "lm", se = FALSE): thêm đường cong hồi quy sử dụng phương pháp hồi quy tuyến tính (method = “lm”) và không hiển thị khoảng tin cậy (confidence interval) bằng cách đặt se = FALSE.

facet_wrap() đùng để chia biểu đồ theo một biến. Trong ví dụ này tôi phân chia dồ thị theo biến species

Lưu ý rằng hàm geom_smooth() trong ví dụ này sẽ vẽ đường cong hồi quy để mô tả mối quan hệ tuyến tính giữa flipper_length_mm và body_mass_g. Nếu bạn muốn sử dụng phương pháp khác hoặc vẽ đường cong mật độ thay vì đường cong hồi quy, bạn có thể thay đổi tham số method trong hàm geom_smooth().

2.2.6 geom_text

geom_text là một lớp hình học trong gói ggplot2 của R. Nó cho phép bạn thêm các nhãn văn bản vào biểu đồ, giúp tăng cường thông tin và giải thích cho các điểm dữ liệu, thanh trượt, hay các yếu tố hình thức khác mà bạn đã trình bày bằng ggplot.

Cú pháp của hàm geom_text như sau:

library(ggplot2)

ggplot(data, aes(x = x_variable, y = y_variable)) +
 geom_point() +
 geom_text(aes(label = label_variable))

Các tham số chính:

data: là tập dữ liệu bạn muốn trình bày.

x_variable, y_variable: là tên cột trong tập dữ liệu, biểu thị trục x và y của biểu đồ.

geom_point(): là hàm để vẽ các điểm dữ liệu (không bắt buộc, nhưng thường kết hợp với geom_point() để hiển thị các điểm trên biểu đồ trước khi thêm văn bản).

geom_text(aes(label = label_variable)): là hàm để thêm văn bản vào biểu đồ. Tham số label = label_variable là cột trong tập dữ liệu, chứa nội dung văn bản bạn muốn hiển thị cho mỗi điểm dữ liệu.

Ví dụ sử dụng geom_text:

penguins |> ggplot(aes(x = island, y = after_stat(count))) +
  geom_bar(fill = 'purple') +
  geom_text(aes(label = scales::percent(after_stat(count/sum(count)))), stat = 'count', color = 'red', vjust = - .5) +
  facet_grid(.~species) +
  labs(x = 'Noi sinh song', y = 'So luong')

Trong phần này, ta dùng hàm geom_text() để thêm vào đầu của mỗi cột trong đồ thị cột tỉ lệ phần trăm của các loài chim sống trên từng hòn đảo. Ta thấy rằng nhờ hàm geom_text() mà biểu đồ chứa đựng được nhiều thông tin hơn. Nhìn vào loài Adelie ta thấy 13,21% loài này sống ở đảo Biscoe, 16.52% sống ở đảo Dream và 14.11% sống ở đảo Torgersen.

2.2.7 geom_rug

Trong ggplot2, hàm geom_rug() được sử dụng để thêm các dấu đánh dấu (rugs) vào biểu đồ. Dấu đánh dấu là các đường thẳng ngắn dọc trên trục x hoặc trục y, chỉ định vị trí của các điểm dữ liệu trên biểu đồ phân tán. Các dấu đánh dấu có thể giúp hiểu rõ hơn vị trí của các điểm dữ liệu và mật độ phân bố chúng trên biểu đồ.

Dưới đây là cú pháp cơ bản để sử dụng geom_rug() trong ggplot2:

library(ggplot2)

ggplot(data, aes(x = x_variable, y = y_variable)) +
 geom_point() +
 geom_rug()
ggplot(penguins, aes(x = flipper_length_mm, y = body_mass_g)) +
  geom_point(color="red") +
  geom_rug()

Trong ví dụ này, chúng ta sử dụng bộ dữ liệu “penguins” từ gói “palmerpenguins”. Sau đó, sử dụng ggplot2 để vẽ biểu đồ phân tán của các biến flipper_length_mm và body_mass_g. Hàm geom_point() được sử dụng để vẽ các điểm dữ liệu, và geom_rug() được sử dụng để thêm các dấu đánh dấu trên trục x, chỉ ra vị trí của các điểm dữ liệu theo trục x.

2.2.8 geom_bin2d

Trong ggplot2, hàm geom_bin2d() được sử dụng để tạo biểu đồ 2D histogram. Biểu đồ 2D histogram là một biểu đồ dùng để biểu diễn mật độ phân bố của hai biến dữ liệu liên tục thông qua việc chia không gian biến thành các ô (bins) và tính số lượng quan sát nằm trong từng ô đó.

Dưới đây là cú pháp cơ bản để sử dụng geom_bin2d() trong ggplot2:

library(ggplot2)
ggplot(data, aes(x = x_variable, y = y_variable)) +
 geom_bin2d(
  bins = 30,            # Số lượng ô theo chiều x và y
  binwidth_x = NULL,    # Độ rộng ô theo chiều x
  binwidth_y = NULL,    # Độ rộng ô theo chiều y
  fill = "blue",        # Màu sắc của ô
  alpha = 0.6,          # Độ trong suốt của ô (giá trị từ 0 đến 1)
  color = "white"       # Màu sắc của đường viền giữa các ô

)

Giải thích các tham số:

bins: Số lượng ô theo chiều x và y trong biểu đồ 2D histogram. binwidth_x và binwidth_y: Độ rộng của ô theo chiều x và y. Nếu bạn muốn xác định độ rộng của từng ô một cách tùy chỉnh, bạn có thể sử dụng binwidth_x và binwidth_y thay vì bins. fill: Màu sắc của ô trong biểu đồ 2D histogram. alpha: Độ trong suốt của ô. Giá trị 0 tương ứng với không trong suốt (hoàn toàn trong suốt), giá trị 1 tương ứng với không trong suốt (hoàn toàn không trong suốt). color: Màu sắc của đường viền giữa các ô.

ggplot(penguins, aes(x = flipper_length_mm, y = body_mass_g)) +
  geom_bin2d(bins = 20, color = "white", fill = "steelblue") +
  labs(title = "Biểu đồ 2D Histogram",
       x = "Chiều dài cánh (mm)",
       y = "Khối lượng cơ thể (g)")

Trong ví dụ này, chúng ta sử dụng bộ dữ liệu “penguins” từ gói “palmerpenguins”. Sau đó, sử dụng ggplot2 để vẽ biểu đồ 2D histogram của các biến flipper_length_mm và body_mass_g trong bộ dữ liệu. Hàm geom_bin2d() được sử dụng để tạo biểu đồ 2D histogram với số lượng ô (bins) là 20, màu viền là “white” và màu nền của các ô là “steelblue”. Chúng ta cũng thêm nhãn cho biểu đồ bằng hàm labs().

2.2.9 geom_area

Trong ggplot2, hàm geom_area() được sử dụng để tạo biểu đồ diện tích (area chart). Biểu đồ diện tích là một biểu đồ dùng để biểu diễn sự biến đổi của một biến theo thời gian hoặc các nhóm dữ liệu khác nhau. Nó được hình thành bởi các dải màu được xếp chồng lên nhau, mỗi dải thể hiện giá trị của biến trong một khoảng thời gian hoặc nhóm dữ liệu.

Dưới đây là cú pháp cơ bản để sử dụng geom_area() trong ggplot2:

library(ggplot2)

ggplot(data, aes(x = x_variable, y = y_variable, fill = group_variable)) +
  geom_area(
   position = "stack",         # Chế độ xếp chồng các dải màu (default) hoặc "identity" để không xếp chồng
   color = "black",            # Màu viền của các dải màu
   alpha = 0.7,                # Độ mờ của màu nền (từ 0 - 1)
   linetype = "dashed",        # Loại đường viền (nếu color được chỉ định)
   size = 1,                   # Độ dày của đường viền
   na.rm = FALSE,              # Bỏ qua các giá trị NA
   mapping = aes(color = group_variable) # Ánh xạ dữ liệu để tô màu viền theo biến "group_variable"
 )

Cú pháp nâng cao của geom_area() trong ggplot2 cho phép bạn tùy chỉnh nhiều thông số hơn để điều chỉnh biểu đồ diện tích. Dưới đây là một số tham số phổ biến và cú pháp để sử dụng geom_area() với các tùy chọn tùy chỉnh:

 library(ggplot2)

 ggplot(data, aes(x = x_variable, y = y_variable, fill = group_variable)) +
   geom_area(
   position = "stack",         # Chế độ xếp chồng các dải màu (default) hoặc "identity" để không xếp chồng
   color = "black",            # Màu viền của các dải màu
   alpha = 0.7,                # Độ mờ của màu nền (từ 0 - 1)
   linetype = "dashed",        # Loại đường viền (nếu color được chỉ định)
   size = 1,                   # Độ dày của đường viền
   na.rm = FALSE,              # Bỏ qua các giá trị NA
   mapping = aes(color = group_variable) # Ánh xạ dữ liệu để tô màu viền theo biến "group_variable"

) Trong đó:

data: là tập dữ liệu bạn muốn trình bày.

x_variable và y_variable: là tên cột trong tập dữ liệu, biểu thị trục x và y của biểu đồ diện tích.

fill: Biến dùng để xác định màu nền của các dải màu. Bạn có thể sử dụng tên cột hoặc giá trị màu (ví dụ: “blue”).

group_variable: Biến dùng để xác định các nhóm dữ liệu trong tập dữ liệu. Các nhóm này sẽ được xếp chồng lên nhau trong biểu đồ diện tích.

Lưu ý rằng các tham số trên chỉ là một số tùy chọn phổ biến và bạn có thể tùy chỉnh nhiều thông số khác trong geom_area() để điều chỉnh biểu đồ diện tích sao cho phù hợp với nhu cầu của bạn.

Vẽ biểu đồ diện tích theo loài penguin và cột flipper_length_mm

`

3 CHƯƠNG 3: VẼ CÁC GRAPH TỪ CƠ BẢN ĐẾN NÂNG CAO

Trong chương 2, tôi chỉ thực hiện viết tổng quan lý thuyết cho mỗi hàm geom_() và các đối số có trong hàm. Còn trong chương 3, tôi sẽ thực hiện vẽ từ cơ bản đến nâng cao cho một số biểu đồ thường dùng để phân tích dữ liệu.

3.1 Biểu đồ phân tán

Trong phần này, tôi sẽ sử dụng 3 Indicator như sau:

  • “SP.POP.TOTL”: Đây là mã thông tin cho chỉ số “Tổng dân số”. Nó thể hiện tổng số dân số của một quốc gia hoặc vùng địa lý tại một năm cụ thể.

  • “SL.UEM.TOTL.ZS”: Chỉ số Tỷ lệ Thất nghiệp (Unemployment Rate).Chỉ số này đo lường tỷ lệ người thất nghiệp trong tổng số lực lượng lao động trong một quốc gia. Nó thể hiện tình hình thất nghiệp và mức độ sử dụng lao động trong kinh tế.

  • “NY.GDP.PCAP.PP.CD”: Đây là mã thông tin cho chỉ số “GDP đầu người (GDP per capita) được điều chỉnh theo thị trường và mua sắm quốc tế (Purchasing Power Parity - PPP)”. Chỉ số này thể hiện giá trị GDP trung bình của mỗi cá nhân trong quốc gia, tính bằng đơn vị tiền tệ quốc tế (USD) và điều chỉnh mức giá cả của các hàng hóa và dịch vụ giữa các quốc gia.

Đầu tiên tôi thực hiện lấy dữ liệu của 3 indicator đó như sau, dữ liệu được thu thập từ năm 2010 đến 2021. Lý do không chọn những năm gần đây như 2022 hay 2023 vì trong 2 năm này chưa thu thập đủ dữ liệu.

library(WDI)
library(ggplot2)
df <- WDI(country = "all", 
 start = 2015,
 end = 2021, 
 indicator = c("SL.UEM.TOTL.ZS","SP.POP.TOTL", "NY.GDP.PCAP.PP.CD"))

Chuẩn bị dữ liệu trước khi vẽ

names(df) <- c("country","iso2c","iso3c","year","unemp","pop","gdp") # Đổi tên các biến
library(tidyverse)
df1 <- df %>% 
  filter(year == 2020)     #Lọc ra dữ liệu của năm 2020
d <- WDIcache()            # Lấy dữ liệu về phân loại nhóm quốc gia
d2 <- d[[2]] %>% as.data.frame()   #Khai thác dataframe thứ 2 của d
names(d2)
## [1] "iso3c"     "iso2c"     "country"   "region"    "capital"   "longitude"
## [7] "latitude"  "income"    "lending"
d2$income %>% unique()
## [1] "High income"         "Aggregates"          "Low income"         
## [4] "Lower middle income" "Upper middle income" "Not classified"

Bây giờ tôi tạo ra một dataframe income_group từ dataframe d2 phân loại về thu nhập của từng quốc gia bao gồm 5 biểu hiện: thu nhập thấp (low income), thu nhập cao (high income), thu nhập trung bình thấp (Lower middle income), thu nhập trung bình cao (Upper middle income) và biểu hiện “Aggregates”. Biểu hiện này không đại diện cho 1 quốc gia nên ta loại bỏ nó. Sau đó ghép 2 dataframe df11 vàincome_group` lại.

# Lấy ra các cột biến cần thiết: 
income_group <- d2 %>% 
  mutate_if(is.factor, as.character) %>% 
  filter(income != "Aggregates") %>% 
  select(iso2c, region, income)

# Ghép hai  DF và loại NA: 

total_df <- right_join(df1, income_group, by = "iso2c") %>% na.omit()

Sau đó ta tính toán tần số cho biến income trong dataframe total_df

# Nhóm thu nhập: 
total_df$income %>% table()
## .
##         High income          Low income Lower middle income Upper middle income 
##                  55                  21                  52                  46
total_df %>% 
  group_by(income) %>% 
  count()
## # A tibble: 4 × 2
## # Groups:   income [4]
##   income                  n
##   <chr>               <int>
## 1 High income            55
## 2 Low income             21
## 3 Lower middle income    52
## 4 Upper middle income    46

Kết quả ta thấy có 55 quốc gia có thu nhập cao (high income), 21 quốc gia có thu nhập thấp (low income), 52 quóc gia có thu nhập trên trung bình (upper middle income) và 46 quốc gia có thu nhập trung bình thấp (lower middle income)

Sau khi chuẩn bị xong những thứ cần thiết, ta thực hiện vẽ biểu đồ như sau. Ta vẽ biểu đồ phân tán của 2 biến tỷ lệ thất nghiệp (unemp) và gdp (GDP/ người) của các quốc gia. Ta sẽ vẽ từ cơ bản đến nâng cao.

total_df %>% 
  ggplot(aes(gdp,unemp)) + 
  geom_point()

Chia lại khoảng cách dữ liệu của trục hoành và trục tung như sau. Ta thấy có 1 số giá trị ngoại lai (ouliers) khi GDP trên 75000$. Do đó ta cũng bỏ các điểm này trên đồ thị.

library(scales)
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
total_df %>% 
  filter(gdp < 75000) %>% 
  ggplot(aes(gdp, unemp)) + 
  geom_point() + 
  scale_x_continuous(breaks = seq(0, 75000,10000), labels = dollar) + 
  scale_y_continuous(breaks = seq(0, 40, 5))

Cải tiến đồ thị phân tán nhằm cho nhiều thông tin hơn bằng cách thêm 2 biến thu nhập income và dân số pop vừa tạo ở trên.

total_df %>% 
  filter(gdp < 75000) %>% 
  ggplot(aes(gdp, unemp, size = pop, color = income)) + 
  geom_point() + 
  scale_x_continuous(breaks = seq(0, 75000,10000), labels = dollar) + 
  scale_y_continuous(breaks = seq(0, 40, 5))

Bây giờ ta thấy đồ thị phân tán đã chứa nhiều thông tin hơn. Những chấm trên đồ thị bao gồm 4 màu đỏ, xanh lá, xanh dương và tím tương ứng với các biểu hiện của biến thu nhập. Và kích cỡ của các chấm thể hiện số dân. Chấm nhỏ thể hiện các quốc gia có dân số từ 0 đến 5*10^8 (người). Chấm to thể hiện số dân từ 10^9 người trở lên.

Tiếp tục cải tiến hơn nữa:

total_df %>% 
  filter(gdp < 75000) %>% 
  ggplot(aes(gdp, unemp, size = pop, color = income)) + 
  geom_point(alpha = 0.3) + 
  scale_x_continuous(breaks = seq(0, 75000, 10000), labels = dollar) + 
   scale_y_continuous(breaks = seq(0, 40, 5)) + 
  scale_size(range = c(1, 30)) + 
  scale_color_discrete(name = "Income Group:") + 
  guides(size = FALSE) + 
  labs(x = "GDP per capital ($)", 
       y = "Unemployment Rate (%)", 
       title = "Mối liên hệ giữa Tỷ lệ thất nghiệp và GDP/ người của mỗi quốc gia trong năm 2020", 
       subtitle = "Ngoài ra những chấm to trên đồ thị thể hiện dân số cao. Mỗi chấm là một màu sắc khác nhau thể hiện các biểu hiện của thu nhậpnhập", 
       caption =  "Data Source: The World Bank")
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Ta thêm đường hồi quy cho biểu đồ phân tán như sau:

total_df %>% 
  filter(gdp < 75000) %>% 
  ggplot(aes(gdp, unemp, size = pop, color = income)) + 
  geom_smooth(aes(group = 1), method = "lm", formula = y ~ log(x), 
              color = "grey40", alpha = 0.1, se = FALSE) + 
  geom_point(alpha = 0.3) + 
  scale_x_continuous(breaks = seq(0, 75000, 10000), labels = dollar) + 
  scale_y_continuous(breaks = seq(0, 40, 5)) + 
  scale_size(range = c(1, 30)) + 
  scale_color_discrete(name = "Income Group:") + 
  guides(size = FALSE) + 
  theme(legend.position = c(0.859, 0.26)) + 
  theme(legend.title = element_text(size = 12, face = "bold")) + 
  theme(legend.background = element_rect(fill = "#fff7ec", size = 0.2, color = "grey70")) + 
  labs(x = "GDP per capital ($)", 
       y = "Unemployment Rate (%)", 
       title = "Mối liên hệ giữa Tỷ lệ thất nghiệp và GDP/ người của mỗi quốc gia trong năm 2020", 
       subtitle = "Ngoài ra những chấm to trên đồ thị thể hiện dân số cao. Mỗi chấm là một màu sắc khác nhau thể hiện các biểu hiện của thu nhậpnhập", 
       caption =  "Data Source: The World Bank")
## Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The following aesthetics were dropped during statistical transformation: size
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
##   the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?

Ta thấy đường hồi quy đi ngang và có lẽ 2 biến này không có tương quan với nhau.

Tiếp tục cải tiến đồ thị phân tán, lần này ta thêm tên cho một số quốc gia.

my_country <- c("Vietnam", "China", "India", "Thailand", "Malaysia", 
                "Germany", "Japan")

library(ggrepel)

total_df %>% 
  filter(gdp < 75000) %>% 
  ggplot(aes(gdp, unemp, size = pop, color = income)) + 
  geom_smooth(aes(group = 1), method = "lm", formula = y ~ log(x), 
              color = "grey40", alpha = 0.1, se = FALSE) + 
  geom_point(alpha = 0.3) + 
  geom_text_repel(data = total_df %>% filter(country %in% my_country), 
            aes(label = country), color = "gray20", size = 3.5, force = 19) + 
  scale_x_continuous(breaks = seq(0, 75000, 10000), labels = dollar) + 
 scale_y_continuous(breaks = seq(0, 40, 5)) +
  scale_size(range = c(1, 30)) + 
  scale_color_discrete(name = "Income Group:") + 
  guides(size = FALSE) + 
  theme(legend.position = c(0.83, 0.22)) + 
  theme(legend.title = element_text(size = 12, face = "bold")) + 
  theme(legend.background = element_rect(fill = "#fff7ec", size = 0.2, color = "grey70")) + 
  labs(x = "GDP per capital ($)", 
       y = "Unemployment Rate (%)", 
       title = "Mối liên hệ giữa Tỷ lệ thất nghiệp và GDP/ người của mỗi quốc gia trong năm 2020", 
       subtitle = "Ngoài ra những chấm to trên đồ thị thể hiện dân số cao. Mỗi chấm là một màu sắc khác nhau thể hiện các biểu hiện của thu nhậpnhập", 
       caption =  "Data Source: The World Bank")
## Warning: The following aesthetics were dropped during statistical transformation: size
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
##   the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?

Ta thấy Việt Nam và Ấn độ là 2 quốc gia có dân số cao. Ấn Độ tuy có dân số cao nhưng GDP/ người thì dưới 10000$/người.

3.2 Biểu đồ cột

library(palmerpenguins)
penguins <- na.omit(penguins)
iris <- na.omit(iris)

Độ sâu mỏ của chim penguins (đơn vị mm).

library(dplyr)
library(ggplot2)
spc <- penguins %>%
  group_by(species) %>%
  count()
theme_set(theme_minimal())
spc %>%
  ggplot(aes(species, n)) +
  geom_col()

Hoặc ta có thể sử dụng geom_bar():

spc %>% 
  ggplot(aes(species, n)) +
  geom_bar(stat = "identity")

sắp xếp lại (cách 1):

spc %>%
  ggplot(aes(reorder(species, n), n)) +
  geom_col() 

Lúc này biểu đồ xắp xếp số lượng chim cánh cụt theo từng loài từ nhỏ đến lớn.

Cách 2:

spc_ordered <- spc %>% 
  ungroup() %>% 
  arrange(n) %>% 
  mutate(species = factor(species, levels = species))
spc_ordered %>% 
  ggplot(aes(species, n)) + 
  geom_col()

Lúc này biểu đồ thể hiện số chim cánh cụt theo tưng loài và xắp xếp từ nhỏ đến lớn.

Hoặc một kiểu khác:

spc %>% 
  ggplot(aes(reorder(species, -n), n)) + 
  geom_col()

Lúc này, biểu đồ thể hiện số chim cánh cụt theo từng loài và được sắp xếp theo thứ tự giảm dần

Tính toán số lượng penguins theo loài

penguins %>%
  filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
  group_by(species) %>%
  count() %>%
  ggplot(aes(reorder(species, -n), n)) +
  geom_col()

Hiển thị các con số:

# Tính toán số lượng penguins theo loài
penguins %>%
  filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
  group_by(species) %>%
  count() %>%
  ggplot(aes(reorder(species,-n), n)) +
  geom_col(width = 0.7,fill="brown") +
  geom_text(aes(label = n), vjust = 2, color = "white", size = 4) +
  labs(x = NULL, y = "Number of Penguins",
       title = "Number of Penguins by Species",
       caption = "Data Source: Custom Penguins Dataset") ->> p1

# Hiển thị biểu đồ
p1

Ta có thể Xoay nghiêng đồ thị cột như sau:

p1 + coord_flip()

Lúc này với biểu đồ cột ngang, các số có trên biểu đồ bị mất. Do đó ta hiệu chỉnh như sau:

Hiệu chỉnh như sau:

penguins_count <- penguins %>%
  group_by(species) %>%
  count()
theme_set(theme_minimal())
p2 <- ggplot(penguins_count, aes(reorder(species, n), n)) +
  geom_col(width = 0.7,fill="brown") +
  geom_text(aes(label = n), hjust = 1.2, color = "white", size = 5) +
  labs(x = NULL, y = "Number of Penguins",
       title = "Number of Penguins by Species",
       caption = "Data Source: Custom Penguins Dataset") +
  coord_flip() +
  scale_y_continuous(breaks = seq(0, max(penguins_count$n), 10))
p2

Lúc này ta thấy đồ thị được biểu diễn đẹp hơn và các con số đã được chỉnh ra phía giữa.

Hoặc ta có thể làm kiểu khác đa màu sắc hơn:

library(dplyr)
library(ggplot2)
penguins %>%
  filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
  group_by(species) %>%
  count() %>%
  ggplot(aes(reorder(species, n), n, fill = species)) +
  geom_col(width = 0.7, show.legend = FALSE) +
  geom_text(aes(label = n), hjust = 1.2, color = "white", size = 5) +
  labs(x = NULL,
       y = "Số lượng",
       title = "Số lượng chim cánh cụt theo loài",
       caption = "Nguồn dữ liệu: https://github.com/allisonhorst/palmerpenguins") +
  coord_flip() +
  scale_y_continuous(breaks = seq(0, 100, 10)) -> p3
print(p3)

Sử dụng theme của một số tạp chí nổi tiếng:

library(ggthemes)
p3 + 
  theme_economist(horizontal = FALSE)

p3 + 
  theme_economist(horizontal = FALSE) + 
  scale_fill_economist()

p3 + 
  theme_fivethirtyeight(base_size = 10)

Làm nổi bật một loài được chọn Gentoo:

penguins %>%
  filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
  group_by(species) %>%
  count() %>%
  ungroup() %>%
  arrange(n) %>%
  mutate(species = factor(species, levels = species)) -> df1

df1 %>%
  ggplot() +
  geom_bar(aes(species, n), fill = "#377eb8", stat = "identity", width = 0.7) +
  geom_bar(data = df1 %>% filter(species == "Gentoo"), aes(species, n),
           fill = "#e41a1c", stat = "identity", width = 0.7) +
  geom_text(data = df1 %>% filter(species == "Gentoo"), aes(species, n, label = n),
            hjust = 1.2, color = "white", size = 5) +
  coord_flip() +
  labs(x = NULL, y = "Số lượng",
       title = "Số lượng chim cánh cụt theo loài",
       caption = "Nguồn dữ liệu: https://github.com/allisonhorst/palmerpenguins") +
  coord_flip() +
  scale_y_continuous(breaks = seq(0, 100, 10))
## Coordinate system already present. Adding new coordinate system, which will
## replace the existing one.

Trong biểu đồ trên, ta đã làm nổi bật được loài Gentoo với 119 cá thể bằng cách tô màu đỏ cho cột đó.

penguins %>%
  filter(species %in% c("Adelie", "Chinstrap", "Gentoo")) %>%
  group_by(species, island) %>%
  count() %>%
  ungroup() -> df2

df2 %>%
  ggplot(aes(species, n, fill = island)) +
  geom_col()

Cải tiến như sau:

df2 %>%
  rename(dao = island) %>%
  ggplot(aes(species, n, fill = dao)) +
  geom_col() 

df2 %>%
  rename(dao = island) %>%
  ggplot(aes(species, n, fill = dao)) +
  geom_col(position = "dodge")

penguins %>%
  rename(dao = island) %>%
  ggplot(aes(species, bill_depth_mm, fill = dao)) +
  geom_col(position = "fill") +
  coord_flip()

penguins %>%
  mutate(dao = case_when(island != "Biscoe" ~ "Others",
                             TRUE ~ island)) %>%
  ggplot(aes(species, bill_depth_mm, fill = dao)) +
  geom_col(position = "fill") +
  coord_flip()

4 CHƯƠNG 4: ỨNG DỤNG CỦA GGPLOT2 vào phân tích trong kinh tế

Như đã đề cập ở chương 1, việc phân tích dữ liệu trở nên phổ biến ở hầu hết mọi lĩnh vực bao gồm kinh tế, tài chính, y tế, xã hội, khoa học… Do đó trong chương này, chúng tôi ứng dụng package ggplot 2 trong phân tích một trong các lĩnh vực đó, và lĩnh vực chúng tôi lựa chọn là kinh tế.

4.1 Phân tích vĩ mô và chuyển động ngành trong 8/2023.

Dữ liệu nghiên cứu

Đối với tình hình vĩ mô thế giới, chúng tôi sử dụng dữ liệu chỉ số giá tiêu dùng CPI của Mỹ, lãi suất FED ban hành, tỷ giá đồng đô la Mỹ… Đối với tình hình vĩ mô Việt Nam, tôi sử dụng dữ liệu đầu tư công, GDP, bất động sản…

4.1.1 Tổng sản phẩm quốc nội

library(readxl)
GUSA <- read_excel("D:\\Vĩ mô\\GDP_USA.xlsx")
library(DT)
datatable(GUSA)
GUSA$Date <- as.Date(GUSA$Date)
sapply(GUSA,class)
##        Date     GDP_USA PREDICT_USA  PREGDP_USA 
##      "Date"   "numeric"   "numeric"   "numeric"

Trên đây là bảng dữ liệu về GDP của Mỹ, bao gồm các biến như sau

Xu hưỡng lãi suất qua từng năm của FED như sau:

  • Date: Ngày

  • GDP_USA : GDP thực tế của Mỹ (%)

  • PREDICT_USA: GDP của Mỹ được dự đoán (%)

  • PREGDP_USA: GDP của Mỹ ở kỳ trước (%)

library(ggplot2)
w_color <- "#973d4c"
n_color <- "#2dc0d2"  
bgr_color <- "#d9e9f0"
grid_color <- "#b2c1ca"
icon_color <- "#ed1c24"
ggplot(data=GUSA,aes(x=Date))+
  geom_line(aes(y=GDP_USA),color="blue",size=1) +
  geom_line(aes(y=PREDICT_USA),color="red",size=1)+
  geom_point(data=GUSA %>% filter(GDP_USA==2.4),aes(Date,GDP_USA),color="blue",size=3)+
  annotate("text", 
           label = "2.4%", 
           x = GUSA$Date[1], y = 2.4, 
           size = 4, hjust = 1, vjust = -1,color="blue")+
  geom_point(data=GUSA %>% filter(PREGDP_USA==2),aes(Date,PREGDP_USA),color="brown",size=3)+
  annotate("text", 
           label = "2%", 
           x = GUSA$Date[2], y = 2, 
           size = 4, hjust = -0.5, vjust = 2,color="brown")+
  labs(title="Tổng sản phẩm quốc nội - Mỹ (%)",x= "Ngày" ,y=element_blank(),
       caption="Dữ liệu được lấy trên trang investing.com")+
  scale_x_date(date_labels = "%m/%Y", date_breaks = "2 month", name = "Ngày ")+
  scale_y_continuous(breaks = seq(-2, 8, 1))+
  theme(plot.caption = element_text(face = "italic",size=10))+
  theme(plot.background = element_rect(fill = bgr_color , color = NA)) +
  theme(panel.background = element_rect(fill = bgr_color, color = NA)) +
  theme(plot.margin = unit(rep(0.7, 4), "cm")) +
  theme(panel.grid.major = element_blank()) + 
  theme(panel.grid.minor = element_blank())

library(utf8)
sapply(GUSA,class)
##        Date     GDP_USA PREDICT_USA  PREGDP_USA 
##      "Date"   "numeric"   "numeric"   "numeric"

Trên đây là biểu đồ thể hiện GDP của Mỹ từ 1-2022 đến 7-2023. Đường màu xanh nước biến thể hiện GDP của Mỹ, đường màu đỏ thể hiện GDP dự đoán của các chuyên gia. Theo biểu đố ta thấy, GDP Mỹ ghi nhận mức tăng trưởng 2.4% trong Q2/2023, vượt mức dự báo 1.8% của các chuyên gia và cao hơn mức tăng trưởng 2% của Q1/2023. Cục dự trữ liên bang Mỹ (FED) vừa tăng lãi suất điều hành thêm 25 điểm (5,25%-5.5%) trong phiên họp mới nhất. Điều này ngụ ý rằng, tuy nền kinh tế của Mỹ đang đối mặt với áp lực lạm phát và lãi suất điều hành cao nhưng GDP vẫn tăng trưởng mạnh.

Tổng sản phẩm quốc nội của Việt Nam:

library(readxl)
gdpvn <- read_excel("D:\\Vĩ mô\\Vietnam_gdp.xlsx")

Trực quan hóa tổng sản phẩm quốc nội của Việt Nam như sau:

library(ggplot2)
w_color <- "#973d4c"
n_color <- "#2dc0d2"  
bgr_color <- "#d9e9f0"
grid_color <- "#b2c1ca"
icon_color <- "#ed1c24"
gdpvn$Date <- as.Date(gdpvn$Date)
ggplot(data=gdpvn,aes(x=Date))+
  geom_line(aes(y=VGDP),color="blue",size=1) +
  geom_line(aes(y=Pre_VGDP),color="red",size=1)+
  geom_point(data=gdpvn %>% filter(VGDP==0.0414),aes(Date,VGDP),color="blue",size=3)+
 annotate("text", 
           label = "4.14%", 
           x = as.Date("2023-06-29"), y = 0.0414, 
           size = 4, hjust = 1, vjust = -1,color="blue")+ 
  geom_point(data=gdpvn %>% filter(Pre_VGDP==0.0328),aes(Date,Pre_VGDP),color="red",size=3)+
 annotate("text", 
           label = "3.28%", 
           x = as.Date("2023-06-29"), y = 0.0328, 
           size = 4, hjust = 1, vjust = 1,color="red")+
  labs(title="Tổng sản phẩm quốc nội Việt Nam (%)",x= "Ngày" ,y=element_blank(),
       caption="Dữ liệu được lấy trên trang investing.com")+
  scale_x_date(date_labels = "%m/%Y", date_breaks = "2 month", name = "Ngày ")+
  scale_y_continuous(breaks = seq(-0.02, 5, 0.01))+
  theme(plot.caption = element_text(face = "italic",size=10))+
  theme(plot.background = element_rect(fill = "burlywood1" , color = NA)) +
  theme(panel.background = element_rect(fill = "burlywood1",color = NA)) +
  theme(plot.margin = unit(rep(0.7, 4), "cm")) +
  theme(panel.grid.major = element_blank()) + 
  theme(panel.grid.minor = element_blank())

Đường màu xanh thể hiện GDP thực tế, đường màu đỏ thể hiện GDP kỳ trước của Việt Nam. Ta thấy GDP của Việt Nam vào cuối tháng 6/2023 là 4.14% cao hơn GDP quý trước là 3.28%

4.1.2 Đầu tư công:

Kể từ 2023, Chính phủ Việt Nam đã đẩy mạnh đầu tư công để thúc đẩy nền kinh tế phát triển trong bối cảnh vốn tư nhân và vốn FDI bị thoái do sức ép của lạm phát. Ta có biểu đồ đầu tư công qua từng năm như sau:

gov <- read_excel("D:\\Vĩ mô\\GOVINVESTMENT.xlsx")
datatable(gov)
gov$rDTC<- c(NA, diff(gov$DTC) / gov$DTC[-length(gov$DTC)]) * 100
library(tidyverse)
ggplot(gov,aes(x=YEAR,y=DTC))+
  geom_col(width=0.7,fill="#377eb8")+
  geom_col(data=gov %>% filter(YEAR==2023),aes(YEAR,DTC),width=0.7,fill= "#973d4c")+
  geom_text(aes(label = DTC), hjust = 1.2, color = "white", size = 5)+
  scale_y_continuous(breaks = seq(-0, 1000,100))+
  labs(x= "Năm",y="Đầu tư công (Nghìn tỷ đồng)",
       title="Kế hoạch giải ngân đầu tư công của chính phủ từ 2019-2023",
       caption="Nguồn: Tổng cục thống kê")+
  coord_flip()

Ta thấy trong năm 2023, với mục tiêu phục hồi nền kinh tế, chính phủ dự định giải ngân 710 nghìn tỷ đồng, cao nhất trong khoảng từ 2019-2023.

Chỉ số

4.2 Biến động giá của cổ phiếu bất động sản trong giai đoạn COVID-19

Trong phần này, ta có bộ dữ liệu về giá của 2 cổ phiếu bất động sản nằm trong rổ VN30 bao gồm Novaland (NVL) và Vinhome (VHM) trong giai đoạn COVID-19 và chiến tranh giữa Nga-Ukraine. Dữ liệu được thu thập từ 01-01-2020 đến 02-08-2023 trên trang web investing.com. Các biến có trong bộ dữ liệu bao gồm:

  • DATE: ngày (từ 1-1-2020 đến 30-1-2023)

  • NVL: Giá cổ phiếu Novaland (VND).

  • VHM: giá cổ phiếu Vinhomes (VND).

library(readxl)
data <- read_excel("D:\\DATA\\batdongsan.xlsx")

Vẽ biểu đồ đường thể hiện xu hướng giá:

library(tidyverse)
library(ggplot2)
dataprice <- data %>% pivot_longer(cols=c(2,3),names_to = "Stock",values_to = "Price")
p <- ggplot(dataprice, aes(x = DATE),color=Stock) +
  geom_line(aes(y = Price,color=Stock), linetype = "solid",size=1) +
  facet_wrap(~Stock)+
  scale_y_continuous(breaks=seq(0,100000,10000))+
  labs(title = "Cổ phiếu bất động sản", y = "Giá (VND)",x="Date",
       caption="Dữ liệu được lấy trên investing.com",
       subtitle="Xu hướng giá 2 cổ phiếu Novaland và Vinhome từ 2020 đến 8/2023") +
  theme(plot.caption = element_text(face = "italic",size=10)) +
  theme(plot.background = element_rect(fill = "lightyellow" , color = NA)) +
  theme(panel.background = element_rect(fill = "#444B5A", color = NA))+
  theme(legend.text = element_text(size =10, 
                                   face = "bold", 
                                   family = "serif"))+
  theme(panel.grid.major = element_blank()) + 
  theme(panel.grid.minor = element_blank())
p

Ta thấy đường màu đỏ là giá cổ phiếu Novaland, đường màu xanh là giá cổ phiếu Vinhomes. Dựa vào biểu đồ ta có thể thấy, giá 2 cổ phiếu này biến động rất mạnh trong cả 2 giai đoạn COVID-19 và chiến tranh giữa Nga - Ukraine.Cụ thể dựa vào biểu đồ trên, ta có thể thấy giá của cổ phiếu NVL tăng rất mạnh, từ 30000VND/cổ phiếu từ cuối năm 2020 đến trên 90000vnd/ cổ phiếu vào cuối năm 2021, giá của cổ phiếu VHM tăng từ 50000vnd/cổ phiếu từ khoảng tháng 3/2020 lên xấp xỉ 90000vnd/ cổ phiếu vào cuối năm 2021.Trong giai đoạn này, ta thấy cổ phiếu NVL dốc hơn nhiều so với cổ phiếu VHM, điều đó chứng tỏ, cổ phiếu NVL biến động mạnh hơn cổ phiếu VHM.

Tuy nhiên, không phải lúc nào sự tăng trưởng cung tiền cũng tốt cho nền kinh tế, bởi vì nguồn lực sản xuất đều có giới hạn. Vào đầu năm 2022, do lượng tiền bơm vào nền kinh tế quá nhiều, sự tăng trưởng của nền kinh tế không theo kịp sự tăng trưởng của cung tiền. Thêm vào đó cộng hưởng với việc xung đột giữa Nga - Ukraine xảy ra vào những tháng đầu năm 2022 gây ra khủng hoảng năng lượng, làm tăng giá. Từ đó, lạm phát đạt đỉnh.. Từ đây, lượng tiền trong các kênh đầu tư bị hút mạnh về phía các ngân hàng trung ương và Việt Nam cũng không ngoại lệ, ngân hàng trung ương Việt Nam thực hiện việc tăng lãi suất liên tục, có thời điểm một ngân hàng có lãi suất là 12%/năm. Kết quả thanh khoản trên thị trường chứng khoán sụt giảm trầm trọng. Ta thấy cổ phiếu NVL từ 80000VND/ cổ phiếu giảm xuống còn dưới 20000vnd/ cổ phiếu, cổ phiếu VHM từ 80000vnd giảm xuống còn 45000vnd/ cổ phiếu. Tiếp tục cổ phiêú NVL biến động mạnh hơn cổ phiếu VHM. Đặc biệt, theo thống kê thì cố phiếu NVL bị giảm giàn 14 lần liên tiếp. Kết quả trên là bằng chứng chuẩn xác cho việc trong giai đoạn COVID-19 và chiến tranh giữa Nga - Ukraine, cổ phiếu thị trường bất động sản biến động rất mạnh.

Gần đây, ngân hàng trung ương Việt Nam đã thực hiện nới lỏng tiền tệ bằng cách hạ lãi suất. Tới giữa năm 2023, ngân hàng trung ương Việt Nam đã hạ lãi suất 3 lần liên tiếp. Ta có thể thấy giá của cổ phiếu bất động sản đã có xu hướng nhích lên dần và có lẽ trong tương lai cổ phiếu bất động sản sẽ hồi phục trở lại

Tiếp theo để thấy rõ sự biến động ta chuyển dữ liệu của 2 biến này về dạng tỷ suất lợi nhuận hằng ngày. Mục đích chính là để cho 2 chuỗi time series của chúng ta có tính dừng và về cùng một đơn vị để thấy được sự biến động tỷ suất sinh lợi theo thời gian. Tính dừng (stationary) là một giả định quan trọng trong nhiều mô hình chuỗi thời gian, bao gồm mô hình GARCH, DECO-GARCH, GARCH-COPULA… Tỷ suất lợi nhuận hàng ngày đã được phát hiện là một chuỗi thời gian có tính dừng, có nghĩa là nó có một trung bình và phương sai không đổi theo thời gian. Điều này cho phép sử dụng các mô hình chuỗi thời gian để phân tích và dự báo giá cổ phiếu trong tương lai. Để thực hiện điều này, ta có thể chuyển dữ liệu giá về dạng log_return như sau:

rNVL <- data$NVL %>% 
  lag() %>%                  # Lấy giá trị trước đó
  log() - log(data$NVL)        # Tính toán log return
rVHM <- data$VHM %>% 
  lag() %>%                  # Lấy giá trị trước đó
  log() - log(data$VHM)        # Tính toán log return
return <- data.frame(data$DATE,rNVL,rVHM)

Sau khi thực hiện chuyển đổi chuỗi dữ liệu giá về dạng tỷ suất sinh lợi, ta thực hiện vẽ biểu đồ chuỗi tỷ suất sinh lợi của NVL và VHM như sau:

datareturn <- return %>% pivot_longer(cols=c(2,3),names_to = "Stock",values_to = "Return")
q <- ggplot(datareturn, aes(x = data.DATE)) +
  geom_line(aes(y = Return,color=Stock), linetype = "solid",size=0.8) +
  facet_wrap(~Stock)+
  scale_y_continuous(breaks = seq(-0.07, 0.07, 0.01),labels=percent)+
  labs(title = "Cổ phiếu bất động sản", y = "Tỷ suất sinh lợi",x="Ngày") +
  theme(plot.background = element_rect(fill = bgr_color , color = NA))+
  theme(panel.grid.major = element_blank()) + 
  theme(panel.grid.minor = element_blank())
q
## Warning: Removed 2 rows containing missing values (`geom_line()`).

Biểu đồ màu đỏ thể hiện sự biến động tỷ suất sinh lợi của cổ phiếu NVL và biểu đồ màu xanh của cổ phiếu VHM. Giống với biểu đồ giá, tỷ suất sinh lợi của NVL và VHM biến động cực kỳ mạnh trong năm 2021, có một vài đợt thay đổi hết biên độ lên tới 0.07 (7%) và trong giai đoạn này, đa số là là tăng trần. Còn trong giai đoạn xung đột giữa Nga - Ukraine, có rất nhiều thời điểm cả 2 cổ phiếu này thay đổi hết biên độ, cụ thể cổ phiếu NVL có 14 lần giảm sàn liên tiếp (-7%). Và cổ phiếu VHM cũng có 1 vài lần giảm sàn.

Ta vẽ biểu đồ thể hiện giá và tỷ suất sinh lợi của 2 cổ phiếu này để xem bộ dữ liệu nào sẽ phù hợp để đưa vào các mô hình như sau:

phanphoigia <- dataprice %>% ggplot(aes(x = Price)) +
  geom_histogram(color="black",fill="blue")+
  facet_wrap(~Stock)+
  labs(title = "Phân phối giá",
       x = "Giá",
       y = "Tần số đếm")
phanphoireturn <- datareturn %>% ggplot(aes(x = Return)) +
  geom_histogram(color="black",fill="blue")+
  facet_wrap(~Stock)+
  labs(title = "Phân phối tỷ suất sinh lợi",
       x = "Lợi suất",
       y = "Tần số đếm")
phanphoigia
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

phanphoireturn
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 2 rows containing non-finite values (`stat_bin()`).

Nhìn vào đồ thị phân phối giá, ta thấy cứ đến một khoảng giá bất kì sẽ có một giá trị trung bình và phương sai khác nhau, do đó dữ liệu giá sẽ không có tính dừng,. Nói cách khác, với dữ liệu giá thì giá trị trung bình và phương sai của giá sẽ thay đổi theo thời gian. Còn nhìn vào biểu đồ phân phối tỷ suất sinh lợi, ta thấy rõ phân phối của chúng và giá trị trung bình, phương sai chỉ có 1. Hay nói cách khác, giá trị trung bình và phương sai của tỷ suất sinh lợi sẽ không đổi theo thời gian. Do đó, nếu đưa dữ liệu vào các mô hình dự báo giá như GARCH, DECO-GARCH, spillover index… Ta sẽ dùng dữ liệu tỷ suất sinh lợi (log return).

5 TÀI LIỆU THAM KHẢO:

  • Waskom, M. L. (2021). Seaborn: statistical data visualization. Journal of Open Source Software, 6(60), 3021.
  • Sadiku, M., Shadare, A. E., Musa, S. M., Akujuobi, C. M., & Perry, R. (2016). Data visualization. International Journal of Engineering Research And Advanced Technology (IJERAT), 2(12), 11-16.