哈佛教授公開R語言源碼,教你用R制作gif動(dòng)圖
在日常教學(xué)的過程中,我有時(shí)會(huì)用動(dòng)畫來形象地解釋概念,并且通過 @rafalab賬號(hào)(https://twitter.com/rafalab)在社交媒體上分享。
John Storey最近問我是否可以公開這些源代碼。由于我不甚有條理,而且這些動(dòng)畫都是靈機(jī)一動(dòng)想出來的,所以之前這些代碼分散在幾個(gè)不相關(guān)聯(lián)的文件中。John的請(qǐng)求促使我把這些代碼整理在一起發(fā)布在這里。
所有的gif動(dòng)圖都是用R語言繪制的數(shù)張圖片的疊加。在代碼中你可以發(fā)現(xiàn),我用幾種不同的方法將單獨(dú)的圖片轉(zhuǎn)化成動(dòng)態(tài)gif圖。***種方法(不推薦)是將圖片文件存儲(chǔ)下來,然后調(diào)用ImageMagick轉(zhuǎn)化工具(https://www.imagemagick.org/script/index.php)。在R環(huán)境下,我現(xiàn)在使用的方法是animation包的saveGIF函數(shù),這是通過讀者Yihui Xie在我simplystats博客下面的評(píng)論學(xué)習(xí)到的。當(dāng)用ggplot畫圖時(shí),我會(huì)使用David Robinson的gganimate包(https://github.com/dgrtwo/gganimate)。***一種方法是我在加特效(例如調(diào)相)時(shí)會(huì)用到的:在線Animated GIF maker(https://ezgif.com/maker)。
以下就是這些gif動(dòng)圖的源代碼,我大致按流行程度排序。因?yàn)榇a是很著急寫出來的,請(qǐng)不要過于苛責(zé)我。事實(shí)上,你可以隨意批判,這就是我們學(xué)習(xí)的方式。
辛普森悖論
這張gif闡述的是辛普森悖論:我們看到X變量和Y變量有很強(qiáng)的負(fù)相關(guān)關(guān)系。不過,一旦我們用一個(gè)混雜因素Z變量進(jìn)行分層,用不同顏色來表示Z,每一層中的相關(guān)性就會(huì)轉(zhuǎn)化為正相關(guān)。這里的數(shù)據(jù)是虛構(gòu)的,不過假設(shè)說X代表學(xué)生參加輔導(dǎo)的次數(shù),Y代表九年級(jí)的測驗(yàn)分?jǐn)?shù),然后再用八年級(jí)的測驗(yàn)分?jǐn)?shù)Z來對(duì)學(xué)生進(jìn)行分層,我們也會(huì)發(fā)現(xiàn)這樣的現(xiàn)象。
這張動(dòng)圖僅用三張圖片組成。我用RStudio的Export功能將它們把存下來,然后用Animated GIF maker(https://ezgif.com/maker)來制作gif。以下是這三張圖片的代碼:
局部加權(quán)回歸散點(diǎn)平滑法(Loess)
我分享的***個(gè)教學(xué)動(dòng)圖是為了解釋局部加權(quán)回歸散點(diǎn)平滑法(Loess)的原理。具體來說,我們對(duì)于每一個(gè)自變量,比如x0,都讓其對(duì)任何一個(gè)臨近點(diǎn)有正的加權(quán)值,用加權(quán)回歸擬合一條線,保留經(jīng)過擬合所得的結(jié)果,然后移動(dòng)向下一個(gè)點(diǎn)。
這里的數(shù)據(jù)來源是某個(gè)基因芯片實(shí)驗(yàn)。圖中所示的是MA圖,即比例對(duì)數(shù)與對(duì)數(shù)平均值之間的關(guān)系。我用animation包來保存gif動(dòng)圖。
預(yù)期壽命 vs 生育率
這個(gè)gif動(dòng)圖是復(fù)制Hans Rosling (https://en.wikipedia.org/wiki/ Hans_Rosling)在他的演講“關(guān)于貧窮的新發(fā)現(xiàn)”(New Insights on Poverty,(https://www.ted.com/talks/ hans_rosling_reveals_new_insights_on_poverty?language=en))中展示的動(dòng)畫。該圖很好地展現(xiàn)出數(shù)據(jù)可視化在消除誤解方面的作用,Hans Rosling通過這張動(dòng)圖展示了如今并不如40年前一樣能夠簡單將世界劃分成兩半。之前,人們一般把世界分為擁有更長壽命、較少家庭人口的西方富有國家和較短壽命、較多家庭人口的發(fā)展中國家,而這個(gè)圖向我們展示了這種劃分的不合理性。
感謝gganimate包,畫這個(gè)圖使用的代碼非常簡單。
聯(lián)合國選舉模式
這里,我們使用Erik Voeten和Anton Strezhnev提供的聯(lián)合國選舉數(shù)據(jù)來闡釋距離的概念。
以下是代碼。整理數(shù)據(jù)的代碼是由David Robinson(https://twitter.com/drob)提供的。你會(huì)看到我們將隨時(shí)間變化的距離進(jìn)行了平滑處理,從而避免一些點(diǎn)跳動(dòng)范圍過大。
隨機(jī)森林
在過去的很長一段時(shí)間里,我都覺得很難理解為何隨機(jī)森林作為一種基于樹的算法,卻能夠產(chǎn)生平滑的預(yù)測。這里的gif圖幫助我理解了原因。我用的是2008年總統(tǒng)選舉的數(shù)據(jù)庫,因?yàn)槲艺J(rèn)為該數(shù)據(jù)的趨勢總體是平滑的,但是有幾個(gè)尖銳的邊,就連局部加權(quán)回歸散點(diǎn)平滑法都很難預(yù)測。需要注意的是,我們只有一個(gè)影響因素,這個(gè)gif并不能展示出隨機(jī)森林的另一個(gè)重要特點(diǎn):隨機(jī)的特征選取可以減少樹與樹之間的相關(guān)程度。
你可以看到我在代碼中使用的方式是傳統(tǒng)的、我并不推薦的方式:保存所有的圖片文件然后調(diào)用系統(tǒng)指令轉(zhuǎn)化。
生態(tài)謬誤
在分享辛普森悖論的動(dòng)圖以后,有些人問我生態(tài)謬誤是不是相同的情況。其實(shí)這二者是不同的。生態(tài)謬誤是我們試圖通過平均值的強(qiáng)相關(guān)性來推斷個(gè)體之間的相關(guān)性。為了更好的解釋,我用dslabs包中自帶的gapminder的數(shù)據(jù)(http://gapminder.org/)畫出了一個(gè)動(dòng)圖,展示新生兒存活率的對(duì)數(shù)與日均收入的對(duì)數(shù)之間的關(guān)系。可以看到在地區(qū)層面上二者相關(guān)度很高,但在各個(gè)國家層面上相關(guān)度很低。這是因?yàn)橥坏貐^(qū)國家與國家之間的差異導(dǎo)致的。
這張gif只由三張圖構(gòu)成。我用RStudio的Export功能保存圖片,然后用Animated GIF maker(https://ezgif.com/maker)來制作gif。
***張圖是地區(qū)平均值;撒哈拉以南非洲國家的數(shù)值,你可以看到一個(gè)平均值被分成數(shù)個(gè)不同的數(shù)值;第三張是所有國家的情況。我標(biāo)出了一些(與本地區(qū)相比)變化較大的國家,并且用了色盲也能識(shí)別的顏色。這里的代碼有些復(fù)雜,原因是我不得不對(duì)Gapminder數(shù)據(jù)進(jìn)行預(yù)處理。
貝葉斯定律
這個(gè)簡單的動(dòng)圖展示的是將一種非常準(zhǔn)確的診斷方法應(yīng)用于一個(gè)發(fā)病率很低的群體的診斷結(jié)果。它展示出來的是,在已知診斷結(jié)果是陽性的情況下發(fā)病的先驗(yàn)概率,比該診斷方法的初試準(zhǔn)確率要低。你可以用貝葉斯定律來確定真實(shí)的條件概率。更多細(xì)節(jié)請(qǐng)參考這里(https://simplystatistics.org/2014/10/17/bayes-rule-in-a-gif/)。
因?yàn)槲覀円鰟?dòng)態(tài)圖,代碼有一些復(fù)雜難懂。
吃豆子
***,我做了這個(gè)動(dòng)畫,向你們展示餅圖唯一的用處。