<div class="article fmt article__content">
<h2>前言</h2>
<p>最近公司组织了一场大咖秀,有位讲师建议我们没事多参加阿里的天池大赛,说是对提高自己很有帮助。于是想起自己几天前看到的FinanceR专栏的<a href="https://segmentfault.com/a/1190000006036420">天池最后一公里</a>,便紧随偶像步伐,注册并下载了一份数据,凑个热闹。详情请点击<a href="https://tianchi.shuju.aliyun.com/competition/information.htm?spm=5176.100067.5678.2.mJKvo4&raceId=231581">赛题介绍</a></p>
<p>此文为截图版,需要js交互版的原文请点击<a href="http://danzhuibing.github.io/R_tianchi_logistics.html">这里</a></p>
<h2>简单分析</h2>
<p>数据有三种类型的节点。第一类是Site,电商订单发货节点。第二类是Shop,O2O订单发货节点。第三类是Spot,消费者收获节点。电商订单的要求比较松,只需在当天晚上8点前配送完毕即可。O2O订单比较着急,必须在指定的时刻前去Shop取货,并在指定的时刻去Spot送货。</p>
<p>首先,我们将电商订单的情况打到地图上看一下。</p>
<pre class="blockcode"><code>library(readr)
library(plyr)
library(dplyr)
library(tidyr)
library(ggplot2)
library(plotly)
library(lubridate)
library(leaflet)
library(sp)
library(RColorBrewer)
library(jsonlite)
library(splitstackshape)
library(stringr)
library(rlist)
# 辅助函数
points2spline <- function(df, x_field, y_field, id_field){
data <- as.matrix(df[,c(x_field, y_field)])
id = df[1, id_field]
Lines(list(Line(data)), ID=id)
}
# 探索Site与Spot的空间关系
df.site <- read_csv("1.csv")
df.spot <- read_csv("2.csv")
df.e.order <- read_csv("4.csv")
df.site.spot <- df.e.order %>%
inner_join(df.site, by=c("Site_id")) %>%
inner_join(df.spot, by=c("Spot_id")) %>%
unite(Point_x, ends_with("x")) %>%
unite(Point_y, ends_with("y")) %>%
gather(point, location, Point_x, Point_y) %>%
separate(location, c("Lng", "Lat"), sep="_", convert=TRUE) %>%
unite(Line_id, Site_id, Spot_id, remove=FALSE)
df.site <- df.site %>%
inner_join(df.site.spot %>%
group_by(Site_id) %>%
dplyr::summarise(order_cnt=sum(Num)),
by=c("Site_id"))
ls.site.spot <- split(df.site.spot, df.site.spot[, c("Line_id")])
names(ls.site.spot) <- NULL
sl.site.spot <- SpatialLines(llply(ls.site.spot, points2spline, "Lng", "Lat", "Line_id"))
m <- leaflet() %>%
addTiles(
'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
tileOptions(tileSize=256, minZoom=9, maxZoom=17)
) %>%
addPolylines(data=sl.site.spot, weight=2, color="#377EB8") %>%
addCircleMarkers(lng=~Lng, lat=~Lat, radius=~order_cnt/1000, data=df.site, stroke=FALSE, fill=TRUE, fillColor="#E41A1C", fillOpacity=0.5, popup=~paste0("Order Num: ", order_cnt)) %>%
fitBounds(sl.site.spot@bbox["x", "min"],sl.site.spot@bbox["y", "min"], sl.site.spot@bbox["x", "max"], sl.site.spot@bbox["y", "max"])
m</code></pre>
<p><span class="img-wrap"><img alt="clipboard.png" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-51644129b90f5f65e7528b8d70e528c9" title="clipboard.png"></span></p>
<p>图中红色的圆圈就是每个Site,半径越长表明出货量越大。蓝色的线表示这个Site与它负责的电商订单的Spot的连线。可以看出Site和Spot之间是一一对应的关系,不存在交叉,所以如果只考虑电商订单,这就是一个比较简单的VRP问题,可以分而治之,每个Site单独规划。</p>
<p>但是呢,我们还有一堆O2O订单要一起配送,这就让问题的复杂度骤然提升了难度。我们先来看一下O2O订单的空间分布。</p>
<pre class="blockcode"><code>df.shop <- read_csv("3.csv")
df.o2o.order <- read_csv("5.csv")
df.shop.spot <- df.o2o.order %>%
inner_join(df.shop, by=c("Shop_id")) %>%
inner_join(df.spot, by=c("Spot_id")) %>%
unite(Point_x, ends_with("x")) %>%
unite(Point_y, ends_with("y")) %>%
gather(point, location, Point_x, Point_y) %>%
separate(location, c("Lng", "Lat"), sep="_", convert=TRUE) %>%
unite(Line_id, Shop_id, Spot_id, remove=FALSE)
ls.shop.spot <- split(df.shop.spot, df.shop.spot[, c("Line_id")])
names(ls.shop.spot) <- NULL
sl.shop.spot <- SpatialLines(llply(ls.shop.spot, points2spline, "Lng", "Lat", "Line_id"))
df.shop <- df.shop %>%
inner_join(df.shop.spot %>%
group_by(Shop_id) %>%
dplyr::summarise(order_cnt=sum(Num)),
by=c("Shop_id"))
m <- leaflet() %>%
addTiles(
'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}& |
|