title: "R Notebook"
author: "Harry Zhu"html
天池最後一千米算法
library(readr) library(plyr) library(dplyr) Site = readr::read_csv("1.csv") %>% mutate(type = "Site") %>% rename(c("Site_id"='ID')) Spot = readr::read_csv("2.csv") %>% mutate(type = "Spot") %>% rename(c("Spot_id" = "ID")) Shop = readr::read_csv("3.csv") %>% mutate(type = "Shop") %>% rename(c("Shop_id" = "ID")) library(tidyr) Geo = rbind(Site,Shop,Spot) E_Order = readr::read_csv("4.csv") O2O_Order = readr::read_csv("5.csv") Courier = readr::read_csv("6.csv") #plot(Site$Lng,Site$Lat) plot(Geo$Lng,Geo$Lat) library(ggplot2) ggplot(data=Geo, aes(x=Lng, y=Lat,color=type))+geom_point(0.1)
# O2O訂單時間統計與分佈 O2O_ts = O2O_Order %>% tidyr::extract(col = Pickup_time,"Pickup_hour") %>% tidyr::extract(col = Delivery_time,"Delivery_hour") # 這裏能夠看到11-13點和17-18點是一個O2O下單高峯時段 plot(table(O2O_ts$Pickup_hour))
# 而配送時間則稍有滯後,在15-點到18點爲低谷期 plot(table(O2O_ts$Delivery_hour))
total_Order = rbind(E_Order,O2O_Order) total_Spot_rank = total_Order %>% group_by(Spot_id) %>% summarise(Order_num = sum(Num)) %>% arrange(Order_num) # 觀察訂單合併分佈狀況 # 配送點的總訂單狀況 plot(table(total_Spot_rank$Order_num)) # 咱們觀察到,絕大多數配送點(9202)都是符合合單配送的,只有12單是不知足合單配送,須要單獨配送。
# 在早上8點-10點集中配送電商訂單,快遞員在11-13點集中配送O2O訂單,在14-17點混合配送電商和O2O訂單,17-19點集中配送O2O訂單,19點-20點混合配送電商和O2O訂單
時間段 | 包裹類型 | 持續時長 | 解決順序 |
---|---|---|---|
8-11點 | 電商 | 2小時 | 5 |
11-13點 | O2O | 2小時 | 1 |
13-17點 | 混合 | 4小時 | 4 |
17-19點 | O2O | 2小時 | 2 |
19-20點 | 混合 | 1小時 | 3 |
在實際商業場景中,O2O配送是賺錢的,並且客單價不低,無論是自營仍是加盟,上海O2O一次配送能夠有6-10元左右的提成。而電商配送須要區分是自營仍是加盟,若是是加盟配送在送件上是不賺錢的,在取件上才賺錢。因此,電商快遞員們其實天天都是很是辛苦的,上午須要集中取件配送,下午通常是集中收件,到是O2O配送在非高峯時段能夠解放出配送的生產力。spa
O2O實際的配送狀況是,對於加盟配送員(默認3千米範圍內)在找到取餐地點可能就會花費10分鐘,在中間行駛還會花費10分鐘,最後10分鐘還要花在找到送餐地點。因此,O2O配送對於配送員對地理狀況的瞭解有比較高的要求,熟悉地理狀況將大大縮短配送時長。設計
O2O在用餐高峯時期的時間約束是很是緊急的,對於送餐員是分秒必爭,這一點和電商配送是有顯著差異的,因此咱們在算法設計上能夠從這個邊界條件入手(OR的基本原理:最優解老是發生在邊界條件上)。3d
O2O_Pickup_time = ldply(strsplit(O2O_Order$Pickup_time, ":"), rbind) %>% plyr::rename(c("1"='P_hour',"2"="P_minute")) O2O_Delivery_time = ldply(strsplit(O2O_Order$Delivery_time, ":"), rbind) %>% plyr::rename(c("1"='D_hour',"2"="D_minute")) O2O_Order_ts <- O2O_Order %>% cbind(O2O_Pickup_time,O2O_Delivery_time) %>% select(-Pickup_time,-Delivery_time) %>% tbl_df() # 首先篩選出高峯訂單 rush_Order_1 <- O2O_Order_ts %>% dplyr::filter(P_hour == c(11,12)) library(DT) DT::datatable(rush_Order_1 %>% arrange(Spot_id,Source_id))
# 咱們觀察到有一些配送點會從多家店鋪分時下單(腦補一個公司你們各自訂餐的場景) # 有的場景是一個店家向多個配送點配送。 # 這樣就有了一取多送和多取一送的兩個基本問題。
# 根據題目寫了一個距離計算公式 distLastMile <- function(lat1,lat2,lng1,lng2){ # parameter type check if(class(lat1) != "numeric" ||class(lat2) != "numeric" ||class(lng1) != "numeric" ||class(lng2) != "numeric" ){ stop("parameter must be numeric") } # reference https://img.alicdn.com/tps/TB1CiDVKXXXXXcpXFXXXXXXXXXX-866-255.png diff_lat = (lat1 - lat2)/2 diff_lng = (lng1 - lng2)/2 radius = 6378137 temp = (sin((pi * diff_lat )/180))^2 + cos((pi * lat1)/180) * cos((pi * lat2)/180)*(sin((pi * diff_lng )/180))^2 result = 2 * radius * asin (sqrt(temp)) return(result) } # 以題中給定15km/h的移動速度,估算 # > Geo[Geo$ID=="S062",] # # A tibble: 1 x 4 # ID Lng Lat type # <chr> <dbl> <dbl> <chr> # 1 S062 121.217 31.04957 Shop # > Geo[Geo$ID=="B1958",] # # A tibble: 1 x 4 # ID Lng Lat type # <chr> <dbl> <dbl> <chr> # 1 B1958 121.217 31.04973 Spot # distance = distLastMile(lat1=31.04973,lat2=31.04957,lng1=121.217,lng2=121.217) # [1] 17.81112 # distance * 4 # [1] 71.24448
這裏計算出來的結果是至少71分鐘左右的配送時長,17km左右的配送距離。因爲不太肯定O2O的具體業務,因此說不敢對這個配送時長的合理性作判斷。code
rush_info_1[rush_info_1$Order_id == "E0036",] # A tibble: 1 x 11 # Order_id Spot_id Source_id Num P_hour P_minute D_hour D_minute Lng Lat type # <chr> <chr> <chr> <int> <fctr> <fctr> <fctr> <fctr> <dbl> <dbl> <chr> #1 E0036 B1958 S062 3 12 14 13 44 121.217 31.04973 Spot # 配送時長最長可爲 90分鐘,看來就是怎麼利用之間的 20分鐘的時間來增長配送量。
接下來,咱們繼續分解任務,將O2O配送分爲三種類型cdn
一對多:同一家店鋪取,順序配送到多個目的地(旺鋪型)htm
多對一:多家店鋪順序取件,一次配送到目的地(大客戶型)blog
其餘ip
# 一對多的情形 # reference https://www.youtube.com/watch?v=A1wsIFDKqBk