第四章:工作流:腳本
迄今為止,我們一直使用RStudio 控制臺(tái)來(lái)運(yùn)行代碼添寺。這是一個(gè)非常好的開(kāi)始,但如果需要?jiǎng)?chuàng)建更復(fù)雜的ggplot2 圖形或者dplyr 管道,你很快就會(huì)發(fā)現(xiàn)控制臺(tái)非常不方便吭露。為了拓展工作空間,我們應(yīng)該使用RStudio 腳本編輯器尊惰。要想打開(kāi)腳本編輯器讲竿,可以點(diǎn)擊File 菜單,選擇New File弄屡,接著選擇R Script题禀;也可以使用組合鍵Ctrl+Shift+N。現(xiàn)在你可以看到4 個(gè)窗格膀捷。
如果你很重視一段代碼迈嘹,那么腳本編輯器就是存放這段代碼的絕好位置。你可以在控制臺(tái)中不斷調(diào)試,一旦代碼正常運(yùn)行并輸出預(yù)期結(jié)果秀仲,你就可以將其放在腳本編輯器中融痛。當(dāng)退出RStudio 時(shí),它會(huì)自動(dòng)保存編輯器中的內(nèi)容神僵,并在重新打開(kāi)時(shí)自動(dòng)加載編輯器中的內(nèi)容雁刷。盡管如此,我們還是應(yīng)該定時(shí)保存腳本挑豌,并做好備份安券。
4.1 運(yùn)行代碼
腳本編輯器還非常適合建立復(fù)雜的ggplot2 圖形或較長(zhǎng)的dplyr 操作序列。有效使用腳本編輯器的關(guān)鍵是記住最重要的快捷鍵之一:Ctrl+Enter氓英。這組快捷鍵會(huì)在控制臺(tái)中執(zhí)行當(dāng)前的R 語(yǔ)句侯勉。例如,輸入以下代碼后铝阐,如果光標(biāo)在█ 處址貌,那么按Ctrl+Enter 會(huì)運(yùn)行生成not_cancedlled 的完整命令,并將光標(biāo)移到下一個(gè)語(yǔ)句(即以not_cancelled %>% 開(kāi)頭的語(yǔ)句)徘键。因此练对,重復(fù)按Ctrl+Enter 就可以輕松運(yùn)行整個(gè)腳本:
除了按照語(yǔ)句順序運(yùn)行,還可以一次性運(yùn)行整個(gè)腳本:Ctrl+Shift+S吹害。定期運(yùn)行整個(gè)腳本是非常好的做法螟凭,可以讓你確認(rèn)腳本中所有重要的代碼都沒(méi)有問(wèn)題。
4.2 Rstudio自動(dòng)診斷
腳本編輯器還會(huì)利用紅色波浪線和邊欄的紅叉來(lái)高亮顯示語(yǔ)法錯(cuò)誤:
將鼠標(biāo)移到紅叉上就可以看到錯(cuò)誤提示:
RStudio 還能找出潛在的代碼問(wèn)題:
第五章:探索性數(shù)據(jù)分析
5.1 簡(jiǎn)介
本章將展示如何使用可視化方法和數(shù)據(jù)轉(zhuǎn)換來(lái)系統(tǒng)化地探索數(shù)據(jù)它呀,統(tǒng)計(jì)學(xué)家將這項(xiàng)任務(wù)稱為探索性數(shù)據(jù)分析(exploratory data analysis螺男,EDA)。EDA 是一個(gè)可迭代的循環(huán)過(guò)程纵穿,具有以下作用下隧。
(1) 對(duì)數(shù)據(jù)提出問(wèn)題。
(2) 對(duì)數(shù)據(jù)進(jìn)行可視化谓媒、轉(zhuǎn)換和建模淆院,進(jìn)而找出問(wèn)題的答案。
(3) 使用上一個(gè)步驟的結(jié)果來(lái)精煉問(wèn)題句惯,并提出新問(wèn)題土辩。
EDA 并不是具有嚴(yán)格規(guī)則的正式過(guò)程,它首先是一種思維狀態(tài)宗弯。在EDA 的初始階段脯燃,應(yīng)該天馬行空地發(fā)揮想象力,并考察和試驗(yàn)?zāi)軌蛳氲降乃蟹椒杀!S行┫敕ㄊ切械猛ǖ模行┫敕▌t會(huì)無(wú)疾而終欲主。當(dāng)探索更進(jìn)一步時(shí)邓厕,你就可以鎖定容易產(chǎn)生成果的幾個(gè)領(lǐng)域逝嚎,將最終想法整理成文,并與他人進(jìn)行溝通详恼。
EDA 是所有數(shù)據(jù)分析過(guò)程中的重要環(huán)節(jié)补君,因?yàn)榭偸切枰疾煲幌聰?shù)據(jù)質(zhì)量,即使你可以不費(fèi)吹灰之力就找出問(wèn)題昧互。數(shù)據(jù)清洗只是EDA 的一項(xiàng)具體應(yīng)用挽铁,此時(shí)你提出的問(wèn)題是,數(shù)據(jù)是否符合預(yù)期敞掘。要想進(jìn)行數(shù)據(jù)清洗叽掘,需要使用所有的EDA 工具:可視化、數(shù)據(jù)轉(zhuǎn)換和建模玖雁。
5.2 問(wèn)題
EDA 期間的目標(biāo)是獲取對(duì)數(shù)據(jù)的理解更扁。進(jìn)行EDA 的最簡(jiǎn)單的方式就是將問(wèn)題作為指導(dǎo)調(diào)查研究的工具。提出問(wèn)題后赫冬,這個(gè)問(wèn)題就使得你將注意力集中在數(shù)據(jù)集中的特定部分浓镜,并幫助你進(jìn)行有關(guān)圖形、模型和數(shù)據(jù)轉(zhuǎn)換的決定劲厌。
EDA 本質(zhì)上是一個(gè)創(chuàng)造性過(guò)程膛薛。和多數(shù)創(chuàng)造性過(guò)程一樣,問(wèn)題的質(zhì)量關(guān)鍵在于問(wèn)題的數(shù)量补鼻。分析過(guò)程的開(kāi)始階段很難提出有啟發(fā)性的問(wèn)題哄啄,因?yàn)槟悴⒉恢罃?shù)據(jù)集中包含了哪些真知灼見(jiàn)。另一方面辽幌,你提出的每個(gè)新問(wèn)題都可以揭示數(shù)據(jù)中的新內(nèi)容增淹,并增加發(fā)現(xiàn)知識(shí)的機(jī)會(huì)。如果在知識(shí)發(fā)現(xiàn)的基礎(chǔ)上不斷使用新問(wèn)題來(lái)補(bǔ)充每個(gè)老問(wèn)題乌企,那么你就可以快速地獲取數(shù)據(jù)中最令人感興趣的部分虑润,并總結(jié)出一組發(fā)人深省的問(wèn)題。
對(duì)于應(yīng)該提出什么樣的問(wèn)題來(lái)指導(dǎo)我們的研究加酵,現(xiàn)在還沒(méi)有確定的規(guī)則拳喻。但有兩類問(wèn)題總是有助于我們?cè)跀?shù)據(jù)中發(fā)現(xiàn)知識(shí)。我們可以粗略地將這兩類問(wèn)題表述如下猪腕。
(1) 變量本身會(huì)發(fā)生何種變動(dòng)冗澈?
(2) 不同變量之間會(huì)發(fā)生何種相關(guān)變動(dòng)?
本章剩余部分會(huì)繼續(xù)討論這兩個(gè)問(wèn)題陋葡。我們將解釋什么是變動(dòng)亚亲,什么是相關(guān)變動(dòng),并介紹回答這兩個(gè)問(wèn)題的幾種方法。為了簡(jiǎn)化討論捌归,我們先定義幾個(gè)術(shù)語(yǔ)肛响。
? 變量:一種可測(cè)量的數(shù)量、質(zhì)量或?qū)傩浴?br>
? 值:變量在測(cè)量時(shí)的狀態(tài)惜索。變量值在每次測(cè)量之間可以發(fā)生改變特笋。
? 觀測(cè):或稱個(gè)案,指在相同條件下進(jìn)行的一組測(cè)量(通常巾兆,一個(gè)觀測(cè)中的所有測(cè)量是在同一時(shí)間對(duì)同一對(duì)象進(jìn)行的)猎物。一個(gè)觀測(cè)會(huì)包含多個(gè)值,每個(gè)值關(guān)聯(lián)到不同的變量角塑。有時(shí)我們會(huì)將觀測(cè)稱為數(shù)據(jù)點(diǎn)蔫磨。
? 表格數(shù)據(jù):一組值的集合,其中每個(gè)值都關(guān)聯(lián)一個(gè)變量和一個(gè)觀測(cè)吉拳。如果每個(gè)值都有自己所屬的“單元”质帅,每個(gè)變量都有自己所屬的列,每個(gè)觀測(cè)都有自己所屬的行留攒,那么表格數(shù)據(jù)就是整潔的煤惩。
5.3 變動(dòng)
變動(dòng)是每次測(cè)量時(shí)數(shù)據(jù)值的變化趨勢(shì)。實(shí)際生活中很容易看到變動(dòng)炼邀。如果對(duì)任意連續(xù)型變量進(jìn)行兩次測(cè)量魄揉,那么會(huì)得到兩個(gè)不同的結(jié)果,即使測(cè)量的是一個(gè)常數(shù)(如光速)拭宁,情況也是如此洛退。每次測(cè)量的結(jié)果都包括少量誤差,誤差在每次測(cè)量間是不同的杰标。如果測(cè)量多個(gè)項(xiàng)目(如不同人的眼睛顏色)或進(jìn)行多次測(cè)量(如電池在不同時(shí)刻的電量)兵怯,分類變量也會(huì)發(fā)生變化。所有變量都有自己的變動(dòng)模式腔剂,可以揭示出一些有趣的信息媒区。理解這種模式的最好方法就是對(duì)變量值的分布進(jìn)行可視化表示。
5.3.1 對(duì)分布進(jìn)行可視化表示
對(duì)變量分布進(jìn)行可視化的方法取決于變量是分類變量還是連續(xù)變量掸犬。如果僅在較小的集合內(nèi)取值袜漩,那么這個(gè)變量就是分類變量。分類變量在R 中通常保存為因子或字符向量湾碎。要想檢查分類變量的分布只恨,可以使用條形圖:
ggplot(data = diamonds) +geom_bar(mapping = aes(x = cut))
條形的高度表示每個(gè)x 值中觀測(cè)的數(shù)量辕近,可以使用dplyr::count() 手動(dòng)計(jì)算出這些值:
> diamonds %>%
+ count(cut)
# A tibble: 5 x 2
cut n
<ord> <int>
1 Fair 1610
2 Good 4906
3 Very Good 12082
4 Premium 13791
如果可以在無(wú)限大的有序集合中任意取值翻斟,那么這個(gè)變量就是連續(xù)變量曲聂。數(shù)值型和日期時(shí)間型變量就是連續(xù)變量的兩個(gè)例子递惋。要想檢查連續(xù)變量的分布,可以使用直方圖:
ggplot(data = diamonds) +
geom_histogram(mapping = aes(x = carat), binwidth = 0.5)
可以通過(guò)dplyr::count() 和ggplot2::cut_width() 函數(shù)的組合來(lái)手動(dòng)計(jì)算結(jié)果:
> diamonds %>%
+ count(cut_width(carat, 0.5))
# A tibble: 11 x 2
`cut_width(carat, 0.5)` n
<fct> <int>
1 [-0.25,0.25] 785
2 (0.25,0.75] 29498
3 (0.75,1.25] 15977
4 (1.25,1.75] 5313
5 (1.75,2.25] 2002
6 (2.25,2.75] 322
7 (2.75,3.25] 32
8 (3.25,3.75] 5
9 (3.75,4.25] 4
10 (4.25,4.75] 1
直方圖對(duì)x 軸進(jìn)行等寬分箱雹顺,然后使用條形的高度來(lái)表示落入每個(gè)分箱的觀測(cè)的數(shù)量丹墨。在上圖中廊遍,最高的條形表示幾乎有30 000 個(gè)觀測(cè)的carat 值在0.25 和0.75 之間嬉愧,這兩個(gè)值分別是條形的左側(cè)值和右側(cè)值。
使用binwidth 參數(shù)來(lái)設(shè)定直方圖中的間隔的寬度喉前,該參數(shù)是用x 軸變量的單位來(lái)度量的没酣。在使用直方圖時(shí),你應(yīng)該試驗(yàn)一下不同的分箱寬度卵迂,因?yàn)椴煌姆窒鋵挾瓤梢越沂静煌哪J皆1恪@纾绻豢紤]重量小于3 克拉的鉆石见咒,并選擇一個(gè)更小的分箱寬度偿衰,那么直方圖如下所示:
smaller <- diamonds %>%
filter(carat < 3)
ggplot(data = smaller, mapping = aes(x = carat)) +
geom_histogram(binwidth = 0.1)
如果想要在同一張圖上疊加多個(gè)直方圖,那么我們建議你使用geom_freqploy() 函數(shù)來(lái)代替geom_histogram() 函數(shù)改览。geom_freqploy() 可以執(zhí)行和geom_histogram() 同樣的計(jì)算過(guò)程下翎,但前者不使用條形來(lái)顯示計(jì)數(shù),而是使用折線宝当。疊加的折線遠(yuǎn)比疊加的條形更容易理解:
5.3.2 典型值
條形圖和直方圖都用比較高的條形表示變量中的常見(jiàn)值视事,而用比較矮的條形表示變量中不常見(jiàn)的值。沒(méi)有條形的位置表示數(shù)據(jù)中沒(méi)有這樣的值庆揩。為了將這些信息轉(zhuǎn)換為有用的問(wèn)題俐东,看看是否具有意料之外的情況。
? 哪些值是最常見(jiàn)的订晌?為什么虏辫?
? 哪些值是非常罕見(jiàn)的?為什么锈拨?這和你的預(yù)期相符嗎砌庄?
? 你能發(fā)現(xiàn)任何異乎尋常的模式嗎?如何解釋推励?
作為示例鹤耍,可以從以下直方圖發(fā)現(xiàn)幾個(gè)有趣的問(wèn)題。
? 為什么重量為整數(shù)克拉和常見(jiàn)分?jǐn)?shù)克拉的鉆石更多验辞?
? 為什么位于每個(gè)峰值稍偏右的鉆石比稍偏左的鉆石更多稿黄?
? 為什么沒(méi)有重量超過(guò)3 克拉的鉆石?
ggplot(data = smaller, mapping = aes(x = carat)) +
geom_histogram(binwidth = 0.01)
一般來(lái)說(shuō)跌造,相似值聚集形成的簇表示數(shù)據(jù)中存在子組杆怕。為了理解子組族购,我們提出以下問(wèn)題。
? 每個(gè)簇中的觀測(cè)是如何相似的陵珍?
? 不同簇之間的觀測(cè)是如何不相似的寝杖?
? 如何解釋或描述各個(gè)簇?
? 為什么有些簇的外觀可能具有誤導(dǎo)作用互纯?
以下的直方圖顯示了美國(guó)黃石國(guó)家公園中的老忠實(shí)噴泉的272 次噴發(fā)的時(shí)長(zhǎng)(單位為分鐘)瑟幕。噴發(fā)時(shí)間似乎聚集成了兩組:短噴發(fā)(2 分鐘左右)和長(zhǎng)噴發(fā)(4~5 分鐘),這兩組間幾乎沒(méi)有其他噴發(fā)時(shí)間:
ggplot(data = faithful, mapping = aes(x = eruptions)) +
geom_histogram(binwidth = 0.25)
5.3.3 異常值
異常值是與眾不同的觀測(cè)或者是模式之外的數(shù)據(jù)點(diǎn)留潦。有時(shí)異常值是由于數(shù)據(jù)錄入錯(cuò)誤而產(chǎn)生的只盹;有時(shí)異常值則能開(kāi)辟出一塊重要的新科學(xué)領(lǐng)域。如果數(shù)據(jù)量比較大兔院,有時(shí)很難在直方圖上發(fā)現(xiàn)異常值殖卑。例如,查看鉆石數(shù)據(jù)集中y 軸變量的分布坊萝,唯一能表示存在異常值的證據(jù)是孵稽,y 軸的取值范圍出奇得寬:
ggplot(diamonds) +
geom_histogram(mapping = aes(x = y), binwidth = 0.5)
正常值分箱中的觀測(cè)太多了,以致于包括異常值的分箱高度太低十偶,因此我們根本看不見(jiàn)(如果仔細(xì)觀察x 軸0 刻度附近菩鲜,沒(méi)準(zhǔn)你能發(fā)現(xiàn)點(diǎn)什么)。為了更容易發(fā)現(xiàn)異常值扯键,我們可以使用coord_cartesian() 函數(shù)將y 軸靠近0 的部分放大:
ggplot(diamonds) +
geom_histogram(mapping = aes(x = y), binwidth = 0.5) +
coord_cartesian(ylim = c(0, 50))
coord_cartesian() 函數(shù)中有一個(gè)用于放大x 軸的xlim() 參數(shù)睦袖。ggplot2 中也有功能稍有區(qū)別的xlim() 和ylim() 函數(shù):它們會(huì)忽略溢出坐標(biāo)軸范圍的那些數(shù)據(jù)。
這樣一來(lái)荣刑,我們就可以看出有3 個(gè)異常值馅笙,分別位于0、30 左右和60 左右厉亏。我們使用
dplyr 將它們找出來(lái):
> unusual <- diamonds %>%
+ filter(y < 3 | y > 20) %>%
+ arrange(y)
> unusual
# A tibble: 9 x 10
carat cut color clarity depth table price x y
<dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl>
1 1 Very~ H VS2 63.3 53 5139 0 0
2 1.14 Fair G VS1 57.5 67 6381 0 0
3 1.56 Ideal G VS2 62.2 54 12800 0 0
4 1.2 Prem~ D VVS1 62.1 59 15686 0 0
5 2.25 Prem~ H SI2 62.8 59 18034 0 0
6 0.71 Good F SI2 64.1 60 2130 0 0
7 0.71 Good F SI2 64.1 60 2130 0 0
8 0.51 Ideal E VS1 61.8 55 2075 5.15 31.8
9 2 Prem~ H SI2 58.9 57 12210 8.09 58.9
# ... with 1 more variable: z <dbl>
y 變量測(cè)量鉆石的三個(gè)維度之一董习,單位為毫米。我們知道鉆石的寬度不可能是0 毫米爱只,因此這些值肯定是錯(cuò)誤的皿淋。我們也完全可以認(rèn)為32 毫米和59 毫米同樣是令人難以置信的,這樣的鉆石長(zhǎng)度超過(guò)1 英寸(1 英寸=2.54 厘米)恬试,簡(jiǎn)直就是無(wú)價(jià)之寶窝趣!
5.4缺失值
如果在數(shù)據(jù)集中發(fā)現(xiàn)異常值,但只想繼續(xù)進(jìn)行其余的分析工作训柴,那么有2 種選擇哑舒。
? 將帶有可疑值的行全部丟棄
diamonds2 <- diamonds %>%
filter(between(y, 3, 20))
不建議使用這種方式,因?yàn)橐粋€(gè)無(wú)效測(cè)量不代表所有測(cè)量都是無(wú)效的幻馁。此外洗鸵,如果數(shù)據(jù)質(zhì)量不高越锈,若對(duì)每個(gè)變量都采取這種做法,那么你最后可能會(huì)發(fā)現(xiàn)數(shù)據(jù)已經(jīng)所剩無(wú)幾膘滨!
? 相反甘凭,我們建議使用缺失值來(lái)代替異常值。最簡(jiǎn)單的做法就是使用mutate() 函數(shù)創(chuàng)建一個(gè)新變量來(lái)代替原來(lái)的變量火邓。你可以使用ifelse() 函數(shù)將異常值替換為NA:
diamonds2 <- diamonds %>%
mutate(y = ifelse(y < 3 | y > 20, NA, y))
ifelse() 函數(shù)有3 個(gè)參數(shù)丹弱。第一個(gè)參數(shù)test 應(yīng)該是一個(gè)邏輯向量,如果test 為T(mén)RUE贡翘,函數(shù)結(jié)果就是第二個(gè)參數(shù)yes 的值蹈矮;如果test 為FALSE,函數(shù)結(jié)果就是第三個(gè)參數(shù)no 的值鸣驱。
和R 一樣,ggplot2 也遵循不能無(wú)視缺失值的原則蝠咆。因?yàn)闊o(wú)法明確地繪制出缺失值踊东,所以ggplot2 在繪圖時(shí)會(huì)忽略缺失值,但會(huì)提出警告以通知缺失值被丟棄了:
> ggplot(data = diamonds2, mapping = aes(x = x, y = y)) +
+ geom_point()
Warning message:
Removed 9 rows containing missing values (geom_point).
要想不顯示這條警告刚操,可以設(shè)置na.rm = TRUE:
ggplot(data = diamonds2, mapping = aes(x = x, y = y)) +
geom_point(na.rm = TRUE)
5.5 相關(guān)變動(dòng)
如果變動(dòng)描述的是一個(gè)變量?jī)?nèi)部的行為闸翅,那么相關(guān)變動(dòng)描述的就是多個(gè)變量之間的行為。相關(guān)變動(dòng)是兩個(gè)或多個(gè)變量以相關(guān)的方式共同變化所表現(xiàn)出的趨勢(shì)菊霜。查看相關(guān)變動(dòng)的最好方式是將兩個(gè)或多個(gè)變量間的關(guān)系以可視化的方式表現(xiàn)出來(lái)坚冀。如何進(jìn)行這種可視化表示同樣取決于相關(guān)變量的類型。
5.5.1 分類變量與連續(xù)變量
我們經(jīng)常需要探索連續(xù)變量的分布鉴逞,這種分布按照一個(gè)分類變量的值可以分為幾個(gè)組记某,就像前面的頻率多邊形圖一樣。geom_freqpoly() 的默認(rèn)外觀不太適合這種比較构捡,因?yàn)楦叨仁怯捎?jì)數(shù)給出的液南。這就意味著,如果一組觀測(cè)的數(shù)量明顯少于其他組的話勾徽,就很難看出形狀上的差別滑凉。舉個(gè)例子,我們探索一下鉆石價(jià)格是如何隨著質(zhì)量而變化的:
ggplot(data = diamonds, mapping = aes(x = price)) +
geom_freqpoly(mapping = aes(color = cut), binwidth = 500)
很難看出分布上的差別喘帚,因?yàn)榭傮w看來(lái)各組數(shù)量的差別太大了:
按分類變量的分組顯示連續(xù)變量分布的另一種方式是使用箱線圖畅姊。箱線圖是對(duì)變量值分布的一種簡(jiǎn)單可視化表示,這種圖在統(tǒng)計(jì)學(xué)家中非常流行吹由。每張箱線圖都包括以下內(nèi)容若未。
? 一個(gè)長(zhǎng)方形箱子,下面的邊表示分布的第25 個(gè)百分位數(shù)溉知,上面的邊表示分布的第75 個(gè)
百分位數(shù)陨瘩,上下兩邊的距離稱為四分位距腕够。箱子的中部有一條橫線,表示分布的中位數(shù)舌劳,
也就是分布的第50 個(gè)百分位數(shù)帚湘。這三條線可以表示分布的分散情況,還可以幫助我們
明確數(shù)據(jù)是關(guān)于中位數(shù)對(duì)稱的甚淡,還是偏向某一側(cè)大诸。
? 圓點(diǎn)表示落在箱子上下兩邊1.5 倍四分位距外的觀測(cè),這些離群點(diǎn)就是異常值贯卦,因此需
要單獨(dú)繪出资柔。
? 從箱子上下兩邊延伸出的直線(或稱為須)可以到達(dá)分布中最遠(yuǎn)的非離群點(diǎn)處。
使用geom_boxplot() 函數(shù)查看按切割質(zhì)量分類的價(jià)格分布:
ggplot(data = diamonds, mapping = aes(x = cut, y = price)) +
geom_boxplot()
雖然看不出太多關(guān)于分布的信息撵割,但箱線圖更加緊湊贿堰,因此可以更容易地比較多個(gè)類別(也更適合使用一張圖來(lái)表示)。與前面的圖形一樣啡彬,我們可以從箱線圖中發(fā)現(xiàn)違反直覺(jué)的現(xiàn)象:質(zhì)量更好的鉆石的平均價(jià)格更低羹与!你將在練習(xí)中接受這一挑戰(zhàn),說(shuō)明為什么會(huì)這樣庶灿。
cut 是一個(gè)有序因子:“一般”不如“較好”纵搁、“較好”不如“很好”,以此類推往踢。因?yàn)楹芏喾诸愖兞坎](méi)有這種內(nèi)在的順序腾誉,所以有時(shí)需要對(duì)其重新排序來(lái)繪制信息更豐富的圖形。重新排序的其中一種方法是使用reorder() 函數(shù)峻呕。
例如利职,我們看一下mpg 數(shù)據(jù)集中的class 變量。你可能很想知道公路里程因汽車類別的不同會(huì)有怎樣的變化:
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
geom_boxplot()
為了更容易發(fā)現(xiàn)趨勢(shì)山上,可以基于hwy 值的中位數(shù)對(duì)class 進(jìn)行重新排序:
ggplot(data = mpg, mapping = aes(
x = reorder(class,hwy,FUN = median),
y = hwy)) +
geom_boxplot()
如果變量名很長(zhǎng)眼耀,那么將圖形旋轉(zhuǎn)90 度效果會(huì)更好一些。你可以通過(guò)coord_flip() 函數(shù)完成這一操作:
5.5.2 兩個(gè)分類變量
要想對(duì)兩個(gè)分類變量間的相關(guān)變動(dòng)進(jìn)行可視化表示佩憾,需要計(jì)算出每個(gè)變量組合中的觀測(cè)數(shù)量哮伟。完成這個(gè)任務(wù)的其中一種方法是使用內(nèi)置的geom_count() 函數(shù):
ggplot(data = diamonds) +
geom_count(mapping = aes(x = cut, y = color))
圖中每個(gè)圓點(diǎn)的大小表示每個(gè)變量組合中的觀測(cè)數(shù)量。相關(guān)變動(dòng)就表示為特定x 軸變量值與特定y 軸變量值之間的強(qiáng)相關(guān)關(guān)系妄帘。
計(jì)算變量組合中的觀測(cè)數(shù)量的另一種方法是使用dplyr:
> diamonds %>%
+ count(color, cut)
# A tibble: 35 x 3
color cut n
<ord> <ord> <int>
1 D Fair 163
2 D Good 662
3 D Very Good 1513
4 D Premium 1603
5 D Ideal 2834
6 E Fair 224
7 E Good 933
8 E Very Good 2400
9 E Premium 2337
10 E Ideal 3903
# ... with 25 more rows
接著使用geom_tile() 函數(shù)和填充圖形屬性進(jìn)行可視化表示:
diamonds %>%
count(color, cut) %>%
ggplot(mapping = aes(x = color, y = cut)) +
geom_tile(mapping = aes(fill = n))
如果分類變量是無(wú)序的楞黄,那么可以使用seriation 包對(duì)行和列同時(shí)進(jìn)行重新排序,以便更清楚地表示出有趣的模式抡驼。對(duì)于更大的圖形鬼廓,你可以使用d3heatmap 或heatmaply 包,這兩個(gè)包都可以生成有交互功能的圖形致盟。
5.5.3 兩個(gè)連續(xù)變量
對(duì)于兩個(gè)連續(xù)變量間的相關(guān)變動(dòng)的可視化表示碎税,我們已經(jīng)介紹了一種非常好的方法:使用geom_point() 畫(huà)出散點(diǎn)圖尤慰。你可以將相關(guān)變動(dòng)看作點(diǎn)的模式。例如雷蹂,你可以看到鉆石的克拉數(shù)和價(jià)值之間存在一種指數(shù)關(guān)系:
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price))
隨著數(shù)據(jù)集規(guī)模的不斷增加伟端,散點(diǎn)圖的用處越來(lái)越小,因?yàn)閿?shù)據(jù)點(diǎn)開(kāi)始出現(xiàn)過(guò)繪制匪煌,并堆積在一片黑色區(qū)域中(如上面的散點(diǎn)圖所示)责蝠。我們已經(jīng)介紹了解決這個(gè)問(wèn)題的一種方法,即使用alpha 圖形屬性添加透度:
ggplot(data = diamonds) +
geom_point(
mapping = aes(x = carat, y = price),
alpha = 1 / 100
)
但是很難對(duì)特別大的數(shù)據(jù)集使用透明度萎庭。另一種解決方法是使用分箱霜医。我們之前使用了geom_histogram() 和geom_freqpoly() 函數(shù)在一個(gè)維度上進(jìn)行分箱,現(xiàn)在學(xué)習(xí)如何使用geom_bin2d() 和geom_hex() 函數(shù)在兩個(gè)維度上進(jìn)行分箱驳规。
geom_bin2d() 和geom_hex() 函數(shù)將坐標(biāo)平面分為二維分箱肴敛,并使用一種填充顏色表示落入每個(gè)分箱的數(shù)據(jù)點(diǎn)。geom_bin2d() 創(chuàng)建長(zhǎng)方形分箱达舒。geom_hex() 創(chuàng)建六邊形分箱值朋。要想使用geom_hex(),需要安裝hexbin 包:
ggplot(data = smaller) +
geom_bin2d(mapping = aes(x = carat, y = price))
ggplot(data = smaller) +
geom_hex(mapping = aes(x = carat, y = price))
另一種方式是對(duì)一個(gè)連續(xù)變量進(jìn)行分箱巩搏,因此這個(gè)連續(xù)變量的作用就相當(dāng)于分類變量。接下來(lái)就可以使用前面學(xué)過(guò)的對(duì)分類變量和連續(xù)變量的組合進(jìn)行可視化的技術(shù)了趾代。例如贯底,你可以對(duì)carat 進(jìn)行分箱,然后為每個(gè)組生成一個(gè)箱線圖:
ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_width(carat, 0.1)))
以上示例使用了cut_width(x, width) 函數(shù)將x 變量分成寬度為width 的分箱撒强。默認(rèn)情況下禽捆,不管其中有多少個(gè)觀測(cè),箱線圖看上去都差不多(除了離群點(diǎn)的數(shù)量不同)飘哨,因此很難分辨出每個(gè)箱線圖是對(duì)不同數(shù)量的觀測(cè)進(jìn)行摘要統(tǒng)計(jì)的胚想。如果想要體現(xiàn)這種信息,可以使用參數(shù)varwidth = TRUE 讓箱線圖的寬度與觀測(cè)數(shù)量成正比芽隆。
另一種方法是近似地顯示每個(gè)分箱中的數(shù)據(jù)點(diǎn)的數(shù)量浊服,此時(shí)可以使用cut_number() 函數(shù):
ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_number(carat, 20)))
5.6 模式和模型
數(shù)據(jù)中的模式提供了關(guān)系線索。如果兩個(gè)變量之間存在系統(tǒng)性的關(guān)系胚吁,那么這種關(guān)系就會(huì)
在數(shù)據(jù)中表現(xiàn)為一種模式牙躺。如果發(fā)現(xiàn)了模式,需要問(wèn)自己以下幾個(gè)問(wèn)題腕扶。
? 這種模式的出現(xiàn)會(huì)不會(huì)是一種巧合(也就是隨機(jī)的偶然因素)孽拷?
? 應(yīng)該如何描述這種模式中隱含的關(guān)系?
? 這種模式中隱含的關(guān)系有多強(qiáng)半抱?
? 其他變量會(huì)如何影響這種關(guān)系脓恕?
? 如果對(duì)數(shù)據(jù)的獨(dú)立分組進(jìn)行檢查膜宋,這種關(guān)系會(huì)有所變化嗎?
我們就前面提到的美國(guó)黃石國(guó)家公園中老忠實(shí)噴泉的噴發(fā)時(shí)長(zhǎng)和兩次噴發(fā)之間的等待時(shí)間
做出一張散點(diǎn)圖炼幔,該圖會(huì)顯示出一個(gè)模式:較長(zhǎng)的等待時(shí)間與較長(zhǎng)的噴發(fā)時(shí)間是相關(guān)的秋茫。
圖中還顯示出兩個(gè)簇,這個(gè)我們之前就發(fā)現(xiàn)了:
ggplot(data = faithful) +
geom_point(mapping = aes(x = eruptions, y = waiting))
模式是數(shù)據(jù)科學(xué)中最有效的工具之一江掩,因?yàn)槠淇梢越沂鞠嚓P(guān)變動(dòng)学辱。如果說(shuō)變動(dòng)會(huì)生成不確定性,那么相關(guān)變動(dòng)就是減少不確定性环形。如果兩個(gè)變量是共同變化的策泣,就可以使用一個(gè)變量的值來(lái)更好地預(yù)測(cè)另一個(gè)變量的值。如果相關(guān)變動(dòng)可以歸因于一種因果關(guān)系(一種特殊情況)抬吟,那么就可以使用一個(gè)變量的值來(lái)控制另一個(gè)變量的值萨咕。
模型是用于從數(shù)據(jù)中抽取模式的一種工具。例如火本,我們思考一下鉆石數(shù)據(jù)危队。切割質(zhì)量與價(jià)格之間的關(guān)系是很難理解的,因?yàn)榍懈钯|(zhì)量和克拉數(shù)以及克拉數(shù)和價(jià)格之間是緊密相關(guān)的钙畔。我們可以使用模型去除價(jià)格和克拉數(shù)之間的強(qiáng)關(guān)系茫陆,這樣就可以繼續(xù)研究剩余的微妙關(guān)系。以下代碼擬合了一個(gè)模型擎析,可以根據(jù)carat 預(yù)測(cè)price簿盅,并計(jì)算出殘差(預(yù)測(cè)值和實(shí)際值之間的差別)。一旦去除克拉數(shù)對(duì)價(jià)格的影響揍魂,殘差就能反映出鉆石的價(jià)格:
library(modelr)
mod <- lm(log(price) ~ log(carat), data = diamonds)
diamonds2 <- diamonds %>%
add_residuals(mod) %>%
mutate(resid = exp(resid))
ggplot(data = diamonds2) +
geom_point(mapping = aes(x = carat, y = resid))
去除克拉數(shù)和價(jià)格之間的強(qiáng)關(guān)系后桨醋,就可以看到預(yù)料中的切割質(zhì)量與價(jià)格的關(guān)系,對(duì)于同樣大小的鉆石现斋,切割質(zhì)量更好的鉆石更昂貴:
ggplot(data = diamonds2) +
geom_boxplot(mapping = aes(x = cut, y = resid))
5.7 ggplot2調(diào)用
通常情況下喜最,一個(gè)函數(shù)的前一個(gè)或前兩個(gè)參數(shù)是非常重要的,你應(yīng)該將它們牢記于心庄蹋。ggplot() 函數(shù)的前兩個(gè)參數(shù)是data 和mapping瞬内,aes() 函數(shù)的前兩個(gè)參數(shù)是x 和y。在本書(shū)剩余的部分中蔓肯,我們不再寫(xiě)出這些參數(shù)名遂鹊,這樣既可以節(jié)省輸入時(shí)間,也可以讓代碼樣板更精簡(jiǎn)蔗包,以便更容易找出兩張圖之間的不同之處秉扑。
ggplot(data = faithful, mapping = aes(x = eruptions)) +
geom_freqpoly(binwidth = 0.25)
ggplot(faithful, aes(eruptions)) +
geom_freqpoly(binwidth = 0.25)
第六章:工作流:項(xiàng)目
6.1什么是真實(shí)的
作為R 的一名新手,你可以認(rèn)為自己的R 環(huán)境(也就是環(huán)境窗格中列出的那些對(duì)象)是“真實(shí)的”。但從長(zhǎng)遠(yuǎn)來(lái)看舟陆,你最好認(rèn)為R 腳本是“真實(shí)的”误澳。可以通過(guò)R 腳本(以及數(shù)據(jù)文件)重建R 環(huán)境秦躯,但在R 環(huán)境中重建R 腳本就要困難得多忆谓!要么被迫重敲一次內(nèi)存中的代碼(伴隨著各種輸入錯(cuò)誤),要么被迫在R 歷史記錄中埋頭翻找踱承。為了培養(yǎng)良好的使用習(xí)慣倡缠,我們強(qiáng)烈建議你指示RStudio 不在兩次會(huì)話間保存工作空間。
6.2 你的分析位于哪里
R 中有個(gè)名為工作目錄的重要概念茎活。R 在這個(gè)目錄中查找你要加載的文件昙沦,也將你要保存的文件放在這個(gè)目錄中。RStudio 在控制臺(tái)上方顯示當(dāng)前工作目錄载荔。
可以通過(guò)運(yùn)行g(shù)etwd() 命令在R 代碼中輸出這個(gè)目錄:
> getwd()
[1] "C:/Users/zszpc/Documents"
作為R 語(yǔ)言新手盾饮,你可以使用自己的主目錄、文檔目錄或計(jì)算機(jī)上其他稀奇古怪的目錄作為R 的工作目錄懒熙。但既然已經(jīng)學(xué)習(xí)了本書(shū)的6 章內(nèi)容丘损,你也應(yīng)該掌握一定的知識(shí)了。從現(xiàn)在開(kāi)始工扎,你應(yīng)該逐漸學(xué)會(huì)使用目錄來(lái)組織分析項(xiàng)目徘钥,每開(kāi)始一個(gè)項(xiàng)目,就應(yīng)該將R 的工作目錄設(shè)置為與這個(gè)項(xiàng)目相關(guān)的目錄肢娘。
還可以使用R 的命令來(lái)設(shè)置工作目錄吏饿,但我們不建議使用這種方法:
setwd("/path/to/my/CoolProject")
不要使用這種操作,因?yàn)檫€有更好的方法蔬浙,可以讓你像專家一樣管理與R 相關(guān)的工作。
6.3 路徑與目錄
路徑與目錄稍微有一點(diǎn)復(fù)雜贞远,因?yàn)槁窂接? 種基本風(fēng)格:Mac/Linux 和Windows畴博。它們主要有以下3 種區(qū)別。
? 最重要的區(qū)別是如何分隔路徑中的各個(gè)部分蓝仲。Mac 和Linux 使用的是斜杠(如plots/diamonds.pdf)俱病,Windows 使用的則是反斜杠(如plots\diamonds.pdf)。R 支持任意一種類型(不管你現(xiàn)在使用的是哪種平臺(tái))袱结,但問(wèn)題是亮隙,反斜杠在R 中具有特殊意義,因此垢夹,如果想要表示路徑中的單個(gè)反斜杠溢吻,你需要輸入2 個(gè)反斜杠!這有點(diǎn)令人沮喪,因此我們建議你一直使用Linux/Mac 風(fēng)格的斜杠促王。
? 絕對(duì)路徑(即不管你的工作目錄是什么犀盟,都指向一個(gè)位置的路徑)的形式不同。在Windows 系統(tǒng)中蝇狼,絕對(duì)路徑的開(kāi)頭是驅(qū)動(dòng)器號(hào)(如C:)或兩個(gè)反斜杠(如\servername)阅畴;在Mac/Linux 系統(tǒng)中,絕對(duì)路徑的開(kāi)頭則是斜杠“/”(如/user/hadley)迅耘。千萬(wàn)不要在腳本中使用絕對(duì)路徑贱枣,因?yàn)椴焕诜窒恚簺](méi)有任何人會(huì)和你具有完全相同的目錄設(shè)置。
? 最后一個(gè)小區(qū)別是~ 指向的位置颤专。~ 是指向主目錄的一個(gè)很方便的快捷方式纽哥。Windows其實(shí)沒(méi)有主目錄的概念,因此~ 指向的是文檔目錄血公。