R 语言:百度地图迁徙大数据爬取与可视化

R 语言:百度地图迁徙大数据爬取与可视化

其实之前蛮多小伙伴跟我说过想学习百度迁徙指数的爬取和可视化,今天终于把这个教程写好啦,其实蛮简单的,就是一个 json 格式的数据处理和 geom_curve() 图层的使用,下面我们来一步步学习如何爬取这个数据和绘制迁徙图吧!

视频讲解(预览版)

准备工作

  1. 我们要爬取的目标网站是:https://qianxi.baidu.com/2020/
  2. 绘制地图需要市级地图 + 省级地图数据,我已经准备好放置在附件中了;
  3. 高德地图接口。高德地图接口的申请我之前在很多课程中提到了;

加载相关的 R 包

1
2
3
4
library(jsonlite)
library(tidyverse)
library(hrbrthemes)
library(ggplot2)

jsonlite 是一个非常方便的处理 json 格式的数据的包。

北京市迁入数据爬取

首先我们爬取北京市的迁入数据作为演示,通过简单的网页分析我们就会发现北京市的迁入数据在这里:

1
https://huiyan.baidu.com/migration/cityrank.jsonp?dt=province&id=110000&type=move_in&date=20200315&callback=

不过这个链接得到的结果是个外面有个括号的,但是这个非常容易处理,我们只需要把得到的结果作为字符读入然后去除括号再使用 fromJSON() 函数解析即可:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这样我们就得到了这一百组数据,为了在地图上绘制出,我们需要知道这些城市的经纬度,使用高德地图提供的地理编码接口即可,我先编写了一个输入中文地址输出经纬度的函数:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

需要注意这个函数的默认参数 key = Sys.getenv("amap.key"),这里你需要预先将你的高德地图密钥存放进环境变量中,运行 usethis::edit_r_environ() 即可创建和打开一个环境变量的存放文件,然后在里面写上 amap.key = "你的高德地图密钥" 再重启 RStudio 即可生效。

然后我们就可以使用这个函数解析经纬度了:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这样我们就得到了两个新的经纬度变量,但是经纬度是连在一起的,下面我们使用 tidyr 包中的 separate 函数将他们分开:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

下面我们读入市级和省级地图数据,为了提升绘图的速度,我使用 st_simplify(dTolerance = 2000) 函数把地图简化了下:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

需要注意的是我们的地图数据是经过投影的,准确来说是这个投影下的:+proj=lcc +lat_1=30 +lat_2=62 +lat_0=0 +lon_0=105 +x_0=0 +y_0=0 +ellps=krass +units=m +no_defs,所以我们得到的经纬度数据如果直接采用 geom_curve 图层绘制的话是无法和地图数据契合的,所以我们需要进行转换,方法就是先把经纬度合成 geometry 变量使用 st_transform() 转到这个兰勃特等角投影(lcc)下,再使用 st_coordinates() 将 geometry 退化成 XY 坐标:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

另外一方面 topos 也是如此:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

使用 bind_cols 函数可以合并 fromdf 和 todf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bind_cols(fromdf, todf) %>% 
select(from, to, value, everything()) -> df

df
#> # A tibble: 100 x 7
#> from to value fromlon fromlat tolon tolat
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 河北省廊坊市 北京市 22.4 969188. 4819033. 940746. 4854591.
#> 2 河北省保定市 北京市 8.21 878200. 4733944. 940746. 4854591.
#> 3 天津市天津市 北京市 5.2 1019308. 4777314. 940746. 4854591.
#> 4 河北省张家口市 北京市 3.88 803706. 4935634. 940746. 4854591.
#> 5 河北省承德市 北京市 3.47 1049361. 4985668. 940746. 4854591.
#> 6 河北省邯郸市 北京市 3 830301. 4483138. 940746. 4854591.
#> 7 河北省石家庄市 北京市 1.98 809718. 4634842. 940746. 4854591.
#> 8 河北省唐山市 北京市 1.96 1090554. 4848506. 940746. 4854591.
#> 9 河北省沧州市 北京市 1.79 1001894. 4689654. 940746. 4854591.
#> 10 河北省衡水市 北京市 1.47 911897. 4615032. 940746. 4854591.
#> # … with 90 more rows

然后我们就可以画图了!

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

同样的方法我们还可以爬取北京迁出的数据:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

然后就可以合并绘制迁入迁出的数据了:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

绘制所有城市的迁入迁出网络

其实如果能够绘制一个城市的,绘制所有城市的只是一个循环的问题。首先编写一个函数用于获取某个城市的迁入迁出数据框:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这个函数里面我用了一个 try 函数,这样可以提供函数的错误兼容性。下面选择我们想要获取的城市列表:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

下面我们就可以使用一个循环获取这些城市的数据并且拼成一个数据框:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

我把得到的数据存储在了 qianxidf.csv 文件中,这样大家如果觉得上面的程序耗时过久可以直接使用我保存的这个数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
read_csv("qianxidf.csv") -> qianxidf

qianxidf
#> # A tibble: 63,846 x 4
#> from value to group
#> <chr> <dbl> <chr> <chr>
#> 1 河北省廊坊市 22.4 北京市 move_in
#> 2 河北省保定市 8.21 北京市 move_in
#> 3 天津市天津市 5.2 北京市 move_in
#> 4 河北省张家口市 3.88 北京市 move_in
#> 5 河北省承德市 3.47 北京市 move_in
#> 6 河北省邯郸市 3 北京市 move_in
#> 7 河北省石家庄市 1.98 北京市 move_in
#> 8 河北省唐山市 1.96 北京市 move_in
#> 9 河北省沧州市 1.79 北京市 move_in
#> 10 河北省衡水市 1.47 北京市 move_in
#> # … with 63,836 more rows

下面我们还是要获取这些城市的经纬度:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这样我们就可以绘制这幅超级炫酷的迁徙网络了:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

不过大家应该会注意到我其实全程都没有使用那个 value 数据,主要是绘制如此密集的网络图,只能选择极细的线条,所以没法再使用线条的粗细表示 value 的大小了。

知识星球附件链接:https://t.zsxq.com/3BAiAyR

#

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×