“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 gear và
carb.
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 cyl và
am. 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 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")
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á 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 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ạ đượ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
hp và mpg 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 mpg và hp 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)
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.
InsectSprays. Hãy thực hiện các
yêu cầu sau:
count.iris. Hãy thực hiện các yêu cầu sau:
Petal.Length và Petal.Width.Petal.Length và Petal.Width trong đó các điểm
được phân biệt theo biến Species.| 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 |
| 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 |
| 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 đồ |