“Hãy làm những việc bình thường bằng lòng say mê phi thường, thành công sẽ đến với bạn.”

Trong chương này chúng ta sẽ sử dụng tập dữ liệu sẵn có trong R là mtcars để minh họa cách vẽ một số biểu đồ cơ bản.

mtcars
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2

Trong tập dữ liệu này ta thấy biến cyl (số xi lanh) là biến định lượng rời rạc. Trong tập dữ liệu này nó chỉ có 3 giá trị là 4, 6 và 8. Do đó để minh họa cho việc vẽ biểu đồ chúng ta tạm xem nó là biến định tính. Tượng tự như vậy cho hai biến gearcarb.

Biểu đồ cột (biểu đồ thanh)

Biểu đồ cột được dùng để thể hiện phân phối của biến định tính. Để vẽ biểu đồ cột trước tiên chúng ta cần lập bảng phân phối tần số bằng hàm table() và sau đó chúng ta vẽ biểu đồ cột bằng hàm barplot(). Nếu biến định tính thuộc lớp factor thì chúng ta chỉ cần dùng hàm plot().

class(mtcars$cyl)
## [1] "numeric"
cyl.freq <- table(mtcars$cyl)
cyl.freq
## 
##  4  6  8 
## 11  7 14
barplot(cyl.freq, xlab = "Số xi lanh", ylab = "Tần số", 
        main = "Biểu đồ cột của số xi lanh", col = c("red", "green", "blue"))

Biểu đồ cho ta thấy động cơ 8 xi lanh chiếm nhiều nhất và động cơ 6 xi lanh chiếm ít nhất trong tập dữ liệu mẫu này.

Dưới đây chúng ta sẽ đưa biến cyl sang dạng factor và vẽ biểu đồ cột.

cyl.fac <- factor(mtcars$cyl)
plot(cyl.fac)

Chúng ta tự thêm vào hàm plot() tên biểu đồ, tên trục và màu cho các cột tương tự như barplot() ở trên.

Tương tự như trên, chúng ta có thể vẽ biểu đồ cột xếp chồng hoặc xếp cạnh để thể hiện mối liên hệ giữa 2 biến định tính cylam. Trước tiên chúng ta cũng dùng hàm table() để lập bảng chéo (bảng phân phối tần số 2 chiều) và sau đó cũng dùng hàm barplot() để vẽ biểu đồ.

cyl.freq.matrix <- table(mtcars$am,mtcars$cyl)
cyl.freq.matrix
##    
##      4  6  8
##   0  3  4 12
##   1  8  3  2
barplot(cyl.freq.matrix, beside = T, col = c("red","blue"), xlab = "Số xi lanh", 
        ylab = "Tần số", legend.text = c("auto","manual"), args.legend=list(x="topleft"))

Biểu đồ cho thấy đa số động cơ 8 xi lanh có hộp số tự động, động cơ 4 xi lanh thì đa số điều chỉnh bằng tay, còn động cơ 6 xi lanh thì hộp số tự động có phần nhiều hơn. Điều này có nghĩa là khi số xi lanh càng nhiều thì động cơ thiên về hộp số tự động nhiều hơn và điều chỉnh bằng tay ít hơn.

Chúng ta có thể thay đổi đối số beside = F để được biểu đồ cột xếp chồng.

barplot(cyl.freq.matrix, beside = F, col = c("red","blue"), xlab = "Số xi lanh",
        ylab = "Tần số", legend.text = c("auto","manual"), args.legend=list(x="topleft"))

Biểu đồ tròn

Biểu đồ tròn có chức năng tương tự như biểu đồ cột. Để vẽ biểu đồ tròn ta dùng hàm pie().

pie(table(mtcars$cyl), col = rainbow(3), main = "Biểu đồ tròn của số xi lanh")

Biểu đồ tần số/tần suất (Histogram)

Histogram dùng để thể hiện phân phối của biến định lượng. Để vẽ histogram chúng ta dùng hàm hist().

hist(mtcars$hp, main = "Phân phối của mã lực động cơ", 
     xlab = "Mã lực", ylab = "Tần số", col = "lightblue")

Biểu đồ cho thấy dữ liệu mã lực có phân phối lệch phải. Mã lực động cơ thường có giá trị từ 50 đến 350 mã lực. Đa số động cơ có mã lực từ 50 đến 250, trong đó chiếm nhiều nhất là từ 100 đến 150 mã lực.

hist(mtcars$hp, breaks = seq(0, 400, 25), main = "Horsepower",xlab = "HP", col = "lightgreen")
abline(v = c(mean(mtcars$hp), median(mtcars$hp)), lty = c(2, 3), lwd = 2, col = c("red", "blue"))
legend("topright", legend = c("mean HP", "median HP"), lty = c(2, 3), lwd = 2, col = c("red", "blue"))

Biểu đồ nhánh và lá

Biểu đồ nhánh và lá có chức năng tương tự như histogram nhưng chỉ được dùng để hiện thị phân phối của các tập dữ liệu có kích thước vừa phải. Để vẽ biểu đồ nhánh và lá chúng ta dùng hàm stem().

stem(mtcars$hp)
## 
##   The decimal point is 2 digit(s) to the right of the |
## 
##   0 | 5677799
##   1 | 0011111122
##   1 | 55888888
##   2 | 123
##   2 | 556
##   3 | 4

Nhìn vào biểu đồ ta thấy dữ liệu có phân phối lệch phải. Biểu đồ nhánh lá có ưu điểm là các giá trị dữ liệu được hiện thị trên biểu đồ.

Chúng ta cũng có thể vẽ biểu đồ nhánh và lá giáp lưng (back-to-back stem and leaf plot) bằng cách sử dụng hàm stem.leaf.backback() trong gói aplpack để so sánh phân phối mã lực động cơ có hộp số điều chỉnh tự động (am = 0) và điều chỉnh bằng tay (am = 1).

library(aplpack)
stem.leaf.backback(x = mtcars$hp[mtcars$am == 0], y = mtcars$hp[mtcars$am == 1], m = 1)
## __________________________________________
##   1 | 2: represents 120, leaf unit: 10 
## mtcars$hp[mtcars$am == 0]
##                         mtcars$hp[mtcars$am == 1]
## __________________________________________
##     3           996| 0 |566699        6   
##   (11)  88877552210| 1 |01117        (5)  
##     5         44310| 2 |6             2   
##                    | 3 |3             1   
## __________________________________________
## n:               19     13             
## __________________________________________

Ta thấy dữ liệu mã lực động cơ có hộp số điều chỉnh tự động có phân phối cân xứng và đồng đều hơn so với phân phối dữ liệu mã lực động cơ có hộp số điều chỉnh bằng tay (lệch phải).

Biểu đồ hộp

Biểu đồ hộp cũng có chức năng tương tự như histogram. Để vẽ biểu đồ hộp chúng ta dùng hàm boxplot().

boxplot(mtcars$hp, ylab = "Mã lực", col = 'lightgreen')

Từ biểu đồ ta cũng thấy dữ liệu có phân phối lệch phải và có một giá trị ngoại vi (outlier). Để xác định giá trị ngoại vi chúng ta dùng hàm boxplot.stats().

boxplot.stats(mtcars$hp)
## $stats
## [1]  52  96 123 180 264
## 
## $n
## [1] 32
## 
## $conf
## [1]  99.5382 146.4618
## 
## $out
## [1] 335

Ta thấy hàm boxplot.stats() cho kết quả là một list và thành phần cuối cùng out của list chính là giá trị outlier. Ở đây ta chỉ có một giá trị outlier là 335.

Chúng ta cũng có thể vẽ biểu đồ hộp thể hiện phân phối của mã (hp) lực tùy theo số xi lanh (cyl) của động cơ.

boxplot(
  mtcars$hp ~ mtcars$cyl, 
  xlab = "Số xi lanh", 
  ylab = "Mã lực", 
  col = c("orange", "lightgreen", "lightblue"),
  main = "Biểu đồ hộp: Mã lực ~ số xi lanh"
)

Biểu đồ hiển thị một điều hiển nhiên là động cơ có càng nhiều xi lanh thì mã lực càng lớn. Thêm nữa, chúng ta cũng có thể vẽ biểu đồ hộp thể hiện phân phối của mã (hp) lực tùy theo số xi lanh (cyl) và số bánh răng chuyển tiếp (gear) của động cơ.

boxplot(
  mtcars$hp ~ mtcars$cyl + mtcars$gear, 
  xlab = "Số xi lanh (4, 6, 8) kết hợp số bánh răng chuyển tiếp (3, 4, 5)", 
  ylab = "Mã lực", 
  col = rainbow(9),
  main = "Biểu đồ hộp: Mã lực ~ số xi lanh + số bánh răng chuyển tiếp"
)

Từ biểu đồ này ta thấy động cơ có 8 xi lanh và 5 bánh răng chuyển tiếp có mã lực cao nhất và thấp nhất là động cơ có 4 xi lanh và 4 bánh răng chuyển tiếp.

Biểu đồ tán xạ

Biểu đồ tán xạ được dùng để thể hiện mối liên hệ giữa 2 biến định lượng. Để vẽ biểu đồ tán xạ (scatter plot) chúng ta dùng hàm plot(y ~ x) hoặc plot(x, y).

plot(mtcars$mpg ~ mtcars$hp, xlab = "HP", ylab = "Miles/(US) gallon", col = "lightblue", pch = 19)

plot(mtcars$hp, mtcars$mpg, xlab = "HP", ylab = "Miles/(US) gallon", col = "blue", pch = 21)

Biểu đồ cho thấy giữa hai biến hpmpg có mối liên hệ tuyến tính nghịch.

Chúng ta cũng có thể vẽ biểu đồ tán xạ thể hiện mối liên hệ giữa 2 biến định lượng mpghp trong đó các điểm được phân loại theo giá trị của biến định tính cyl.

plot(mtcars$hp, mtcars$mpg, xlab = "HP", ylab = "Miles/(US) gallon", type = "n")
points(mtcars$hp[mtcars$cyl == 4], mtcars$mpg[mtcars$cyl == 4], pch = 1, col = "red")
points(mtcars$hp[mtcars$cyl == 6], mtcars$mpg[mtcars$cyl == 6], pch = 19, col = "lightgreen")
points(mtcars$hp[mtcars$cyl == 8], mtcars$mpg[mtcars$cyl == 8], pch = 1, col = "blue")
legend("topright", legend = c("4 xi lanh", "6 xi lanh", "8 xi lanh"), 
       col = c("red", "lightgreen", "blue"), pch = c(1, 19, 1))

Chúng ta cũng có thể dùng hàm pairs() để vẽ ma trận các biểu đồ tán xạ để thể hiện mối liên hệ giữa các cặp biến với nhau.

pairs(~ mpg + disp + hp + drat + wt + qsec, data = mtcars, col = "lightblue")

panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...)
{
    par(usr = c(0, 1, 0, 1))
    r <- abs(cor(x, y))
    txt <- format(c(r, 0.123456789), digits = digits)[1]
    txt <- paste0(prefix, txt)
    if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
    text(0.5, 0.5, txt, cex = cex.cor * r)
}
pairs(~ mpg + disp + hp + drat + wt + qsec, data = mtcars, col = "lightblue", lower.panel = panel.cor)

Biểu đồ chuỗi thời gian

Biểu đồ chuỗi thời gian dùng để biểu thị dữ liệu thay đổi theo thời gian. Để vẽ biểu đồ chuỗi thời gian chúng ta dùng hàm plot(). Chúng ta sẽ vẽ biểu đồ chuỗi thời gian thể hiện giá cổ phiếu của Google và Amazon được cho trong bảng sau.
Ngày GOOGL AMZN
27/01/2023 99.37 102.24
30/01/2023 96.94 100.55
31/01/2023 98.84 103.13
01/02/2023 100.43 105.15
02/02/2023 107.74 112.91
03/02/2023 104.78 103.39
06/02/2023 102.90 102.18
07/02/2023 107.64 102.11
08/02/2023 99.37 100.05
09/02/2023 95.01 98.24

Nhập dữ liệu vào R.

Ngay = c("27/01/2023","30/01/2023","31/01/2023","01/02/2023","02/02/2023","03/02/2023","06/02/2023","07/02/2023","08/02/2023","09/02/2023")
Ngay = as.Date(Ngay, "%d/%m/%Y") # chuyển Ngay ở dạng chuỗi thành số (ngày tháng năm thực).
GOOGL = c(99.37,96.94,98.84,100.43,107.74,104.78,102.90,107.64,99.37,95.01)
AMZN = c(102.24,100.55,103.13,105.15,112.91,103.39,102.18,102.11,100.05,98.24)

Vẽ biểu đồ chuỗi thời gian cho giá cổ phiếu Google.

plot(Ngay, GOOGL, type = "o", xlab = "Ngày", ylab = "Giá", pch = 19,
     main = "Giá cổ phiếu Google từ 27/01/2023 đến 09/02/2023",)

Chúng ta có thể thêm biểu đồ chuỗi thời gian cho giá cổ phiếu Amazon vào biểu đồ trên bằng cách dùng hàm lines().

plot(Ngay, GOOGL, type = "o", xlab = "Ngày", ylab = "Giá", pch = 19,
     main = "Giá cổ phiếu Google và Amazon từ 27/01/2023 đến 09/02/2023",
     ylim = c(min(min(AMZN), min(GOOGL)), max(max(AMZN),max(GOOGL))), col = "red", lty = 2)
lines(Ngay, AMZN , type = "o", pch = 18, col = "blue", lty = 3)
legend("topleft", legend = c("GOOGL", "AMZN"), col = c("red", "blue"), lty = c(2,3), pch = c(19,18))

Dưới đây là đoạn code minh họa cho thấy chúng ta có thể vẽ lên biều đồ nhiều thứ chúng ta muốn.

x <- 1:20
y <- c(-1.49, 3.37, 2.59, -2.78, -3.94, -0.92, 6.43, 8.51, 3.41, -8.23, -12.01, -6.58, 2.87, 
       14.12, 9.63, -4.58, -14.78, -11.67, 1.17, 15.62)
plot(x, y, type = "n", main = "")
abline(h=c(-5, 5), col = 'red', lty = 2, lwd = 2)
segments(x0 = c(5, 15), y0 = c(-5, -5), x1 = c(5, 15), y1 = c(5, 5), col = 'red', lty = 3, lwd = 2)
points(x[y >= 5], y[y >= 5], pch = 4, col = 'darkmagenta')
points(x[y <= -5], y[y <= -5], pch = 4, col = 'darkgreen')
points(x[(x >= 5 & x <= 15) & (y >-5 & y < 5)], y[(x >= 5 & x <= 15) & (y >- 5 & y < 5)], 
       col = "blue", pch = 19)
points(x[(x < 5 | x > 15) & (y > -5 & y < 5)], y[(x < 5 | x > 15) & (y > -5 & y < 5)])
lines(x, y, lty = 4)
arrows(x0 = 8, y0 = 14, x1 = 11, y1 = 2.5)
text(x = 8, y = 15, labels = "sweet spot")
legend(
  "bottomleft", 
  legend = c("overall process", "sweet", "standard", "too big", "too small",
             "sweet y range", "sweet x range"),
  col = c("black", "blue", "black", "darkmagenta", "darkgreen", "red", "red"),
  pch = c(NA, 19, 1, 4, 3, NA, NA), lty = c(4, NA, NA, NA, NA, 2, 3),
  lwd = c(1, NA, NA, NA, NA, 2, 2), pt.cex = c(NA, 1, 1, 1, 1, NA, NA),
  cex = 0.5
)

Bài tập 9.1.

  1. Xét tập dữ liệu sẵn có InsectSprays. Hãy thực hiện các yêu cầu sau:
    1. Hãy vẽ biểu đồ histogram cho biến count.
    2. Hãy cho biết số côn trùng tương ứng với mỗi loại thuốc trừ sâu bọ. Sau đó biểu diễn các con số này thành biểu đồ cột và biểu đồ tròn một cách hoàn chỉnh.
    3. Vẽ biểu đồ hộp cho số côn trùng tùy theo từng loại thuốc.
  2. Xét dữ liệu sẵn có iris. Hãy thực hiện các yêu cầu sau:
    1. Hãy vẽ biểu đồ tán xạ thể hiện mối liên hệ giữa hai biến Petal.LengthPetal.Width.
    2. Hãy vẽ biểu đồ tán xạ thể hiện mối liên hệ giữa hai biến Petal.LengthPetal.Width trong đó các điểm được phân biệt theo biến Species.
    3. Hãy vẽ ma trận các biểu đồ tán xạ thể hiện mối liên hệ giữa các biến định lượng.
  3. Hãy vẽ biểu đồ cột cho bảng tần số sau đây:
    Hệ đào tạo Số lượng
    Đại học chính quy 10000
    Đại học liên thông 1500
    Đại học tại chức 1000
    Cao đẳng 2000
    Cao học 500
d. Hãy vẽ biểu đồ chuỗi thời gian thể hiện nhiệt độ ở TP. Hồ Chí Minh qua các tháng như sau.
Tháng Cao Trung bình Thấp
Tháng 1 32 26 22
Tháng 2 33 27 23
Tháng 3 34 28 25
Tháng 4 34 29 26
Tháng 5 34 29 26
Tháng 6 33 28 25
Tháng 7 32 27 25
Tháng 8 32 28 25
Tháng 9 31 27 24
Tháng 10 31 27 24
Tháng 11 31 27 23
Tháng 12 31 26 22

Tóm tắt

Hàm Chức năng
barplot() Vẽ biểu đồ cột
pie() Vẽ biểu đồ tròn
hist() Vẽ histogram
boxplot() Vẽ biểu đồ hộp
pairs() Ma trận các biểu đồ tán xạ
lines() Thêm đường vẽ vào biểu đồ

Tài liệu tham khảo

Davies, Tilman M. 2016. The Book of R: A First Course in Programming and Statistics. No Starch Press.