博客 / 詳情

返回

R語言之 ggplot 2 和其他圖形

文章和代碼已經歸檔至【Github倉庫:https://github.com/timerring/dive-into-AI 】或者公眾號【AIShareLab】回覆 R語言 也可獲取。

1. 初識 ggplot2 包

ggplot2 包提供了一套基於圖層語法的繪圖系統,它彌補了 R 基礎繪圖系統裏的函數缺乏一致性的缺點,將 R 的繪圖功能提升到了一個全新的境界。ggplot2 中各種數據可視化的基本原則完全一致,它將數學空間映射到圖形元素空間。想象有一張空白的畫布,在畫布上我們需要定義可視化的數據(data),以及數據變量到圖形屬性的映射(mapping)。

下面使用數據集 mtcars 作圖。

該數據集摘自 1974 年的美國《汽車趨勢》雜誌,包含 32 輛汽車的燃油消耗、設計和性能等方面的 11 個指標:mpg(耗油量)、cyl(氣缸數)、disp(排量)、hp(總功率)、drat(後軸比)、wt(車重)、qsec(四分之一英里用時)、vs(發動機類型)、am(傳動方式)、gear(前進擋個數)和 carb(化油器個數)。我們首先來探索車重和耗油量的關係,將變量 wt 映射到 x 軸,變量 mpg 映射到 y 軸。

library(ggplot2)
p <- ggplot(data = mtcars, mapping = aes(x = wt, y = mpg)) 

在上面的命令裏,aes 代表美學(aesthetics)元素,我們把需要映射的變量都放在這個函數中。直接運行 p 得到的只是一個空白的畫布,還需要定義用什麼樣的圖形來表示數據。 以 geom 開頭的一系列函數用於指定圖形元素,包括點、線、面、多邊形等。下面使用點(point)這種幾何對象來展示數據,結果如下圖所示。

p + geom_point()

除了座標軸,還可以把變量映射到顏色(color)、大小(size)、形狀(shape)等屬性。

例如,為了展示不同傳動方式下車重和耗油量的關係,我們可以將變量 am 映射為顏色(下圖左)或形狀(下圖右)。變量 am 在原數據集裏是一個數值型變量(取值為 0 和 1),實質上它應該是一個分類變量,因此我們先把它轉換為一個二水平的因子。

library(gridExtra)
mtcars$am <- factor(mtcars$am)
p1 <- ggplot(data = mtcars, aes(x = wt, y = mpg, color = am)) + geom_point()
p2 <- ggplot(data = mtcars, aes(x = wt, y = mpg, shape = am)) + geom_point()
grid.arrange(p1, p2, nrow=1)

上面的圖形都是原始數據的展示,有時候我們需要對原始數據進行某種歸納後作圖。例如,用上圖中的散點擬合曲線。

ggplot(data = mtcars, aes(x = wt, y = mpg, color = am)) + geom_smooth()

函數 geom_smooth( )裏的參數 method 默認值為“loess”,即 LOESS 局部加權迴歸

如果想換一種擬合曲線的方法,可以改變參數 method 的值。例如,用直線迴歸

ggplot(data = mtcars, aes(x = wt, y = mpg, color = am)) + 
        geom_smooth(method = "lm")

上面兩幅圖中都有兩條擬合線,那是因為我們將變量 am 映射成了顏色屬性。如果只想顯示一條平滑線,就需要在 geom_point( )函數中單獨設置顏色的映射,結果如下圖所示。

ggplot(data = mtcars, aes(x = wt, y = mpg)) + 
        geom_point(aes(color = am)) +
        geom_smooth() 

現在我們已經有了“圖層”的概念了。一個圖層就像是一張玻璃紙,包含各種圖形元素,我們可以分別建立多個圖層,然後把它們疊放在一起組成最終的顯示效果。

函數 aes( ) 就像是 ggplot2 的大腦,負責美學設計,而眾多的以 geom 開頭的函數就像是 ggplot2 的雙手,負責將這些美學設計呈現出來。ggplot2 包中有超過 30 個以 geom 開頭的函數,讀者可通過該包的幫助文檔查看這些函數。映射只負責將變量關聯到某個圖形屬性,並不負責具體的數值。例如,在上圖中,我們將變量 am 映射到顏色,但具體使用哪種顏色是 ggplot2 自動選擇的。如果想自己設定顏色,就需要使用標度(scale)函數了。

標度函數是圖形細節的調節函數,好比電視機的遙控器,可以調節電視機的音量、畫面、色彩等屬性。ggplot2 中有種類繁多的以 scale 開頭的標度函數,可用於控制圖形的顏色、點的大小和形狀等。例如,我們可以用下面的標度函數手動設置需要的顏色,結果如下圖所示。

ggplot(data = mtcars, aes(x = wt, y = mpg)) + 
        geom_point(aes(color = am)) +
        scale_color_manual(values = c("blue", "red")) +
        geom_smooth() 

ggplot2 包還能實現 lattice 包中的分組繪圖功能,即分面(facet)。分面是將整個數據按照某一個或幾個分類變量分成多個子集,然後用這些子集分別作圖。例如,要將上圖按照變量 am 的兩個水平分別展示,可以使用下面的命令。繪圖結果如下圖所示。

ggplot(data = mtcars, aes(x = wt, y = mpg)) + 
        geom_point() +
        stat_smooth() +
        facet_grid(~ am)

ggplot2 包中的主題(theme)函數用於定義繪圖的風格,例如畫布的背景。下圖是一個黑白主題畫布背景示例:

ggplot(data = mtcars, aes(x = wt, y = mpg)) + 
        geom_point(aes(color = am)) +
        stat_smooth() +
        theme_bw()

除了 ggplot2 包自帶的主題,還有一些擴展包提供了多種主題風格,例如 ggthemes 包、artyfarty 包等。使用這些包之前需要先安裝,感興趣的讀者可自行探索。
以上介紹了 ggplot2 包中的映射(mapping)、圖形元素(geom)、標度(scale)、分面(facet)和主題(theme)等概念,並展示了它們的基本用法。接下來我們將探索用 ggplot2 包繪製常用統計圖形的方法。

2.分佈的特徵

在探索數據的過程中,最基本的手段就是觀察單個變量的取值情況。對於連續型變量,可以繪製直方圖或密度曲線圖。

下面用之前提及的 MASS 包裏的數據集anorexia 作圖。先加載數據並建立新變量 wt.change(體重改變量,單位:lb)。

data(anorexia, package = "MASS")
anorexia$wt.change <- anorexia$Postwt - anorexia$Prewt

接下來,用 ggplot2 包繪製變量 wt.change 的直方圖,代碼如下:

library(ggplot2)
p1 <- ggplot(anorexia, aes(x = wt.change)) +
        geom_histogram(binwidth = 2, fill = "skyblue", color = "black") +
        labs(x = "Weight change (lbs)") +
        theme_bw()
p1

其中,參數 binwidth 用於設置組距,默認值為全距除以 30,在作圖時可以嘗試設置不同參數值以得到比較滿意的結果。參數 fill 用於設置填充色。參數 color 用於設置矩形邊框的顏色。我們還可以將直方圖和密度曲線同時展示,如下圖所示。

p2 <- ggplot(anorexia, aes(x = wt.change, y = ..density..)) +
        geom_histogram(binwidth = 2, fill = "skyblue", color = "black") +
        stat_density(geom = "line",linetype = "dashed", size = 1) +
        labs(x = "Weight change (lbs)") +
        theme_bw()
p2

其中,“y = ..density..”用於設定 y 軸為頻率(密度),stat_density( )是一種用於計算密度估計曲線的統計變換。

密度曲線還能用於對不同數據的分佈進行比較。例如,要比較不同治療方式下體重改變量的分佈,輸入下面的代碼:

p3 <- ggplot(anorexia, aes(x = wt.change, color = Treat, linetype = Treat)) +
        stat_density(geom = "line", size = 1) +
        labs(x = "Weight change (lbs)") +
        theme_bw()
p3

上面的命令先將變量 Treat 映射為顏色和線型,再畫出 3 種治療方式下的體重改變量 wt.change 的密度曲線,如上圖所示。

除了直方圖和密度曲線圖,箱線圖也經常用於展示數值型變量的分佈,尤其多用於各組之間分佈的比較。例如:

p4 <- ggplot(anorexia, aes(x= Treat, y = wt.change)) +
        geom_boxplot() +
        theme_bw()
p4

從上圖可以看出,FT 組的體重改變量要高於其他兩組,但是差異的顯著性需要經過統計學檢驗才能得出結論。

ggpubr 包提供了在平行箱線圖上添加組間比較的統計學差異的功能。該包是一個 ggplot2 的衍生包,可以生成用於論文發表的統計圖形,值得醫學研究工作者探索。下面在上圖的基礎上添加組間均值比較的統計學差異。

library(ggpubr)
my_comparisons <- list(c("CBT", "Cont"), c("CBT", "FT"), c("Cont", "FT"))
p5 <- ggplot(anorexia, aes(x= Treat, y = wt.change)) +
        geom_boxplot() +
        stat_compare_means(comparisons = my_comparisons,
                           method = "t.test",
                           color = "blue") +
        theme_bw()
p5

上圖中的 p 值是用 t 檢驗進行組間兩兩比較得到的。另外,我們還可以用 ggplot2 繪製與上圖相似的小提琴圖,結果如下圖所示。

p6 <- ggplot(anorexia, aes(x= Treat, y = wt.change)) +
        geom_violin() +
        geom_point(position = position_jitter(0.1), alpha = 0.5) +
        theme_bw()
p6

3.比例的構成

許多數據會涉及比例的問題,提取比例信息能使我們瞭解各個組成部分對於整體的重要性。比例的構成常用條形圖展示,例如:

library(vcd)
data(Arthritis)
ggplot(Arthritis, aes(x = Treatment, fill = Improved)) +
        geom_bar(color = "black") +
        scale_fill_brewer() +
        theme_bw()

上圖被稱為疊加條形圖,是為了在一幅圖中同時展現多個變量,圖中的縱座標是計數的絕對大小。但有時候我們更希望觀察相對比例,這可以通過將參數 position 設為“fill”來實現,結果如下圖所示。

ggplot(Arthritis, aes(x = Treatment, fill = Improved)) +
        geom_bar(color = "black", position = "fill") +
        scale_fill_brewer() +
        theme_bw()

我們還可以把參數 position 設為“dodge”來將條形圖並排放置,如下圖所示。

ggplot(Arthritis, aes(x = Treatment, fill = Improved)) +
        geom_bar(color = "black", position = "dodge") +
        scale_fill_brewer() +
        theme_bw()

4.用函數 ggsave( )保存圖形

函數 ggsave( )專門用於保存 ggplot2 包繪製的圖形,該函數可以導出多種不同格式的圖片。例如:

p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
ggsave("myplot.png", p)
ggsave("myplot.pdf", p)

上面的命令先創建了一幅散點圖並把結果保存為 p,然後用函數 ggsave( )分別把這幅圖形保存為 png 和 pdf 格式的文件。打開當前工作目錄就可以看到這兩個文件。

如果要把圖片用於出版物中,我們可以對圖片的尺寸和分辨率等進行設置。例如,把上面的圖形對象 p 保存為 tiff 格式,並設置圖片的長和寬分別為 12cm 和 15cm,分辨率為 500 dpi,代碼如下:

ggsave("myplot.tiff", width = 15, height = 12, units = "cm", dpi = 500)

2. 其他圖形

2.1 金字塔圖

金字塔圖是一種背靠背式的條形圖,常用於展示研究人羣的人口結構,所以也稱為人口金字塔圖。DescTools 包裏的 PlotPyramid( ) 函數,以及 epiDisplay 包裏的 pyramid( )函數都可以用來繪製金字塔圖。下面以 epiDisplay 包裏的數據集 Oswego 為例繪製金字塔圖,這裏需要用到數據集裏的兩個變量 age 和 sex。

options(warn = -1)
library(epiDisplay)
data(Oswego)
pyramid(Oswego$age, Oswego$sex, col.gender = c(2, 4), bar.label = TRUE)

上圖展示的是不同性別下各個年齡組的頻數分佈。函數 pyramid( )裏有很多參數可以用於控制圖形的細節展示,讀者請查看該函數的幫助文檔並嘗試改變不同的參數設置以得到滿意的輸出效果。

2.2 橫向堆棧條形圖

在做流行病學調查時,經常需要在問卷上設置很多選擇題。對於一組問題,可以使用 sjPlot 包裏的函數 plot_stackfrq( ) 對不同選項的比例進行可視化。下面以該包裏的數據集 efc 為例作圖,這裏需要用到其中的 9 個變量,它們分別對應問卷裏的 9 個選擇題。運行下面代碼前請先安裝 sjPlot 包。

library(sjPlot)
data(efc)
names(efc)

head(efc)

qdata <- dplyr::select(efc, c82cop1:c90cop9)
plot_stackfrq(qdata)

繪圖結果如上圖所示,我們可以從圖中獲取每個問題的表述、回答的人數、不同選項的選擇的百分比等信息。

sjPlot 包裏彙集了很多用於可視化流行病學和社會科學領域的數據的函數。使用這些函數能夠輕鬆地繪製出既美觀又實用的統計圖形,值得讀者進一步探索。

3.3 熱圖

熱圖(heatmap)是將一個矩陣中的元素數值用不同顏色表達,並對矩陣的行或列進行層次聚類的一種顏色圖。通過熱圖,我們不僅可以直接觀察矩陣中的數值分佈狀況,還可以知道聚類的結果。關於聚類分析的進一步介紹參見第 10 章。熱圖經常運用在生物信息學數據分析中。以 RNA-seq 為例,熱圖可以直觀地呈現多樣本或多個基因的全局表達量的變化,還可以呈現多樣本或多個基因表達量的聚類關係。

stats 包裏的函數 heatmap( )可用於製作熱圖。下面以數據集 mtcars 為例介紹該函數的用法。由於該數據集裏變量的測量尺度有較大差異,我們首先需要用函數 scale( )把變量標準化。標準化後的變量組成的矩陣可以作為函數 heatmap( )的輸入,繪圖結果如下圖所示。

data(mtcars)
dat <- scale(mtcars)
class(dat)
heatmap(dat)

3.4 三維散點圖

前面提到的圖形都是二維的,如果想對 3 個數值型變量的關係進行可視化,可以使用 scatterplot3d 包的 scatterplot3d( )函數,使用前請先安裝該包。

函數 scatterplot3d( ) 提供的參數選項包括設置圖形符號、突出顯示、角度、顏色、線條、座標軸和網格線等。下面以 datasets 包裏的數據集 trees 為例説明此函數的用法。該數據集包含 3 個數值型變量 Girth、Height 和Volume。我們分別以這 3 個變量為座標軸繪製三維散點圖,結果如下圖所示。

library(scatterplot3d)
data(trees)
scatterplot3d(trees, type = "h", highlight.3d = TRUE, angle = 55, pch = 16)

上面函數 scatterplot3d( )中的參數 type 用於設置繪圖的類型,默認為“p”(點),這裏設為“h”,顯示垂線段。參數 angle 用於設置 x 軸和 y 軸的角度。需要注意的是,用靜態的三維散點圖描述 3 個變量之間的關係時,可能會受到觀察角度的影響。

3.5 小結

其他一些專門的圖形,例如散點圖矩陣、相關圖、正態 QQ 圖、生存曲線、聚類圖、碎石圖、ROC 曲線和 Meta 分析森林圖等,將會在後續章節中結合統計分析方法陸續介紹。在 R 的應用中,可視化是一個非常活躍的領域,新的包層出不窮。網站 The R Graph Gallery 收集了各種新穎的圖形以及相應的示例代碼,值得對可視化感興趣的讀者關注。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.