Histogram cho bạn thấy gì
Histogram trả lời một câu hỏi về một biến số: các giá trị phân bố như thế nào? Nó cắt khoảng giá trị của dữ liệu thành các khoảng liên tiếp (bin), đếm xem có bao nhiêu quan sát rơi vào mỗi khoảng, rồi vẽ mỗi bin một cột có chiều cao bằng số đếm đó. Chỗ dữ liệu dày thì cột cao; chỗ thưa thì cột thấp.
Chỉ một hình đó cho bạn biết những điều mà trung bình và độ lệch chuẩn không nói được: dữ liệu có một đỉnh hay hai, đối xứng hay lệch về một phía, và có giá trị lạc nào nằm xa phần còn lại không. Đây thường là biểu đồ đầu tiên cần vẽ khi bạn gặp một bộ dữ liệu mới, đi cùng với các con số từ thống kê mô tả.
Trong R, hàm đó là hist(), và chỉ cần một dòng.
Histogram đầu tiên với hist()
Hãy mô phỏng chiều cao của 200 người, phân phối chuẩn quanh 170 cm với độ lệch chuẩn 10 (xem số ngẫu nhiên để biết set.seed() và rnorm() làm gì):
set.seed(42)
heights <- rnorm(200, mean = 170, sd = 10)
hist(heights)
R tự chọn các bin và vẽ một chồng cột hình chuông: cột thấp gần 145 cm, cao dần qua khoảng 160, đạt đỉnh quanh 170, rồi giảm dần đối xứng sau 190. Trục dọc có nhãn "Frequency", tức số đếm thô, còn tiêu đề và nhãn trục lấy từ tên biến.
Mặc định được cố ý làm đơn giản. Các đối số trang trí quen thuộc đều dùng được ở đây:
hist(heights,
main = "Distribution of heights",
xlab = "Height (cm)",
col = "steelblue",
border = "white")
col tô màu cột, border tô màu đường viền; border = "white" cho kiểu cột tách bạch gọn gàng mà bạn thấy trong hầu hết các ấn phẩm. Mọi điều hướng dẫn plot() nói về màu sắc và tiêu đề đều áp dụng nguyên vẹn.
Độ rộng bin: đối số breaks
Đối số quan trọng nhất của hist() là breaks, vì độ rộng bin quyết định câu chuyện biểu đồ kể. Cùng dữ liệu, hai thiết lập:
hist(heights, breaks = 5) # five wide bins: a crude, blocky bell
hist(heights, breaks = 30) # thirty narrow bins: detail, plus noise
Với breaks = 5, histogram thô đến mức mọi thứ trông như một cái bướu trơn duy nhất: một cụm thứ hai hay một khoảng trống trong dữ liệu sẽ không thể thấy được. Với breaks = 30, bạn thấy cấu trúc chi tiết, nhưng các dao động ngẫu nhiên bắt đầu giả dạng thành đặc điểm. Không cách nào là "đúng"; cách làm trung thực là thử vài thiết lập và xem đặc điểm nào còn trụ lại.
breaks nhận ba dạng:
- Một con số:
breaks = 30là một gợi ý về số bin. R điều chỉnh để rơi vào các mốc gọn gàng, nên bạn có thể nhận 28 hoặc 33 bin. Ai cũng bất ngờ vì điều này một lần. - Một vector điểm cắt:
breaks = seq(140, 200, by = 5)là các mép bin chính xác, không thương lượng. Dùng cách này khi các bin phải thẳng hàng giữa nhiều histogram bạn đang so sánh. - Tên một quy tắc:
breaks = "FD"cho quy tắc Freedman-Diaconis, chọn độ rộng dựa trên độ phân tán và cỡ mẫu của dữ liệu, và hoạt động tốt với dữ liệu lệch.
Histogram mật độ và đường cong phân phối chuẩn
Mặc định chiều cao cột là số đếm (freq = TRUE). Đặt freq = FALSE sẽ co giãn các cột để tổng diện tích của chúng bằng 1, tức thang mật độ. Hình dạng không đổi; trục dọc thì đổi. Mục đích là histogram mật độ nằm trên cùng thang với hàm mật độ xác suất, nên bạn có thể vẽ đường cong lý thuyết chồng thẳng lên dữ liệu:
hist(heights,
freq = FALSE,
col = "gray90",
main = "Heights vs. a normal curve",
xlab = "Height (cm)")
curve(dnorm(x, mean = mean(heights), sd = sd(heights)),
add = TRUE, col = "tomato", lwd = 2)
curve() với add = TRUE vẽ đường cong hình chuông lên trên histogram có sẵn (x bên trong dnorm(x, ...) là chỗ giữ chỗ do curve() điền vào, không phải biến của bạn). Nếu các cột ôm sát đường cong, mô hình chuẩn là hợp lý; chỗ nào cột phình ra khỏi đường cong (một đuôi nặng, một đỉnh thứ hai), mô hình đang thiếu điều gì đó. Bỏ freq = FALSE thì đường cong sẽ bò sát đáy biểu đồ chẳng để làm gì, vì số đếm và mật độ nằm trên hai thang khác nhau.
Những con số đằng sau các cột
hist() không chỉ vẽ: nó trả về cách chia bin dưới dạng một list. Với plot = FALSE, nó bỏ hẳn phần vẽ và chỉ tính toán, nghĩa là bạn có thể chạy ví dụ này ngay tại đây:
h$counts chính là histogram dưới dạng dữ liệu: mỗi con số là chiều cao của một cột. Dòng table(cut(...)) là phiên bản dạng văn bản tương đương: cut() chia bin các giá trị, table() đếm từng bin, và đây là một phép kiểm tra nhanh đáng in ra trước hoặc thay cho biểu đồ. Nếu bạn gán mà không có plot = FALSE (h <- hist(heights)), R vừa vẽ vừa trả về list; phép gán không ngăn biểu đồ được vẽ.
Histogram với ggplot2
Phiên bản ggplot2 đổi breaks lấy binwidth, thường là nút chỉnh tự nhiên hơn: bạn nói một bin rộng bao nhiêu theo đơn vị của dữ liệu thay vì muốn bao nhiêu bin:
library(ggplot2)
ggplot(data.frame(heights), aes(x = heights)) +
geom_histogram(binwidth = 5, fill = "steelblue", color = "white") +
labs(title = "Distribution of heights", x = "Height (cm)", y = "Count")
binwidth = 5 nghĩa là mỗi cột trải rộng 5 cm. ggplot2 cảnh báo nếu bạn không đặt binwidth và lặng lẽ dùng mặc định 30 bin: hãy để ý cảnh báo đó, vì mặc định hiếm khi là độ rộng phù hợp với dữ liệu của bạn. Để xem nhanh một biến, hist() gõ ít hơn; ggplot2 đáng giá khi histogram cần facet, nhóm, hoặc một theme nhất quán với các hình khác.
Những điều cần nhớ
- Histogram cho thấy phân phối của một biến số:
hist(x)là xong. breakslà đối số quan trọng: một con số chỉ là gợi ý, một vector đặt mép chính xác,"FD"chọn một độ rộng có cơ sở. Luôn thử nhiều hơn một thiết lập.freq = FALSEchuyển sang thang mật độ, nhờ đócurve(dnorm(...), add = TRUE)vẽ chồng đường cong chuẩn một cách có ý nghĩa.hist(x, plot = FALSE)trả về các bin dưới dạng dữ liệu ($breaks,$counts,$mids);table(cut(x, breaks))là phiên bản tương đương chỉ dùng văn bản.- Trong ggplot2, dùng
geom_histogram(binwidth = ...)và tự đặtbinwidth.
Tiếp theo: boxplot, biểu đồ phân phối thật sự tỏa sáng khi bạn so sánh các nhóm cạnh nhau.
Câu hỏi thường gặp
Vẽ histogram trong R như thế nào?
Gọi hist(x) với một vector số. R chia khoảng giá trị của x thành các bin và vẽ mỗi bin một cột, chiều cao cột cho biết có bao nhiêu giá trị rơi vào bin đó. Thêm breaks = để điều chỉnh số bin và col = để tô màu các cột.
Đối số breaks trong hist() làm gì?
Nó điều khiển cách chia bin. Một con số như breaks = 30 là gợi ý về số bin cần dùng (R làm tròn để có các mốc gọn gàng), một vector như breaks = seq(140, 200, by = 5) đặt chính xác các điểm cắt, còn breaks = "FD" dùng quy tắc Freedman-Diaconis.
Vẽ đường cong phân phối chuẩn lên histogram trong R như thế nào?
Vẽ histogram trên thang mật độ với freq = FALSE, rồi thêm đường cong bằng curve(dnorm(x, mean = mean(data), sd = sd(data)), add = TRUE). Trên thang tần suất, đường cong sẽ nằm sát số 0 và chẳng có ích gì, nên freq = FALSE là bắt buộc.
Histogram và biểu đồ cột khác nhau thế nào?
Histogram chia bin cho một biến số, nên trục ngang là một thang liên tục và các cột sát nhau. Biểu đồ cột so sánh các nhóm riêng biệt, nên các cột tách rời. Trong R, đó là hist() cho số và barplot() cho số đếm theo nhóm.