R語言數據清洗實戰——世界瀕危遺產地數據爬取案例

最近重複新翻閱R語言領域唯一一本關於網路數據採集的參考書——《基於R語言的自動數據收集》,開篇就是一個數據爬取的案例。

儘管之前已經粗略的看過一遍,但是仍感書中諸多細節不甚理解,還有平時過於眼高手低,第一遍看的時候只是動眼卻不動手,案例幾乎很少做過,準備刷第二遍,案例也打算仔仔細細的過一遍,做的時候才發現作者書中代碼有些部分已經無法運行,還是需要自己去一點兒一點兒倒騰。

library("XML")library("stringr")library("RCurl")library("dplyr")library("rvest")

以下是書中案例引用的世界瀕危文化遺產名錄的維基百科地址。

url<-"https://en.wikipedia.org/wiki/List_of_World_Heritage_in_Danger"

經過自己嘗試,作者書中的代碼已經無法運行,這裡我藉助RCurl結合readHTMLTable函數完成了數據抓取,當然你也可以使用rvest會更方便一些。

heritage_parsed <- getURL(url,.encoding="utf-8") %>% readHTMLTable(stringAsFactors=FALSE)

仔細查看第一部分內容的結構(是一個list體),裡面嵌套有所有表格(數據框 ),確定我們需要的表格是第2、4兩個。

因為該網頁有兩份目標數據,所以需要分別提取,並直接剔除我們不需要的列。

heritage_Current<-heritage_parsed[[2]] %>% .[,setdiff(1:ncol(.),c(2,5,7,9))]heritage_Previous<-heritage_parsed[[4]] %>% .[,setdiff(1:ncol(.),c(2,5,7,9))]

原始數據非常混亂,我使用stringr結合sapply函數,分別提取了遺產的所在地址、經緯度信息、類別信息等。以下函數除了sapply之外,我都在最近幾篇的推送中有所涉及,特別是正則表達式在本次數據清洗中起到了很大的作用,如果你對正則還不太熟悉,可以參考這篇文化文章。

左手用R右手Python系列13——字元串處理與正則表達式

heritage_Current$Address<-heritage_Current$Location %>% strsplit(",") %>% sapply("[[",1)heritage_Current$lat<-heritage_Current$Location %>% str_extract("-?\d{1,2}\.\d{1,}; -?\d{1,3}\.\d{1,}") %>% strsplit(";") %>% sapply("[[",1) %>% as.numericheritage_Current$long<-heritage_Current$Location %>% str_extract("-?\d{1,2}\.\d{1,}; -?\d{1,3}\.\d{1,}") %>% strsplit(";") %>% sapply("[[",2) %>% as.numericheritage_Current$Criteria<-heritage_Current$Criteria %>% strsplit(":") %>% sapply("[[",1)heritage_Current<-heritage_Current[,c("Name","Criteria","Address","Year (WHS)","long","lat","Reason")] %>% rename("Year"="Year (WHS)") heritage_Current$Year<-as.numeric(heritage_Current$Year)

因為兩張表格內容格式一致,所以只是修改了表名,其他的沒有任何改動。

heritage_Previous$Address<-heritage_Previous$Location %>% strsplit(",") %>% sapply("[[",1)heritage_Previous$lat<-heritage_Previous$Location %>% str_extract("-?\d{1,2}\.\d{1,}; -?\d{1,3}\.\d{1,}") %>% strsplit(";") %>% sapply("[[",1) %>% as.numericheritage_Previous$long<-heritage_Previous$Location %>% str_extract("-?\d{1,2}\.\d{1,}; -?\d{1,3}\.\d{1,}") %>% strsplit(";") %>% sapply("[[",2) %>% as.numericheritage_Previous$Criteria<-heritage_Previous$Criteria %>% strsplit(":") %>% sapply("[[",1)heritage_Previous<-heritage_Previous[,c("Name","Criteria","Address","Year (WHS)","long","lat","Reason")] %>% rename("Year"="Year (WHS)") heritage_Previous$Year<-as.numeric(heritage_Previous$Year)

分列之後,是一個與原始向量等長的列表,每個列表對象是長度為2的向量。sapply函數在這裡起到批量提取列表中單個對象第n個子對象的作用,因為strsplit函數按照「;」作為分隔符分列,這裡「[[」其實是一個函數,詳細用法參考?sapply文檔說明。

如何使用管道操作符優雅的書寫R語言代碼

列表是R裡面最為自由、最為包容和靈活的數據對象,是R與外部非結構化數據通訊的唯一窗口,所以熟悉列表操作,是進階R語言的必經階段。

這裡預覽一下兩個表格信息:

word<-"EgyAbusir,<U+00A0>Egypt30°50′30″N 29°39′50″E<U+FEFF> / <U+FEFF>30.84167°N 29.66389°E<U+FEFF> / 30.84167; 29.66389<U+FEFF> (Abu Mena)"

針對上文中一處較長的正則表達式,我覺得這裡有必要解析一下,我提取了原始字元串,這個字元串中末尾有一個「;」分割的兩個浮點數值分別代表維度和經度,而且每一個文化遺產該項都是如此,也就是說符合模式匹配的需求,仔細觀察最後的那兩個數值間的模式。

左側是維度,右側是經度,維度取值範圍-90~90,經度取值範圍-180~180,小數點後保留的位數不確定,但是都大於1位數,經緯度之間間隔了分號和一個空格。

那麼正則就應該寫成 「-」(可能有可能沒有)+1~2位數字+「.」+至少一位數字+「;」+空格+負號(可能有可能沒有)+1~3位數字+「.」+至少一位數字。

使用正則表達式寫出之後即為:

」-?d{1,2}.d{1,}; -?d{1,3}.d{1,}」

其中-?代表「-」可能存在可能不存在(?是一個限定符,限定左側對象出現0次或者1次),\.對「.」進行轉義,因為「.」是一個具有特殊意義的元字元,可以指代任何一個對象。

str_extract(word,"-?\d{1,2}\.\d{1,}; -?\d{1,3}\.\d{1,}")[1] "30.84167; 29.66389"

完美的匹配出來了,之後再做一次分列,然後分別提取經緯度就OK了。

原數書作者也是通過正則匹配的經緯度信息,不過使用的預留關鍵詞,而是分了較多步驟,使用正則表達式做字元串清洗的過程就是這樣,有無數種方式任你選擇,只要達到目的即可,在目標達到的情況下,適當的選擇自己熟悉並高效的方式。

可視化:

兩個表格剛好有經緯度信息,還有遺產類別信息,可以藉助這些信息進行可視化呈現,原書中使用maps包做的地圖,我個人用慣了ggplot2,所以直接套用了老代碼。

library("RColorBrewer")library("ggthemes")library("maps")library("ggplot2")world_map<-map_data("world") #從maps包中提取世界地圖。

當前瀕危遺產分布:

ggplot()+ geom_polygon(data=world_map,aes(x=long,y=lat,group=group),col="grey60",fill="white",size=.2,alpha=.4)+geom_point(data=heritage_Current,aes(x=long,y=lat,shape=Criteria,fill=Criteria),size=3,colour="white")+ scale_shape_manual(values=c(21,22))+ scale_fill_wsj()+ labs(title="世界瀕危文化遺產分布圖(當前)",caption="數據來源:維基百科")+ theme_void(base_size=15) %+replace% theme( plot.title=element_text(size=25,hjust=0), plot.caption=element_text(hjust=0), legend.position = c(0.05,0.55), plot.margin = unit(c(1,0,1,0), "cm") )

先前瀕危遺產(後期經過保護又被從瀕危遺產中除名了)。

ggplot()+ geom_polygon(data=world_map,aes(x=long,y=lat,group=group),col="grey60",fill="white",size=.2,alpha=.4)+geom_point(data=heritage_Previous,aes(x=long,y=lat,shape=Criteria,fill=Criteria),size=3,colour="white")+ scale_shape_manual(values=c(21,22))+ scale_fill_wsj()+ labs(title="世界瀕危文化遺產分布圖(先前)",caption="數據來源:維基百科")+ theme_void(base_size=15) %+replace% theme( plot.title=element_text(size=25,hjust=0), plot.caption=element_text(hjust=0), legend.position = c(0.05,0.55), plot.margin = unit(c(1,0,1,0), "cm") )

奇怪哦!怎麼沒有大天朝,難到我們的遺產全部都不瀕危了,記得上次做的中國世界文化遺產分布圖,有將近52除自然文化遺產,肯定維基百科給搞漏了。

shiny動態儀錶盤應用——中國世界自然文化遺產可視化案例

其他爬蟲相關文章:

R語言版:

用R語言抓取網頁圖片——從此高效存圖告別手工時代

經歷過絕望之後,選擇去知乎爬了幾張圖~

一言不合就爬蟲系列之——爬取小姐姐的秒拍MV

教你如何優雅的用R語言調用有道翻譯

2017年的第一周,你吸了多少霧霾?

用數據來聊聊國產電影~

當大家都在討論金剛狼3的時候,他們到底在說些什麼~

一篇文章揭開office配色模板的的神秘面紗~

你知道經管類的核心期刊都分布在那裡嗎?

這是一篇很務正業的可視化推送~(上篇)

下篇(續)

大連市2016年空氣質量數據可視化~

北京歷史空氣質量數據可視化~

挑戰不可能之——ggplot環形字體地圖

用emoji表情包來可視化北京市歷史天氣狀況!

實習僧招聘網爬蟲數據可視化

R+Python

同時用R語言和Python爬取知乎美圖

網易雲課堂Excel課程爬蟲思路

R語言爬蟲實戰——網易雲課堂數據分析課程板塊數據爬取

在線課程請點擊文末原文鏈接:

Hellobi Live | 9月12日 R語言可視化在商務場景中的應用

往期案例數據請移步本人GitHub:

github.com/ljtyduyu/Dat


推薦閱讀:

多層數據巧鑽取,業務盲點無處可躲~
珍藏,最全面+最完善的Excel條件格式使用手冊
世紀佳緣用戶畫像-Part1
leaflet在線地圖——常用熱力地圖
pyecharts 又更新啦!繪圖速度更快啦!

TAG:R编程语言 | 数据清洗 | 数据可视化 |