还在等外卖?python告诉你,为什么你的外卖这么慢

 

某天中午,⼩编喜滋滋地点了⼀份⽜⾁饭外卖,然后翘⾸以盼等待配送⼩哥的到来。半个多⼩时过去了,软件上的地图显⽰⼩哥离我只有三百⽶的距离,⽜⾁饭已经近在咫尺。然⽽左等右等⽜⾁饭也没有到,再打开app⼀看,简直两眼发⿊:⼩哥的距离竟然从三百⽶变成了 ⼀千⽶!

相信⼤家都曾遇到过这样的问题:外卖点的各种美⾷,或者跑腿购买的东西,还有淘宝的包裹,明明页⾯显⽰它们已经近在咫尺甚⾄只有⼏分钟的路程,结果配送⼩哥⾮要绕远去别的地⽅,

在家翘⾸以盼包裹到来的你等到花⼉都快谢了,让你⽆语凝咽:软件上的路线规划完全是⼈⼯智障!然⽽,好奇⼼旺盛的⼩编陷⼊了沉思,为何这路线规划显得如此智障呢,莫⾮这⾥⾯隐藏着某些不 为⼈知的秘密?这究竟是⼈性的缺失还是算法的沦丧?

刚好,天池最后⼀公⾥配送问题⼤赛提供了配送机制以及这个问题需要的数据,让我们来⼀探究竟。

 

 

-配送机制-

 

我们来看看淘宝的配送机制:

·配送⼈员从⽹点将包裹配送到客户⼿上 

·每个配送员最多只能携带140个包裹 

·送完所有的包裹回到⽹点 

·配送点与⽹点的从属关系固定

 

-数据介绍-

 

⽼样⼦,使⽤pandas读取并观察数据:

import pandas as pd
tp1=pd.read_csv(r"F:\data\tianchi\peisong\peisongshuju\1.csv",sep=",")
tp2=pd.read_csv(r"F:\data\tianchi\peisong\peisongshuju\2.csv",sep=",")
tp3=pd.read_csv(r"F:\data\tianchi\peisong\peisongshuju\4.csv",sep=",")
tp1.head()# 点ID以及对应的经度和纬度

tp2.head()#配送点ID以及对应的经度和纬度

tp3.head()#订单ID,配送点ID,点ID以及需要送配送点的电商包裹量
我们来看单个⽹点的路线规划,先将A117⽹点数据整合在⼀张表⾥:
#整合A117点的整合A117点数据
tp1=tp1.set_index('Site_id')
a="A117"
a1=tp3[tp3.Site_id=="A117"]
a1=pd.merge(a1,tp2) #获取对应配送点的坐标
a1.Lng=a1.Lng-tp1.loc["A117"]["Lng"]
a1.Lat=a1.Lat-tp1.loc["A117"]["Lat"]
#以网点为原点,只看配送点与点之间的相对坐标
a1.head()

观察配送点与⽹点的位置关系:
import pylab
pylab.plot([0],[0],"o")
pylab.plot(a1.Lat.values,a1.Lng.values,"o")
如图所⽰,蓝⾊的点是⽹点A117的位置,黄⾊的点是配送点的位置,配送⼩哥从蓝⾊点出发,把包裹送到黄⾊点,每次携带的包裹不⼤于140个。当携带的包裹配送完后,配送⼩哥需要再次返回到 ⽹点取包裹。路线规划所考虑的问题是:怎么⾛才能使配送⼩哥⾛的路程最短呢?为了简化起见,我们将经纬度下的曲线距离⽤直线距离来代替。

 

路线规划⼀:基于点的⾓度顺序配送

物流配送路径优化问题是⼀个很经典的问题,针对该问题有很多的解决⽅法。基于点的⾓度顺序配 送是⼀个⽐较简单且运⾏良好的算法。

如上图所⽰,P0为起始点,其它点为配送需求点。

1. 采⽤极坐标来表⽰各点的相对位置,然后以P0点为坐标原点,以P1为起始点,定其⾓度为零 度,以顺时钟或逆时钟⽅向开始扫描各个点,获得各点与原点连线P0Pn相对于P0P1的⾓度⼤ ⼩。

2. 根据⾓度⼤⼩确定其顺序,直⾄扫描完毕。 

3. 扫描结束后获得的点的序列就是各点的配送顺序。 

了解了算法原理,我们来试验⼀下,A117这个⽹点的配送顺序是如何的。

 

下⾯,就开始路线规划啦:

a1=pd.concat([a1,a1.Lng/a1.Lat],axis=1) #计算各个配送点的正切值 a1.rename(columns={0:"zhengqie"},inplace=True)
a1=pd.concat([a1,(a1.Lng**2+a1.Lat**2)**0.5],axis=1)#计算各个配送点与中点的距离
a1.rename(columns={0:"r"},inplace=True)
lu1=a1[a1.Lat>0].sort_values(["zhengqie"])
lu2=a1[a1.Lat<0].sort_values(["zhengqie"])
lu=pd.concat([lu1,lu2])

zz=0
x=[0]
y=[0]
ju=0
lat=0
lng=0

for i in lu.iterrows():
zz=zz+i[1]["Num"]
if zz>140:
x.append(0)
y.append(0)
pylab.plot(x,y,"-o")
ju=ju+(lat**2+lng**2)**0.5 #加回程距离
lat=0
lng=0
x=[0]
y=[0]
zz=i[1]["Num"]
ju=ju+((i[1]["Lat"]-lat)**2+(i[1]["Lng"]-lng)**2)**0.5#加 了路径长度的计算

lat=i[1]["Lat"]
lng=i[1]["Lng"]

x.append(lat)
y.append(lng)
ju=ju+((0-lat)**2+(0-lng)**2)**0.5
x.append(0)
y.append(0)
print(ju)
pylab.plot(x,y,"-o")
pylab.show()
通过这份路线规划图,就不难明⽩配送⼩哥为何会绕远了。以顺时针⽅向进⾏配送 假设你在图中1的位置, 配送⼩哥正在2的位置进⾏配送, 按照实际距离来讲,快递⼩哥离你最近,下⼀个应该⾸先为你进⾏配送,但是根据⾓度⼤⼩来规划路线,快递⼩哥却去了更远的3这个位置!

我饿着肚子痴痴地等待着我的牛肉饭,明明我是最近的,却让我白白地多等了半个小时,就因为我家地理位置的正切值比别人家的大?这路线规划一点儿也不合理!别急,我们来看看另一种路线规划方法。

 

路线规划⼆:环形扫描法

由于仅仅按照⾓度顺序分配,导致径向距离来回的浪费。因此我们把点分为不同径向长度的环,环内按照⾓度排序,减少径向⾏⾛。

def c1(a):#点与配送点的数据准
a1=tp3[tp3.Site_id==a]
a1=pd.merge(a1,tp2)
a1.Lng=a1.Lng-tp1.loc[a]["Lng"]
a1.Lat=a1.Lat-tp1.loc[a]["Lat"]
a1=pd.concat([a1,a1.Lng/a1.Lat],axis=1)
a1.rename(columns={0:"zhengqie"},inplace=True)
a1=pd.concat([a1,(a1.Lng**2+a1.Lat**2)**0.5],axis=1)
a1.rename(columns={0:"r"},inplace=True)
return a1

def c2(a1):#⻆度排序
lu1=a1[a1.Lat>0].sort_values(["zhengqie"])
lu2=a1[a1.Lat<0].sort_values(["zhengqie"])
return pd.concat([lu1,lu2])

def c3(lu):#按照最140的负荷布置路径
zz=0
x=[0]
y=[0]
ju=0
lat=0
lng=0

for i in lu.iterrows():
zz=zz+i[1]["Num"]
if zz>140:
x.append(0)
y.append(0)
pylab.plot(x,y,"-o")
ju=ju+(lat**2+lng**2)**0.5
lat=0
lng=0
x=[0]
y=[0]
zz=i[1]["Num"]
ju=ju+((i[1]["Lat"]-lat)**2+(i[1]["Lng"]-lng)**2)**0.5
lat=i[1]["Lat"]
lng=i[1]["Lng"]
x.append(lat)
y.append(lng)
ju=ju+((0-lat)**2+(0-lng)**2)**0.5
x.append(0)
y.append(0)
pylab.plot(x,y,"-o")
pylab.show()
return ju

p1=c1(a) #数据处理
r0=p1.r.mean()#配送点与 点的平均距离
h0=p1[p1.r<r0]
p2=c2(h0)
p3=c3(p2)
print(p3)

使用环形扫描法 基本的扫描法效果好了很多。配送哥少跑了很多冤枉路,但是可以看到,它仍然法完全解决你的困扰!
若为顺时针扫描,假设你在位置1,配送⼩哥正在位置2,虽然你距离他很近,但仍然,他需要先到 达更远的位置3,再到你的位置!

事实上,通过其他算法也可以得到或近似得到配送⼩哥的最短路径规划⽅案。但不论如何,配送⼩哥距离你的位置最近就⼀定会为你最先配送吗?

答案是否定的!毕竟考虑到配送⼩哥⼯作量如此之⼤,在家嗷嗷待哺的我们就稍微耐⼼⼀点吧!

想要获取更多数据科学知识干货,欢迎关注我们的公众号【DC黑板报】

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值