任务3:共享单车潮汐点优化


## 学习目标

  • 对停车点进行状态(潮汐情况)划分;
  • 对停车点进行距离计算,并进行分类;
  • 通过主动引导停车用户到邻近停车点位停车,


## 街道潮汐状态统计

根据上一章节的街道潮汐统计,我们可以统计得出每个街道的具体潮汐情况,并进而可以按照密度计算得到潮汐情况最为严重的区域。为了对厦门市潮汐情况与区域关系进行可视化,来对具体的潮汐情况进行直观的感受。

首先我们按照之前的代码完成具体数据读取,并对单车订单数据的时间进行提取:

bike_order['UPDATE_TIME'] = pd.to_datetime(bike_order['UPDATE_TIME'])
bike_order['DAY'] = bike_order['UPDATE_TIME'].dt.day.astype(object)
bike_order['DAY'] = bike_order['DAY'].apply(str)

bike_order['HOUR'] = bike_order['UPDATE_TIME'].dt.hour.astype(object)
bike_order['HOUR'] = bike_order['HOUR'].apply(str)
bike_order['HOUR'] = bike_order['HOUR'].str.pad(width=2,side='left',fillchar='0')

bike_order['DAY_HOUR'] = bike_order['DAY'] + bike_order['HOUR']

为了方便统计这里,我们只使用一个时间的订单数据进行绘制:

import folium
from folium import plugins
from folium.plugins import HeatMap

map_hooray = folium.Map(location=[24.482426, 118.157606], zoom_start=14)
HeatMap(bike_order.loc[(bike_order['DAY_HOUR'] == '2106') & (bike_order['LOCK_STATUS'] == 1), 
                   ['LATITUDE', 'LONGITUDE']]).add_to(map_hooray)

for data in bike_fence['FENCE_LOC'].values[::10]:
    folium.Marker(
        data[0, ::-1]
    ).add_to(map_hooray)

map_hooray

如上图,我们可以看到颜色表示为具体停车位置的热度,具体点为订车点的位置。

  • 并不是所有的车都听到了停车点,有一些车听到了距离停车点较远的距离;
  • 有一些停车点有潮汐现象,有的不存在潮汐现象;

## 其他停车点推荐

根据上一章节的街道潮汐统计,我们可以得到每个停车点具体的潮汐情况。如果此停车点停满了,进一步我们也可以推荐其他停车点。

我们使用下面的代码完成具体的停车点潮汐统计:

import geohash
bike_order['geohash'] = bike_order.apply(lambda x: 
                        geohash.encode(x['LATITUDE'], x['LONGITUDE'], precision=9), axis=1)

from geopy.distance import geodesic

bike_fence['MIN_LATITUDE'] = bike_fence['FENCE_LOC'].apply(lambda x: np.min(x[:, 1]))
bike_fence['MAX_LATITUDE'] = bike_fence['FENCE_LOC'].apply(lambda x: np.max(x[:, 1]))

bike_fence['MIN_LONGITUDE'] = bike_fence['FENCE_LOC'].apply(lambda x: np.min(x[:, 0]))
bike_fence['MAX_LONGITUDE'] = bike_fence['FENCE_LOC'].apply(lambda x: np.max(x[:, 0]))

bike_fence['FENCE_AREA'] = bike_fence.apply(lambda x: geodesic(
    (x['MIN_LATITUDE'], x['MIN_LONGITUDE']), (x['MAX_LATITUDE'], x['MAX_LONGITUDE'])
).meters, axis=1)

bike_fence['FENCE_CENTER'] = bike_fence['FENCE_LOC'].apply(
    lambda x: np.mean(x[:-1, ::-1], 0)
)

import geohash
bike_order['geohash'] = bike_order.apply(
    lambda x: geohash.encode(x['LATITUDE'], x['LONGITUDE'], precision=7), 
axis=1)

bike_fence['geohash'] = bike_fence['FENCE_CENTER'].apply(
    lambda x: geohash.encode(x[0], x[1], precision=7)
)

bike_inflow = pd.pivot_table(bike_order[bike_order['LOCK_STATUS'] == 1], 
                   values='LOCK_STATUS', index=['geohash'],
                    columns=['DAY'], aggfunc='count', fill_value=0
)

bike_outflow = pd.pivot_table(bike_order[bike_order['LOCK_STATUS'] == 0], 
                   values='LOCK_STATUS', index=['geohash'],
                    columns=['DAY'], aggfunc='count', fill_value=0
)

bike_remain = (bike_inflow - bike_outflow).fillna(0)
bike_remain[bike_remain < 0] = 0  
bike_remain = bike_remain.sum(1)
bike_fence['DENSITY'] = bike_fence['geohash'].map(bike_remain).fillna(0)

如果乘客到了一个潮汐停车点A,如何对乘客进行引导呢?

  1. 推荐的停车点B应该和A距离不远;
  2. 推荐的停车点B应该没有潮汐情况;
  3. 也需要考虑到跨街道和横穿马路的情况;

首先为了完成停车点距离计算,还是先定义好KNN:

from sklearn.neighbors import NearestNeighbors

knn = NearestNeighbors(metric = "haversine", n_jobs=-1, algorithm='brute')
knn.fit(np.stack(bike_fence['FENCE_CENTER'].values))

然后是具体的计算逻辑进行编码:

def fence_recommend1(fence_id):
    fence_center = bike_fence.loc[bike_fence['FENCE_ID']==fence_id, 'FENCE_CENTER'].values[0]
    # 具体街道方向
    fence_dir = fence_id.split('_')[1]
    # 根据距离计算最近的20个待选位置
    dist, index = knn.kneighbors([fence_center], n_neighbors=20)

    # 对每个待选位置进行筛选
    for idx in index[0]:
        # 剔除已经有很多车的
        if bike_fence.iloc[idx]['DENSITY'] > 10:
            continue
        # 剔除需要过街的
        if fence_dir not in bike_fence.iloc[idx]['FENCE_ID']:
            continue
        return bike_fence.iloc[idx]['FENCE_ID']

    return None

## 停车引导计划

此外还需要考虑到单车没有起到停车点的情况,即推荐根据经纬度推荐最近非潮汐停车点:

def fence_recommend2(la, lo):
    dist, index = knn.kneighbors([[la, lo]], n_neighbors=20)
    for idx in index[0][1:]:
        if bike_fence.iloc[idx]['DENSITY'] > 10:
            continue
        return bike_fence.iloc[idx]['FENCE_ID']

    return None

综上所述我们可以将潮汐引导计划描述如下,分为两种情况:

graph LR A(潮汐停车) -->B(已到停车点) A -->C(未到停车点) C -->D(距离计算) D -->E(推荐近邻非潮汐停车点) B -->H(距离计算) H -->G(推荐近邻非潮汐停车点)

## 改进方向

  1. 近邻非潮汐停车点需要综合推荐,不能总是推荐一个,否则会导致出现新的潮汐点;
  2. 近邻非潮汐停车点推荐需要考虑到交通情况,如街道信息、具体位置信息;
  3. 近邻非潮汐停车点推荐需要全局调度,也可以具体分析周中和周五两种情况;

## 报告撰写建议

  1. 建议考察下现有单车的停车建议,并进行对比分析;
  2. 可以选择一个潮汐点,进行具体分析并给出具体建议,并对比优化前后对比;
  3. 数据使用+技术架构,可以先设计demo,撰写好文档;


© 2019-2023 coggle.club 版权所有     京ICP备20022947    京公网安备 11030102010643号