一个小案例,教你如何从数据抓取、数据清洗到数据可视化
一篇小短文了,囊括数据抓取、数据清洗、数据呈现等全过程,数据主要展示2016年我国top100地级市GDP、增长率、及地区分布密度图三个维度信息。
library(plyr)
library(rvest)
library(stringr)
library("data.table")
library(dplyr)
随便找的一篇微信短文,复制网址链接直接在浏览器打开
readurl<-"http://mp.weixin.qq.com/s?__biz=MzI1ODM5NTQ1Mw==&mid=2247484083&idx=1&sn=ba4f4b10af3e4d6ed45f4d04edc30980&chksm=ea099ee1dd7e17f717afffdb3a3ff82c6e4e6bd351251601f0968c792b7e7cb5cdf084fb86a8&mpshare=1&scene=23&srcid=02039mlTmLqMxQEnb4CnUrK3#rd"
用rvest简单提取文本内容
web<-read_html(readurl,encoding="UTF-8")
a<-web%>%html_nodes("p")%>%html_text()
数据抓取阶段完毕,以下转入数据清洗阶段:
#------------------------------------------------------------------------------------------------------
仔细观察该文本向量可以发现,我们需要的城市数据都是以数开头(1~3位不等),其中第七行也是一数据字开头(2017年1月20日),使用正则表示进行精准匹配,并将所有标点符号(记得是中文标点)替换成逗号(英文),方便之后作为分列拆分依据(也可以自定义拆分的符号)
a<-grep("^\\d{1,3}\\D",a,value=TRUE)
a<-gsub("(\\(|\\)|\\,|\\:)",",",a)
由于四个直辖市文本行与其他城市相比,缺失一个省级标签,为使之后拆分顺利完成,需要将其修改与其他城市一致。
a[1]<-"1.上海,上海1,26688亿元,同比增长6.7%,人口,2415万,"
a[2]<-"2.北京,北京1,24541亿元,同比增长6.7%,人口,2171万,"
a[5]<-"5.天津,天津1,17800亿元,同比增长9%,人口,1547万,"
a[6]<-"6.重庆,重庆1,17010亿元,同比增长10.7%,人口,3372万,"
剔除中文冗余文字
dataA<-gsub("((亿元)|(同比增长)|(人口)|(万))","",a)
字符串拆分,使用stringr中的str_split函数进行拆分,使用plyr中的ldply函数进行数据框转化,然后对列字段重命名,重排序。
temp1<-str_split(dataA,",")
result1<-ldply(temp1,.fun=NULL)
Error in list_to_dataframe(res, attr(.data, "split_labels"), .id, id_as_factor) :
Results do not have equal lengths
以上语法出错,提示长度不等,用函数查看具体哪一行出现不等长的情况。
m<-c()
for (i in 1:length(temp1)) m[i]<-length(temp1[[i]])
grep("6",m)
[1] 35 36
查看具体情况
dataA[35:37]
[1] "35.温州,浙江3,5110,8%,919," "36.绍兴,浙江4,4800,5%,501,"
[3] "37.鄂尔多斯,内蒙古1,4678,7.3%,,201,"
原来是倒数第二个分割点少了一个逗号,重新补全,使其等长。
dataA[35]<-"35.温州,浙江3,5110,8%,,919,"
dataA[36]<-"36.绍兴,浙江4,4800,5%,,501,"
再次运行拆分函数:
temp1<-str_split(dataA,",")
result1<-ldply(temp1,.fun=NULL)
names(result1)<-c("city","province","gdp","ratio","blank1","scale","blank2")
result1<-result1[,-c(5,7)]
提取城市名称字段:
wh<-regexpr("[0-9]{1,3}",result1[,1])
order<-substring(result1[,1],wh,wh+attr(wh,"match.length")-1)
city<-substring(result1[,1],attr(wh,"match.length")+2)
nchar(city)>1
为防止提取的城市名称不全,查看下是否有少于一个字符的名称:
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[15] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[29] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[43] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[57] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[71] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[85] TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE
[99] TRUE TRUE
第92名宿迁因为少了一个句号,只提取了一个字符,立即补全(之后要使用城市名称提取经纬度,否则会失败)
city[92]<-"宿迁"
合并:
result<-data.frame(order,city,result1)
result<-result[,-3]
提取省份名称、省内排名字段
wm<-regexpr("[0-9]{1,2}",result[,3])
prov<-substring(result[,3],1,wm-1)
scope<-substring(result[,3],wm,wm+attr(wh,"match.length")-1)
替换百分号(坑爹啊,R不支持百分号显示,一律识别为文本)
result$ratio<-sub("%","",result$ratio)
result$ratio<-as.numeric(result$ratio)
result$ratio<-result$ratio/100
合并并重排序列字段
resultm<-data.frame(prov,scope,result)
resultm<-resultm[,c(3,4,1,2,6,7,8)]
查看数据框字段属性,不符号要求需要重新定义属性
str(resultm)
resultm$order<-as.numeric(resultm$order)
resultm$city<-as.character(resultm$city)
resultm$prov<-as.character(resultm$prov)
resultm$scope<-as.numeric(resultm$scope)
resultm$gdp<-as.numeric(resultm$gdp)
resultm$scale<-as.numeric(resultm$scale)
按照排名排序
resultm<-arrange(resultm,order)
resultm$order[92:100]<-92:100
至此数据清洗阶段完毕,以下转入数据呈现
#-----------------------------------------------------------------------------------------------
分布密度图:
library(ggplot2)
library(plyr)
library(maptools)
library(ggmap)
library(REmap)
china_map<-readShapePoly("c:/rstudy/bou2_4p.shp")
china_map1 <- fortify(china_map)
data<-get_geo_position(resultm$city)
data$lon<-as.numeric(data$lon)
data$lat<-as.numeric(data$lat)
ggplot()+
geom_polygon(data=china_map1,aes(x=long,y=lat,group=group),fill="white",col="grey60",size=.3)+
geom_polygon(data=data,aes(x=lon,y=lat,fill = ..level..), stat="density_2d", alpha = .3, color = NA)+
coord_map("polyconic") +
scale_fill_gradient2( low = "white",mid="yellow", high = "red")+
theme_nothing()
gdp总量分布图:
data1<-inner_join(resultm,data)
ggplot()+
geom_polygon(data=china_map1,aes(x=long,y=lat,group=group),fill="white",col="grey60",size=.3)+
coord_map("polyconic") +
geom_point(data=data1, aes(x =lon,y =lat,size=gdp), alpha=0.6,shape=21, fill="red",colour="white")+
scale_size_area(max_size=12)+
theme_nothing()
增长率分布图:
ggplot()+
geom_polygon(data=china_map1,aes(x=long,y=lat,group=group),fill="white",col="grey60",size=.3)+
geom_point(data=data1, aes(x =lon,y =lat,size=ratio,fill=ratio), alpha=0.6,shape=21, colour="white")+
scale_fill_gradient2(low="#0E4E75", mid="#BFBEBE", high="red", midpoint=median(na.omit
(data1$ratio)))+
coord_map("polyconic") +
scale_size_area(max_size=6)+
theme_nothing()
麻雀虽小,五脏俱全,数据可视化也是一样!地图素材在魔方学院QQ群贡献的rstudy文件中,其他作图数据可通过运行代码获得~
我是分割线~
欢迎关注魔方学院QQ群