R數據科學筆記:1

最近把之前的《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 決定。


用數值進行標識的R 的25 種內置形狀

練習

(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 變量的值。這樣就生成了一張完整的圖。但你還可以進一步調整幾何對象在坐標系中的位置(位置調整),或者將圖劃分為多個子圖(分面)。你還可以通過添加一個或多個附加圖層對圖進行擴展,其中每個附加圖層都使用一個數據集、一個幾何對象、一個映射集合、一個統計變換和一個位置調整。

轉載請注明周小釗的博客>>R4ds1

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372