最近把之前的《R數據科學》的筆記整理一下,大概每篇文章整理2-3章,這本書有中英文兩版,不知道為什么中文版比英文版少了一章,而且一些關鍵內容也有所刪減,所以大家學習這本書的時候以英文版為準。
電子書下載地址:《R4ds》
源代碼地址:https://github.com/hadley/r4ds
作者簡介:
哈德利?威克姆(Hadley Wickham)
RStudio首席科學家,統計學家,斯坦福大學、奧克蘭大學、萊斯大學兼職統計學教授。已被下載數百萬次的ggplot2等多款知名R包的開發者,一直致力于讓普羅大眾更容易上手數據分析,被R社區譽為“改變了R的人”。另著有《R包開發》等書。
加勒特?格羅勒芒德(Garrett Grolemund)
RStudio數據科學家,知名R培訓師,曾受邀在Google、eBay等諸多公司講授R語言和數據科學,在DataCamp開授的R相關課程備受R開發者喜愛。另著有《R語言入門與實踐》。
第一章:使用ggplot2進行數據可視化
1.1 簡介
準備工作
本章重點討論tidyverse 的一個核心R 包——ggplot2。為了訪問本章用到的數據集、幫助頁面和函數,需要先運行以下代碼來加載tidyverse
install.packages("tidyverse")
library(tidyverse)
1.2 第一步
我們使用第一張圖來回答問題:大引擎汽車比小引擎汽車更耗油嗎?你可能已經有了答案,但應該努力讓答案更精確一些。引擎大小與燃油效率之間是什么關系?是正相關,還是負相關?是線性關系,還是非線性關系?
1.2.1 mpg數據框
你可以使用ggplot2 包中的mpg 數據框(即ggplot2::mpg)來檢驗自己的答案。數據框是變量(列)和觀測(行)的矩形集合。mpg 包含了由美國環境保護協會收集的38 種車型的觀測數據。
> mpg
# A tibble: 234 x 11
manufacturer model displ year cyl trans drv cty hwy fl
<chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr>
1 audi a4 1.8 1999 4 auto~ f 18 29 p
2 audi a4 1.8 1999 4 manu~ f 21 29 p
3 audi a4 2 2008 4 manu~ f 20 31 p
4 audi a4 2 2008 4 auto~ f 21 30 p
5 audi a4 2.8 1999 6 auto~ f 16 26 p
6 audi a4 2.8 1999 6 manu~ f 18 26 p
7 audi a4 3.1 2008 6 auto~ f 18 27 p
8 audi a4 q~ 1.8 1999 4 manu~ 4 18 26 p
9 audi a4 q~ 1.8 1999 4 auto~ 4 16 25 p
10 audi a4 q~ 2 2008 4 manu~ 4 20 28 p
# ... with 224 more rows, and 1 more variable: class <chr>
mpg 中包括如下變量。
? displ:引擎大小,單位為升。
? hwy:汽車在高速公路上行駛時的燃油效率,單位為英里/ 加侖(mpg)。與燃油效率高的汽車相比,燃油效率低的汽車在行駛相同距離時要消耗更多燃油。要想了解更多關于mpg 的信息,可以使用?mpg 命令打開其幫助頁面。
1.2.2 創建ggplot圖形
為了繪制mpg 的圖形,運行以下代碼將displ 放在x 軸,hwy 放在y 軸:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy))
上圖顯示出引擎大小(displ)和燃油效率(hwy)之間是負相關關系。換句話說,大引擎汽車更耗油。
在ggplot2 中,你可以使用ggplot() 函數開始繪圖。ggplot() 創建了一個坐標系,你可以在它上面添加圖層。ggplot() 的第一個參數是要在圖中使用的數據集。ggplot(data = mpg)會創建一張空白圖,因為這張圖沒什么意思,所以就不在這里展示了。
函數geom_point() 向圖中添加一個點層,這樣就可以創建一張散點圖。ggplot2 中包含了多種幾何對象函數,每種函數都可以向圖中添加不同類型的圖層。
ggplot2 中的每個幾何對象函數都有一個mapping 參數。這個參數定義了如何將數據集中的變量映射為圖形屬性。mapping 參數總是與aes() 函數成對出現,aes() 函數的x 參數和y參數分別指定了映射到x 軸的變量與映射到y 軸的變量。ggplot2 在data 參數中尋找映射變量,本例中就是mpg。
1.2.3 繪圖模板
將上面的代碼轉換為一個可重用的ggplot2 繪圖模板。要想生成一張圖,將以下代碼中的尖括號部分替換為數據集、幾何對象函數或映射集合即可:
ggplot(data = <DATA>) +
<GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))
1.2.4 練習
(1) 運行ggplot(data = mpg),你會看到什么?
一片空白
(2) 數據集mpg 中有多少行?多少列?
234行11列
(3) 變量drv 的意義是什么?使用?mpg 命令閱讀幫助文件以找出答案。
傳動系的類型,其中f =前輪驅動,r =后輪驅動,4 = 4wd
(4) 使用hwy 和cyl 繪制一張散點圖。
ggplot(data = mpg) +
geom_point(mapping = aes(x = cyl, y = hwy))
上圖顯示出引擎大小(displ)和燃油效率(hwy)之間是負相關關系。換句話說,大引擎汽車更耗油。
在ggplot2 中,你可以使用ggplot() 函數開始繪圖。ggplot() 創建了一個坐標系,你可以在它上面添加圖層。ggplot() 的第一個參數是要在圖中使用的數據集。ggplot(data = mpg)會創建一張空白圖,因為這張圖沒什么意思,所以就不在這里展示了。
函數geom_point() 向圖中添加一個點層,這樣就可以創建一張散點圖。ggplot2 中包含了多種幾何對象函數,每種函數都可以向圖中添加不同類型的圖層。
ggplot2 中的每個幾何對象函數都有一個mapping 參數。這個參數定義了如何將數據集中的變量映射為圖形屬性。mapping 參數總是與aes() 函數成對出現,aes() 函數的x 參數和y參數分別指定了映射到x 軸的變量與映射到y 軸的變量。ggplot2 在data 參數中尋找映射變量,本例中就是mpg。
1.2.3 繪圖模板
將上面的代碼轉換為一個可重用的ggplot2 繪圖模板。要想生成一張圖,將以下代碼中的尖括號部分替換為數據集、幾何對象函數或映射集合即可:
ggplot(data = <DATA>) +
<GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))
1.2.4 練習
(1) 運行ggplot(data = mpg),你會看到什么?
一片空白
(2) 數據集mpg 中有多少行?多少列?
234行11列
(3) 變量drv 的意義是什么?使用?mpg 命令閱讀幫助文件以找出答案。
傳動系的類型,其中f =前輪驅動,r =后輪驅動,4 = 4wd
(4) 使用hwy 和cyl 繪制一張散點圖。
ggplot(data = mpg) +
geom_point(mapping = aes(x = cyl, y = hwy))
(5) 如果使用class 和drv 繪制散點圖,會發生什么情況?為什么這張圖沒什么用處?
ggplot(data = mpg) +
geom_point(mapping = aes(x = class, y =drv))
(5) 如果使用class 和drv 繪制散點圖,會發生什么情況?為什么這張圖沒什么用處?
ggplot(data = mpg) +
geom_point(mapping = aes(x = class, y =drv))
車的類型與驅動類型之間沒有對應關系,或者說兩者無法發生關系。
1.3 圖形屬性映射
The greatest value of a picture is when it forces us to notice what we never expected to see. —John Tukey
下圖中有一組點(顯示為紅色)似乎位于線性趨勢之外。這些汽車比預期具有更高的里程數。
假設這些汽車是混合動力車。檢驗這種假設的一個方法是查看每輛汽車的class值。mpg 數據集中的class 變量對汽車進行了分類,比如小型、中型和SUV。如果那些離群點是混合動力車,那么它們應該分類為小型車,也可能是微型車(注意,這份數據是在混合動力車和SUV 流行前收集的)。
可以向二維散點圖中添加第三個變量,比如class,方式是將它映射為圖形屬性。圖形屬性是圖中對象的可視化屬性,其中包括數據點的大小、形狀和顏色。通過改變圖形屬性的值,可以用不同的方式來顯示數據點(如下圖所示)。因為已經使用“value”這個詞來表示數據的值,所以下面使用“level”(水平)這個詞來表示圖形屬性的值。我們來改變一個點的大小、形狀和顏色來反映不同屬性。
通過將圖中的圖形屬性映射為數據集中的變量,可以傳達出數據的相關信息。例如,可以將點的顏色映射為變量class,從而揭示每輛汽車的類型:
要想將圖形屬性映射為變量,需要在函數aes() 中將圖形屬性名稱和變量名稱關聯起來。ggplot2 會自動為每個變量值分配唯一的圖形屬性水平(本例中是唯一的顏色),這個過程稱為標度變換。ggplot2 還會添加一個圖例,以表示圖形屬性水平和變量值之間的對應關系。
也可以用同樣的方式將其映射為點的大小。在下面的示例中,每個點的實際大小表示其所屬的類別。這里我們收到一條警告信息,因為將無序變量(class)映射為有序圖形屬性(size)可不是好主意。
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, size = class))
Warning message:
Using size for a discrete variable is not advised.
或者我們也可以將class 映射為控制數據點透明度的alpha 圖形屬性,還可以將其映射為點的形狀。
# 上圖
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, alpha = class))
# 下圖
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, shape = class))
SUV 怎么了? ggplot2 只能同時使用6 種形狀。默認情況下,當使用這種圖形屬性時,多出的變量值將不會出現在圖中。
一旦映射了圖形屬性,ggplot2 會處理好其余的事情。它會為圖形屬性選擇一個合適的標度,并創建圖例來表示圖形屬性水平和變量值之間的映射關系。ggplot2 不會為x 和y 這兩個圖形屬性創建圖例,而會創建帶有刻度標記和標簽的坐標軸。坐標軸就相當于圖例,可以體現出位置和變量值之間的映射關系。
還可以手動為幾何對象設置圖形屬性。例如,我們可以讓圖中的所有點都為藍色:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy), color = "blue")
此時顏色不會傳達關于變量的信息,只是改變圖的外觀。要想手動設置圖形屬性,需要按名稱進行設置,將其作為幾何對象函數的一個參數。這也就是說,需要在函數aes() 的外部進行設置。此外,還需要為這個圖形屬性選擇一個有意義的值。
? 顏色名稱是一個字符串。
? 點的大小用毫米表示。
? 點的形狀是一個數值,如圖1-1 所示。有些形狀相同,比如0、15 和22 都是正方形。
形狀之間的區別在于color 和fill 這兩個圖形屬性。空心形狀(0~14)的邊界顏色由color 決定;實心形狀(15~20)的填充顏色由color 決定;填充形狀(21~24)的邊界顏色由color 決定,填充顏色由fill 決定。
練習
(1) 以下這段代碼有什么錯誤?為什么點不是藍色的?
ggplot(data = mpg) +
geom_point(
mapping = aes(x = displ, y = hwy, color = "blue"))
color在mapping的括號里面,成為了圖形屬性映射
(2) mpg 中的哪些變量是分類變量?哪些變量是連續變量?(提示:輸入?mpg 來閱讀這個數據集的文檔。)當調用mpg 時,如何才能看到這些信息?
在每一列的下方有<chr>和<int>兩個屬性,其中<chr>是分類變量,<int>是連續變量
(3) 將一個連續變量映射為color、size 和shape。對分類變量和連續變量來說,這些圖形屬性的表現有什么不同?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = hwy))
顏色是一個漸變色,大小也是漸變,形狀會報錯
(4) 如果將同一個變量映射為多個圖形屬性,會發生什么情況?
兩種屬性會結合,例如顏色和大小
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, size = class, color=class))
(5) stroke 這個圖形屬性的作用是什么?它適用于哪些形狀?(提示:使用?geom_point 命令。)
改變形狀的邊框的大小
(6) 如果將圖形屬性映射為非變量名對象,比如aes(color = displ < 5),會發生什么情況?
Error: geom_point requires the following missing aesthetics: x and y
1.4 常見問題
當開始運行R 代碼時,你很可能會遇到問題。不用擔心,每個人都會遇到問題。首先,將你需要運行的代碼與書中的代碼進行仔細對比。R 極其挑剔,即使一個字母放錯了位置,也可能會造成問題。確保每個( 都有一個) 與之匹配,并且每個" 后面都跟著另一個"。有時運行了代碼卻什么也沒有發生。檢查一下控制臺左側:如果有一個+ 號,那么說明R 認為你沒有輸入完整的表達式,正在等待你完成輸入。這種情況下,按Esc 鍵中止當前執行的命令就可以重新開始。
創建ggplot2 圖形時的一個常見問題是將+ 號放錯了位置:+ 必須放在一行代碼的末尾,而不是開頭。
1.5 分面
添加額外變量的一種方法是使用圖形屬性。另一種方法是將圖分割成多個分面,即可以顯示數據子集的子圖。這種方法特別適合添加分類變量。
要想通過單個變量對圖進行分面,可以使用函數facet_wrap()。其第一個參數是一個公式,創建公式的方式是在~ 符號后面加一個變量名(這里所說的“公式”是R 中的一種數據結構,不是數學意義上的公式)。傳遞給facet_wrap() 的變量應該是離散型的。
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy),stroke=1.5) +
facet_wrap(~ class, nrow = 2)
要想通過兩個變量對圖進行分面,需要在繪圖命令中加入函數facet_grid()。這個函數的第一個參數也是一個公式,但該公式包含由~ 隔開的兩個變量名。
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(drv ~ cyl)
如果不想在行或列的維度進行分面,你可以使用. 來代替變量名,例如+ facet_grid(. ~cyl)。
練習
(1) 如果使用連續變量進行分面,會發生什么情況?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(~ cty)
(2) 在使用facet_grid(drv ~ cyl) 生成的圖中,空白單元的意義是什么?它們和以下代碼生成的圖有什么關系?
雖然空白單元沒有數據,但也代表了一種組合
ggplot(data = mpg) +
geom_point(mapping = aes(x = drv, y = cyl))
這張圖生成的是沒有意義的圖,每個點代表每種組合,facet_grid(drv ~ cyl) 生成的圖則將每個組合中displ和 hwy之間的關系表現了出來。
(3) 以下代碼會繪制出什么圖? . 的作用是什么?
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(drv ~ .)
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_grid(. ~ cyl)
.的作用決定了分布方向,如果前面出現、縱向分布,反之為橫向分布
(4) 查看本節的第一個分面圖:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_wrap(~ class, nrow = 2)
與使用圖形屬性相比,使用分面的優勢和劣勢分別是什么?如果有一個更大的數據集,
你將如何權衡這兩種方法的優劣?
使用分面能更好的體現出每個類別displ與hwy的關系,但是沒辦法比較不同類別之間的區別
使用屬性能更好的體現整體的關系,但是個體差異不明顯
1.6 幾何對象
兩張圖有同樣的x 變量和y 變量,而且描述的是同樣的數據。但這兩張圖并不一樣,它們各自使用不同的可視化對象來表示數據。在ggplot2 語法中,我們稱它們使用了不同的幾何對象。
幾何對象是圖中用來表示數據的幾何圖形對象。我們經常根據圖中使用的幾何對象類型來描述相應的圖。例如,條形圖使用了條形幾何對象,折線圖使用了直線幾何對象,箱線圖使用了矩形和直線幾何對象。散點圖打破了這種趨勢,它們使用點幾何對象。如上面的兩幅圖所示,我們可以使用不同的幾何對象來表示同樣的數據。左側的圖使用了點幾何對象,右側的圖使用了平滑曲線幾何對象,以一條平滑曲線來擬合數據。要想改變圖中的幾何對象,需要修改添加在ggplot() 函數中的幾何對象函數。舉例來說,要想繪制出上圖,你可以使用以下代碼:
# 左圖
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy))
# 右圖
ggplot(data = mpg) +
geom_smooth(mapping = aes(x = displ, y = hwy))
ggplot2 中的每個幾何對象函數都有一個mapping 參數。但是,不是每種圖形屬性都適合每種幾何對象。你可以設置點的形狀,但不能設置線的“形狀”,而可以設置線的線型。geom_smooth() 函數可以按照不同的線型繪制出不同的曲線,每條曲線對應映射到線型的變量的一個唯一值:
ggplot(data = mpg) +
geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv))
根據表示汽車驅動系統的drv 變量的值,這里的geom_smooth() 函數分別用3 條曲線來表示汽車。一條線表示drv 值為4 的所有汽車,一條線表示drv 值為f 的所有汽車,另一條線表示drv 值為r 的所有汽車。其中4 表示四輪驅動,f 表示前輪驅動,r 表示后輪驅動。如果你覺得這有些難以理解,我們可以將這些曲線覆蓋在原始數據上,并按照drv 值對所有的點和線進行著色,這樣你就能看得更清楚一些了。
要想在同一張圖中顯示多個幾何對象,可以向ggplot() 函數中添加多個幾何對象函數:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
geom_smooth(mapping = aes(x = displ, y = hwy))
但是,這樣代碼就產生了一些重復。假如你想將y 軸上的變量從hwy 改成cty,那么就要在兩個地方修改這個變量,但你或許會漏掉一處。避免這種重復的方法是將一組映射傳遞給ggplot() 函數。ggplot2 會將這些映射作為全局映射應用到圖中的每個幾何對象中。
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_point() +
geom_smooth()
如果將映射放在幾何對象函數中,那么ggplot2 會將其看作這個圖層的局部映射,它將使用這些映射擴展或覆蓋全局映射,但僅對該圖層有效。這樣一來,我們就可以在不同的圖層中顯示不同的圖形屬性:
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_point(mapping = aes(color = class)) +
geom_smooth()
同理,你也可以為不同的圖層指定不同的數據。下圖中的平滑曲線表示的只是mpg 數據集的一個子集,即微型車。geom_smooth() 函數中的局部數據參數覆蓋了ggplot() 函數中的全局數據參數,當然僅對這個圖層有效:
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_point(mapping = aes(color = class)) +
geom_smooth(
data = filter(mpg, class == "subcompact"),
se = FALSE
)
練習
(1) 在繪制折線圖、箱線圖、直方圖和分區圖時,應該分別使用哪種幾何對象?
折線圖使用了直線幾何對象,箱線圖使用了矩形和直線幾何圖像、直方圖使用了使用了矩形幾何對象
(2) 在腦海中運行以下代碼,并預測會有何種輸出。接著在R 中運行代碼,并檢查你的預測是否正確。
ggplot(
data = mpg,
mapping = aes(x = displ, y = hwy, color = drv)
) +
geom_point() +
geom_smooth(se = FALSE)
(3) show.legend = FALSE 的作用是什么?刪除它會發生什么情況?你覺得我為什么要在本章前面的示例中使用這句代碼?
sohw.legend=FLASE去掉圖例
(4) geom_smooth() 函數中的se 參數的作用是什么?
se如果設定為TRUE,則會為曲線設定置信區間,FLASE則沒有置信區間
(6) 自己編寫R 代碼來生成以下各圖。
#######1
ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) +
geom_point() +
geom_smooth(se=FALSE)
#######2
ggplot() +
geom_point(
data = mpg,
mapping = aes(x = displ, y = hwy)
) +
geom_smooth(
data = mpg,
mapping = aes(x = displ, y = hwy,group=drv),se=FALSE)
#######3
ggplot(data = mpg, mapping = aes(x = displ, y = hwy,color=drv)) +
geom_point() +
geom_smooth(se = FALSE)
#######4
ggplot() +
geom_point(
data = mpg,
mapping = aes(x = displ, y = hwy,color=drv)
) +
geom_smooth(
data = mpg,
mapping = aes(x = displ, y = hwy),se=FALSE)
######5
ggplot() +
geom_point(
data = mpg,
mapping = aes(x = displ, y = hwy,color=drv)
) +
geom_smooth(
data = mpg,
mapping = aes(x = displ, y = hwy,linetype=drv),se=FALSE)
######6
ggplot() +
geom_point(
data = mpg,
mapping = aes(x = displ, y = hwy,color=drv))
1.7 統計變換
接下來我們看一下條形圖。條形圖雖然簡單,但很有意思,因為它可以揭示出圖形中的一些微妙信息。我們看一下用geom_bar() 函數就可以繪制的基本條形圖。下面的條形圖顯示了diamonds 數據集中按照cut 變量分組的各種鉆石的總數量。diamonds 數據集是ggplot2的內置數據集,包含大約54 000 顆鉆石的信息,每顆鉆石具有price、carat、color、clarity 和cut 變量。條形圖顯示,高質量切割鉆石的數量要比低質量切割鉆石的數量多:
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut))
條形圖x 軸顯示的是cut,這是diamonds 數據集中的一個變量。y 軸顯示的是count,但count 不是diamonds 中的變量!那么count 來自哪里呢?很多圖形繪制的是數據集的原始數據,比如散點圖。另外一些圖形則可以繪制那些計算出的新數據,比如條形圖。
? 條形圖、直方圖和頻率多邊形圖可以對數據進行分箱,然后繪制出分箱數量和落在每個分箱的數據點的數量。
? 平滑曲線會為數據擬合一個模型,然后繪制出模型預測值。
? 箱線圖可以計算出數據分布的多種摘要統計量,并顯示一個特殊形式的箱體。
繪圖時用來計算新數據的算法稱為stat(statistical transformation,統計變換)。下圖描述了geom_bar() 函數的統計變換過程。
通常來說,幾何對象函數和統計變換函數可以互換使用。例如,你可以使用stat_count()替換geom_bar() 來重新生成前面那張圖:
ggplot(data = diamonds) +
stat_count(mapping = aes(x = cut))
你可能想要覆蓋從統計變換生成的變量到圖形屬性的默認映射。例如,你或許想顯示一張表示比例(而不是計數)的條形圖:
ggplot(data = diamonds) +
geom_bar(
mapping = aes(x = cut, y = ..prop.., group = 1)
)
你可能想要在代碼中強調統計變換。例如,你可以使用stat_summary() 函數將人們的注意力吸引到你計算出的那些摘要統計量上。stat_summary() 函數為x 的每個唯一值計算y 值的摘要統計:
練習
(1) stat_summary() 函數的默認幾何對象是什么?不使用統計變換函數的話,如何使用幾何對象函數重新生成以上的圖?
geom_pointrange,
(2) geom_col() 函數的功能是什么?它和geom_bar() 函數有何不同?
直方圖,其中柱狀圖的高度表示數據中的值,geom_col()的默認統計變換為identity(),geom_bar()默認為count()
1.8 位置調整
可以使用color 或者fill(這個更有用)圖形屬性來為條形圖上色:
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, color = cut))
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = cut))
如果將fill 圖形屬性映射到另一個變量(如clarity),那么條形會自動分塊堆疊起來。每個彩色矩形表示cut 和clarity 的一種組合。
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut, fill = clarity))
這種堆疊是由position 參數設定的位置調整功能自動完成的。如果不想生成堆疊式條形圖,你還可以使用以下3 種選項之一:"identity"、"fill" 和"dodge"。
? position = "identity" 將每個對象直接顯示在圖中。這種方式不太適合條形圖,因為條形會彼此重疊。為了讓重疊部分能夠顯示出來,我們可以設置alpha 參數為一個較小的數,從而使得條形略微透明;或者設定fill = NA,讓條形完全透明:
ggplot(
data = diamonds,
mapping = aes(x = cut, fill = clarity)
) +
geom_bar(alpha = 1/5, position = "identity")
ggplot(
data = diamonds,
mapping = aes(x = cut, color = clarity)
) +
geom_bar(fill = NA, position = "identity")
? position = "fill" 的效果與堆疊相似,但每組堆疊條形具有同樣的高度,因此這種條形圖可以非常輕松地比較各組間的比例:
ggplot(data = diamonds) +
geom_bar(
mapping = aes(x = cut, fill = clarity),
position = "fill"
)
? position = "dodge" 將每組中的條形依次并列放置,這樣可以非常輕松地比較每個條形表示的具體數值:
ggplot(data = diamonds) +
geom_bar(
mapping = aes(x = cut, fill = clarity),
position = "dodge"
)
回憶一下我們的第一張散點圖。你是否發現,雖然數據集中有234 個觀測值,但散點圖中只顯示了126 個點?
因為hwy 和displ 的值都進行了舍入取整,所以這些點顯示在一個網格上時,很多點彼此重疊了。這個問題稱為過繪制。點的這種排列方式很難看出數據的聚集模式。數據點是均勻地分布在圖中,還是存在hwy 和displ 的特殊組合,其中包括了109 個點?
通過將位置調整方式設為“抖動”,可以避免這種網格化排列。position = "jitter" 為每個數據點添加一個很小的隨機擾動,這樣就可以將重疊的點分散開來,因為不可能有兩個點會收到同樣的隨機擾動:
添加隨機性來改善圖形似乎是一種奇怪的方式,然而盡管這種方式會損失圖形的精確性,但可以大大提高圖形的啟發性。因為這種操作的用處非常大,所以ggplot2 提供了geom_point(position = "jitter") 的一種快速實現方式:geom_jitter()。
1.9坐標系
坐標系可能是ggplot2 中最復雜的部分。默認的坐標系是笛卡兒直角坐標系,可以通過其獨立作用的x 坐標和y 坐標找到每個數據點。偶爾也會用到一些其他類型的坐標系。
? coord_flip() 函數可以交換x 軸和y 軸。當想要繪制水平箱線圖時,這非常有用。它也非常適合使用長標簽,但要想在x 軸上不重疊地安排好它們是非常困難的:
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
geom_boxplot()
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
geom_boxplot() +
coord_flip()
? coord_polar() 函數使用極坐標系。極坐標系可以揭示出條形圖和雞冠花圖間的一種有趣聯系:
bar <- ggplot(data = diamonds) +
geom_bar(
mapping = aes(x = cut, fill = cut),
show.legend = FALSE,
width = 1
) +
theme(aspect.ratio = 1) +
labs(x = NULL, y = NULL)
p1<-bar + coord_flip()
p2<-bar + coord_polar()
ggarrange(p1, p2)
1.10 圖形分層語法
在前面幾節中,你學到的絕不僅僅是如何繪制散點圖、條形圖和箱線圖,而是使用ggplot2繪制任何類型圖形的基礎知識。為了說明這一點,我們向前面的代碼模板中添加位置調整、統計變換、坐標系和分面:
ggplot(data = <DATA>) +
<GEOM_FUNCTION>(
mapping = aes(<MAPPINGS>),
stat = <STAT>,
position = <POSITION>
) +
<COORDINATE_FUNCTION> +
<FACET_FUNCTION>
為了說明圖形語法的工作方式,我們看一下如何從頭開始構建一個基本圖形:首先需要有一個數據集,然后(通過統計變換)將其轉換為想要顯示的信息。
接下來,你可以選擇一個幾何對象來表示轉換后的數據中的每個觀測值,然后選擇幾何對象的圖形屬性來表示數據中的變量,這會將每個變量的值映射為圖形屬性的水平。
下一步是選擇放置幾何對象的坐標系。你可以使用對象位置(對象本身的一個圖形屬性)來顯示x 變量和y 變量的值。這樣就生成了一張完整的圖。但你還可以進一步調整幾何對象在坐標系中的位置(位置調整),或者將圖劃分為多個子圖(分面)。你還可以通過添加一個或多個附加圖層對圖進行擴展,其中每個附加圖層都使用一個數據集、一個幾何對象、一個映射集合、一個統計變換和一個位置調整。