Trực quan hóa dữ liệu

Visualization in R

Sự cần thiết của trực quan dữ liệu

Một số khái niệm về trực quan

     Có một vấn đề được đặt ra là: Với hàng triệu mẫu DNA và con số ngày nay cùng với hàng triệu ca nhiễm COVID-19 trên toàn thế giới ngày càng gia tăng thì chúng ta cần làm gì để có thể biết được xu hướng, ý nghĩa và cách phân phối của dữ liệu (ứng với từng quốc gia cho các ca nhiễm COVID-19 chẳng hạn). Việc phân tích mối tương quan hoặc xu hướng phân bố của dữ liệu đóng vai trò cực kỳ quan trọng trong nghiên cứu khoa học và đánh giá thống kê.

The number of infected cases in INDIA

     Người Trung Hoa hay có câu một hình ảnh có giá trị tương đương với một vạn chữ. Quả đúng như vậy, với một “đại dương” số liệu thì việc khai thác hiệu quả “đại dương” này là một vấn đề nan giải. Chúng ta cần phải hiểu rằng, khi có dữ liệu thì việc truyền tải thông tin tới người khác là vô cùng khó khăn. Phải làm thế nào để họ hiểu, họ nắm được xem bộ dữ liệu đó nói về cái gì, miêu tả cái gì và rút ra điều gì từ bộ dữ liệu đó. Chữ viết hoàn toàn có thể sử dụng cho những bộ dữ liệu đơn giản nhưng không thể thực hiện được việc truyền tải nội dung về xu hướng và dao dộng của dữ liệu

Một số biểu đồ trực quan

     Hiển thị dữ liệu, mô phỏng dữ liệu hay trực quan dữ liệu (Visualization) nói chung là một bước quan trọng trong tổng thể phân tích dữ liệu. Trước khi phân tích bất kỳ một mô hình nào, việc đầu tiên là chúng ta cần “cảm thụ” được bộ dữ liệu đó, tức là có một cái nhìn khái quát nhất về bộ dữ liệu mà chúng ta đang có. Hiện nay, trong phân tích nghiên cứu khoa học, một số biểu đồ thường được sử dụng, đó là:

  1. Biểu đồ tương quan (scatterplot)
  2. Biểu đồ phân phối (histogram)
  3. Biểu đồ thanh (barchat)
  4. Biểu đồ hộp (box plot)

Lịch sử hiển thị dữ liệu

     Biểu đồ có một lịch sử rất thú vị. Trước thể kỷ 18, dữ liệu khoa học thường được trình bày dạng bảng (tables) và đôi khi biểu đồ được coi là vô dụng vì không phản ánh bất kỳ điều gì. Quan điểm này khá là sai lầm, năm 1786, William Playfair (một nhà kinh tế chính trị học) sáng tạo ra biểu đồ tròn (pie chart), biểu đồ thanh (bar chart) và biểu đồ dây (line chart), những cái mà chúng ta vẫn sử dụng cho tới ngày nay. Mãi đến năm 1832, nhà thiên văn học người Anh là Alexander S. Herche sáng chế ra biểu đồ tương quan (scatter plot) và trở thành rất phổ biến trong khoa học thực nghiệm.

Nguyên tắc thiết kế biểu đồ

     Hãy làm quen với Edward Tufte, vì ông là một guru - bậc thầy về biểu đồ. Ông là giáo sư thống kê học của Đại học Yale, giáo sư chính trị học và giáo sư về khoa học máy tính của đại học Yale, ông là người có ảnh hưởng rất lớn tới lĩnh vực trực quan dữ liệu. Ông là người đã dám thế chấp căn nhà của mình để vay tiền ngân hàng nghiên cứu và cho ra công trình data visualization mà sau này ông không bao giờ phải hối hận. Tờ báo New York Times gọi ông là Leonardo Da Vinci of Data

     Edward Tufte đặt ra 4 triết lý và nguyên tắc chính trong trình bày dữ liệu bằng biểu đồ. Có thể tóm gọn như sau “Graphical excellence is that which gives to the viewer the greatest number of ideas in the shortest time with the least ink in the smallest space”. Như vậy, khi trình bày dữ liệu bằng biểu đồ phải để ý tới thông tin của 4 khía cạnh: Lượng thông tin, thời gian, lượng mực in và không gian.

     Từ đó có thể hiểu 4 nguyên tắc chính khi trình bày dữ liệu chính là: Phản ảnh dữ liệu một cách đầy đủ, tối ưu hóa dữ liệu trên mực in, tối ưu hóa mật độ dữ liệu và trình bày dữ liệu chứ không phải trang trí biểu đồ.

Edward Tufte

Boxplot1

<>

Boxplot2

<>

Barplot1

Barplot1

Thư viện GGPLOT2

Giới thiệu về ggplot2

     Chương trình ggplot2 do tác giả Hadley Wickham phát triển và phổ biến là một thư viện rất có ích cho việc biên soạn biểu đồ với chất lượng cao. Cú pháp của ggplot2 được mô phỏng theo việc chồng lấp các lớp (layers); mỗi lớp sẽ có một chức năng riêng. Tuy nhiên có 3 layers chính, đó là:

  • Lớp xác định biến số cần trực quan dữ liệu
  • Lớp hình thức thể hiện
  • Lớp trang trí, gán nhãn cho biểu đồ..
    Hadley Wickham

Lớp biến số

     Về định nghĩa biến số, thông thường một biểu đồ thường có 2 biến số chính là \(x\)\(y\). Nếu chúng ta muốn thể hiện mối liên quan giữa giới tính và thu nhập thì thông thường \(x\) sẽ là biến giới tính và \(y\) là biến thu nhập. Ví dụ dưới đây chỉ ra mối liên hệ giữa thu nhập và tuổi thọ trung bình giữa các quốc gia trong thư viện ggplot2.

Cú pháp của lớp này như sau:

\(p=ggplot(data=gapminder,aes(x=gdpPercap,y=lifeExp))\)

p=ggplot(data=gapminder,aes(x=gdpPercap,y=lifeExp))
p + geom_point(aes(color = continent))

Hình thức thể hiện:

     Hình thức thể hiện của biến x và y thể hiện qua argument có tên là geom(), trong đó có một số loại phổ biến sau:

  • geom_point(): Biểu đồ tương quan
  • geom_box(): Biểu đồ hộp
  • geom_histogram(): Biểu đồ phân bố
  • geom_line(): Biểu đồ dây
  • geom_text(): Biểu đồ chữ viết
  • geom_smooth(): Chọn đường biểu diễn làm mịn dữ liệu
  • geom_jitter(): Tạo sàng rung, hiển thị dữ liệu, fix lỗi overplotting
  • geom_hline(): Đường biểu diễn nằm ngang
  • geom_vline(): Đường biểu diễn thẳng đứng

Trang trí biểu đồ

Tiêu đề của biểu đồ

ggtitle(“tên biểu đồ”) + theme(plot.title = element_text(line.height = 0.8, face = “bold”, hjust = 0.5))

Nhãn và trục tung, trục hoành

labs(x=“Tiêu đề trục x”, y = “Tiêu đề trục y”)

Màu và kích thước của nhãn trục tung và hoành

theme(axis.title.x = element_text(color = “blue, size = 14, face =”bold“), axis.title.y = element_text(color =”blue, size = 14, face =“bold”))

Khoảng cách giá trị của trục tung và trục hoành

scale_x_continuous(name=“…”, limits =c(min, max)) + scale_y_continuous(name=“…”, limits = c(min,max)) Một trong những lợi thế của ggplot2 là cho phép người sử dụng hoán chuyển dữ liệu ngày trong phần arguments của hàm ggplot. Chúng ta có thể hoán chuyển đơn vị của trục tung (thu nhập) sang đơn vị log:

p1 = ggplot(data=gapminder,aes(x=gdpPercap,y=lifeExp)) + geom_point(aes(color = continent)) 
p1 <- p1 + scale_x_log10() + geom_smooth(method="loess")
p1
## `geom_smooth()` using formula 'y ~ x'

Thực hành ggplot2

     Để áp dụng cách sử dụng thư viện ggplot2, chúng ta sử dụng bộ dữ liệu có tên là gapminder, vẽ biểu đồ tương quan giữa 2 biến là tuổi thọ trung bình và thu nhập bình quân. Xem qua về dữ liệu

mydata <- gapminder
head(gapminder)
## # A tibble: 6 x 6
##   country     continent  year lifeExp      pop gdpPercap
##   <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
## 1 Afghanistan Asia       1952    28.8  8425333      779.
## 2 Afghanistan Asia       1957    30.3  9240934      821.
## 3 Afghanistan Asia       1962    32.0 10267083      853.
## 4 Afghanistan Asia       1967    34.0 11537966      836.
## 5 Afghanistan Asia       1972    36.1 13079460      740.
## 6 Afghanistan Asia       1977    38.4 14880372      786.
str(gapminder)
## tibble [1,704 x 6] (S3: tbl_df/tbl/data.frame)
##  $ country  : Factor w/ 142 levels "Afghanistan",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ continent: Factor w/ 5 levels "Africa","Americas",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ year     : int [1:1704] 1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
##  $ lifeExp  : num [1:1704] 28.8 30.3 32 34 36.1 ...
##  $ pop      : int [1:1704] 8425333 9240934 10267083 11537966 13079460 14880372 12881816 13867957 16317921 22227415 ...
##  $ gdpPercap: num [1:1704] 779 821 853 836 740 ...

Chúng ta bắt đầu trực quan dữ liệu

p2 <- ggplot(data = mydata, mapping = aes(x = gdpPercap, y = lifeExp))
p2 + geom_point() -> p2 

Thêm một đường biểu diễn tương quan tuyến tính

p2 + geom_smooth(method = "loess") -> p2

Tuy nhiên, quá nhiều điểm dữ liệu cùng màu, rất khó phân biệt, trực quan theo biến lục địa

ggplot(data = mydata, mapping = aes(x = gdpPercap, y = lifeExp)) + geom_point(aes(color = continent)) +
  geom_smooth(method = "loess")
## `geom_smooth()` using formula 'y ~ x'

Chuyển sang đơn vị log() cho dễ nhìn

ggplot(data = mydata, mapping = aes(x = gdpPercap, y = lifeExp)) + geom_point(aes(color = continent)) +
  geom_smooth(method = "loess") +
  scale_x_log10()
## `geom_smooth()` using formula 'y ~ x'

Gán thêm các nhãn cho biểu đồ

ggplot(data = mydata, mapping = aes(x = gdpPercap, y = lifeExp)) + geom_point(aes(color = continent)) +
  geom_smooth(method = "loess") +
  scale_x_log10() +
  labs(x =" Log GDP per Capita", y = "Life Expectancy") +
  ggtitle("Association between GDP Per Capita and Life Expectancy") + theme(plot.title = element_text(lineheight = 0.8, face = "bold", hjust = 0.5))
## `geom_smooth()` using formula 'y ~ x'

Thay đổi theo phong cách màu của tạp chí “The Economist” như sau:

library(ggthemes)
ggplot(data = mydata, mapping = aes(x = gdpPercap, y = lifeExp)) + geom_point(aes(color = continent)) +
  geom_smooth(method = "loess") +
  scale_x_log10() +
  labs(x =" Log GDP per Capita", y = "Life Expectancy") +
  ggtitle("Association between GDP Per Capita and Life Expectancy") + theme(plot.title = element_text(lineheight = 0.8, face = "bold", hjust = 0.5)) + theme_economist()
## `geom_smooth()` using formula 'y ~ x'

Một số biểu đồ phổ biến khác sử dụng ggplot2

Biểu đồ histogram

Đây còn được gọi là biểu đồ phân bố, sử dụng rất hữu ích khi thể hiện sự phân bố của một biến số liên tục nào đó. Trong bộ dữ liệu gapminder, thì biến gdpPercap là một biến số liên tục ngẫu nhiên, chúng ta thử vẽ biểu đồ histogram cho biến số này vào năm 2007. Sử dụng lệnh subset() đã học để bóc tách dữ liệu cho năm 2007

year2007 <- subset(mydata, year == 2007)
head(year2007)
## # A tibble: 6 x 6
##   country     continent  year lifeExp      pop gdpPercap
##   <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
## 1 Afghanistan Asia       2007    43.8 31889923      975.
## 2 Albania     Europe     2007    76.4  3600523     5937.
## 3 Algeria     Africa     2007    72.3 33333216     6223.
## 4 Angola      Africa     2007    42.7 12420476     4797.
## 5 Argentina   Americas   2007    75.3 40301927    12779.
## 6 Australia   Oceania    2007    81.2 20434176    34435.
ggplot(data = year2007, mapping = aes(gdpPercap)) +
  geom_histogram(fill = "lightblue", color = "white") +
  labs(title = "Distribution of GDP per Capita in 2007")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Nếu chúng ta không muốn trục Oy là count mà muốn là xác suất (tần suất xuất hiện)

ggplot(data = year2007, mapping = aes(gdpPercap)) +
  geom_histogram(aes(y = ..density..), fill = "lightblue", color = "white")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Nếu chúng ta quan tâm phân phối theo từng lục địa

ggplot(data = year2007, mapping = aes(gdpPercap, fill = continent)) +
  geom_density(alpha = 0.4)

Biểu đồ thanh Barplot

Biểu đồ này thường được dùng để biểu thị tần số xuất hiện của 1 hay nhiều hơn 1 biến liên tục. Ví dụ: Chúng ta muốn tìm hiểu số quốc gia trong mỗi lục địa là bao nhiêu, sử dụng dữ liệu gapminder cho năm 2007.

dim(year2007)
## [1] 142   6
ggplot(data = year2007, mapping = aes(x = continent, fill = continent)) +
  geom_bar() 

Tuy nhiên phần legend hơi thừa, xóa bớt

dim(year2007)
## [1] 142   6
ggplot(data = year2007, mapping = aes(x = continent, fill = continent)) +
  geom_bar() + theme(legend.position = "none")

Ngoài ra biểu đồ barplot còn thể hiện được sự liên quan giữa hai biến số thông qua kiểu (stacked bar plot), biểu đồ thanh chồng lên nhau. Ví dụ tuổi của các quốc gia có thể phân thành các nhóm sau đây:

  • Nhóm 1: Gồm các quốc gia có tuổi thọ dưới 60
  • Nhóm 2: Gồm các quốc gia có tuổi thọ lớn hơn 60 và nhỏ hơn 80
  • Nhóm 3: Gồm các quốc gia có tuổi thọ trên 80

Sử dụng toán tử điều kiện [] để tạo ra một biến mới tên là level_age có tính thứ bậc

year2007$level_age[year2007$lifeExp < 60.0] <- "< 60 age"
## Warning: Unknown or uninitialised column: `level_age`.
year2007$level_age[60.0 <= year2007$lifeExp & year2007$lifeExp <= 80.0] <- "60-80 age"
year2007$level_age[year2007$lifeExp > 80.0] <- "> 80 age"
ggplot(data = year2007, aes(x = continent, fill = level_age)) +
  geom_bar()

Biểu đồ Barplot cũng có thể miêu tả một biến liên tục như sau. Ví dụ: Chúng ta muốn thể hiện tuổi thọ trung bình của mỗi quốc gia thuộc Châu Á (Asian). Trước tiên cần lọc các quốc gia có lục địa là Asian:

asia <- subset(mydata, year == 2007 & continent == "Asia")
dim(asia)
## [1] 33  6

Như vậy ở Châu Á có 33 quốc gia. Trực quan dữ liệu

ggplot(data = asia, mapping = aes(x = country, y = lifeExp, fill = country)) + geom_bar(stat = "identity", width = 0.9)

Tuy nhiên giao diện rất khó nhìn và bị chồng lên nhau ở trục Ox, chúng ta đảo ngược

ggplot(data = asia, mapping = aes(x = country, y = lifeExp, fill = country)) + geom_bar(stat = "identity", width = 0.9) + coord_flip()

Biểu đồ này rất khó so sánh, chúng ta nên sắp xếp lại theo trật tự

ggplot(data = asia, mapping = aes(x = reorder(country, lifeExp), y = lifeExp, fill = country)) + geom_bar(stat = "identity", width = 0.9) + coord_flip() + theme(legend.position = "none") + labs(x="", y="Life Expectancy") -> graph1

Ngoài ra chúng ta có thể trình bày nhiều biểu đồ trên cùng một hình, sử dụng gói gridExtra, biểu diễn hai đồ thị thanh cho tuổi thọ và thu nhập bình quân đầu người

ggplot(data = asia, mapping = aes(x = reorder(country, gdpPercap), y = gdpPercap, fill = country)) + geom_bar(stat = "identity", width = 0.9) + coord_flip() + theme(legend.position = "none") + labs(x="", y="GDP Per Capita") -> graph2
grid.arrange(graph1, graph2, ncol = 2)

Biểu đồ hộp (Boxplot)

Giới thiệu về biểu đồ hộp

     Biểu đồ hộp trong tiếng Anh là Box Plot hay Box and Whisker plot, là một loại biểu đồ thể hiện các khuôn hình của dữ liệu định tính (quantitative data).

     Biểu đồ hộp do John Tukey sáng tạo ra năm 1977.

     Biểu đồ hộp (Box plot) hay còn gọi là biểu đồ hộp và râu (Box and whisker plot) là biểu đồ diễn tả 5 vị trí phân bố của dữ liệu, đó là: - Giá trị nhỏ nhất (min) - Giá trị tứ phân vị thứ nhất (Q1) - Giá trị trung vị (median) - Giá trị tứ phân vị thứ 3 (Q3) - Giá trị lớn nhất (max)

John Tukey

John Tukey : “Đặt câu hỏi đúng quan trọng hơn ngàn lần tìm câu trả lời đúng cho một câu hỏi sai.”

Đặc trưng của biểu đồ hộp

     Số phân tử hay còn gọi là tứ phân vị (Quartiles): Tứ phân vị là đại lượng mô tả sự phân bố và sự phân tán của tập dữ liệu. Số phân tử có 3 giá trị, đó là số phân tử thứ nhất (Q1), thứ nhì (Q2) và thứ ba (Q3). Ba giá trị này chia một tập hợp dữ liệu (đã sắp xếp dữ liệu theo trật từ bé đến lớn) thành 4 phần có số lượng quan sát đều nhau.

Tứ phân vị được xác định như sau:

  • Sắp xếp các số theo thứ tự tăng dần

  • Cắt dãy số thành 4 phần bằng nhau

  • Tứ phân vị là các giá trị tại vị trí cắt

    Tứ phân vị

Khoảng biến thiên số phân tử (Interquartile Range - IQR) IQR được xác định như sau:

IQR

     Biểu đồ boxplot còn thể hiện 2 đại lượng phổ biến khi nói về độ rộng của một tập dữ liệu:

  • Khoảng dữ liệu (range): Nếu bạn quan tâm đến độ rộng của tất cả dữ liệu thì, đó đơn giản là khoảng cách giữa giá trị lớn nhất và giá trị nhỏ nhất trong tập dữ liệu. Còn nếu bạn muốn loại trừ các giá trị ngoại lai, thì đó là khoảng cách giữa 2 đầu ria mép!
  • Khoảng liên phần tư (IQR): là nửa giữa của tập dữ liệu nằm giữa 2 điểm Q3 và Q1. Trong biểu đồ trên, IQR là khoảng 7 – 3 = 4
     Và cuối cùng, biểu đồ boxplots còn cung cấp thông tin cho chúng ta về hình dạng của tập dữ liệu:

Độ lệch

     Đây là 3 hình dạng chủ yếu về độ lệch. Nếu đường trung vị chia chiếc hộp thành 2 nửa đều nhau, thì tập dữ liệu này đối xứng (symmetric). Nếu nửa phải lớn hơn (nửa trái) thì tập dữ liệu bị lệch phải (right-skewed), và ngược lại, nếu nửa trái lớn hơn thì tập dữ liệu bị lệch trái (left-skewed).

Ví dụ Boxplot và cách đọc

Dưới đây mô tả sử dụng biểu đồ hộp để phân tích, nhận biết vấn đề.

     Ví dụ: Với số liệu thu thập được về tỉ lệ làm lại (Rework Ratio) trong quá trình sản xuất, (có xmin = 0,0; Q1 = 14,9; x = 19,0; x = 15,8; Q3 = 20,6; xmax =23,2) ta có biểu đồ hộp với hình dáng biểu đồ như sau:

Rework Ration

     Trung bình tỉ lệ làm lại là 15,8%, trung vị là 19%. Dữ liệu có xu hướng nghiêng nhiều về phía trên giá trị trung bình:

  • Khoảng số phân tử = Q3 - Q1 = 20,6 - 14,9 = 5,7

  • Khoảng cách giữa giá trị lớn nhất và nhỏ nhất là 23,2 - 0 = 23,2.

     Nhìn chung, tỉ lệ làm lại cao và quá trình có sự dao động lớn, không ổn định, kiểm soát chất lượng kém. Tuy nhiên, biểu đồ hộp giúp nhìn trực quan hơn khi so sánh 3 giai đoạn hoặc khu vực khác nhau như hình dưới đây:

Rework Ration

Nhận xét:

     Với ba lần thu thập dữ liệu về tỉ lệ làm lại vào thời điểm tháng 11/2011, tháng 3/2012 và tháng 6/2012, dữ liệu vào thời điểm tháng 11/2011 cho thấy quá trình kiểm soát lỗi kém vì xu hướng tập trung của dữ liệu (trung vị) ở mức cao, độ dao động lớn.

     Kiểm soát chất lượng vào thời điểm tháng 3/2012 là tốt nhất vì dữ liệu về tỉ lệ làm lại tập trung ở mức thấp, dao động ở phạm vi hẹp.

Áp dụng vào dữ liệu

Giả sử chúng ta muốn tóm tắt thu nhập bình quân năm 2007 của 142 quốc gia bằng biểu đồ hộp

ggplot(data = year2007, aes(x = continent, y = gdpPercap, fill = continent)) + geom_boxplot(alpha = 0.6)

ggplot(data = year2007, aes(x = continent, y = gdpPercap, fill = continent)) + geom_boxplot(alpha = 0.6) + geom_jitter(alpha = 0.3)