2021年认证杯SPSSPRO杯数学建模
C题 破局共享汽车
原题再现:
自 2015 年以来,共享汽车行业曾经“百花齐放”,多个项目获得巨额融资。但因为模式过重、运营成本过高、无法盈利等问题,陆续有共享汽车公司因为资金链断裂而倒闭。据易观发布的《2019 中国共享汽车平台创新白皮书》显示,2019 年的共享汽车行业,是中小参与者不断出局,头部平台拉动行业重启增长的一年。而共享汽车增速在 2019 年 5–10 月达到 2.21%,超过网约车和线上租车。
在以前,汽车被当作“大件”购买。而现在,由于车型更新迭代之快让人眼花缭乱,加之受疫情影响,消费者的决策过程会变得更长。消费者有用车的欲望、有消费升级的欲望,但他们越来越聪明了,他们想知道,有没有更轻更好的用车方式。共享汽车的“分时租赁”模式很多的解决了这个问题。但是这种方式的成本控制环节过多,导致盈利非常困难。
第一阶段问题: 附件是共享汽车的位置数据集,数据集中提供了时间,经纬度等位置信息,以及停车点上停放的车辆的数量和车辆列表。请建立数学模型分析该城市的共享汽车使用分布情况,并且制定一个对企业最有利的共享汽车调度方案。
整体求解过程概述(摘要)
如今,在汽车款式更迭速度的迅猛增长与疫情对消费者决策的影响等客观因素,与人们生活水平日益提高导致的用车需求增长与欲望增强等主观因素作用下,“共享汽车”因其特殊的“分时租赁”优势,以更低的成本满足更多人群的用车需求,超越买车租车等选项成为人们心中的首选。但是,在“共享汽车”市场环境稳中向好的同时,其本身存在的控制环节多,模式重、成本高等因素的仍导致“共享汽车”产业盈利困难,许多相关·企业最终都因资金链断裂而倒闭。基于此可以说,有利的共享汽车调度方案市决定企业命运的关键一环。本文参考附件信息,分析城市的共享汽车使用分布情况,制定了一个对企业最有利的共享汽车调度方案。
针对问题一: 我们先用 python 读取 cvs 数据,通过读取的数据,依托地图坐标系统,读取数据表中的经纬度,参考这些数据,查询到共享单车分布的具体地点在以色列特拉维夫市。
针对问题二:在问题一的基础上,我们利用 python 中的 matplotlib 模块,以经度、纬度、停车点上停放的车辆的数量为参数变量,绘制了气泡图。在这些用颜色标记的区域中,红色标记代表车辆数较多,黄色标记代表车辆数中等,蓝色标记代表车辆数较少,依托此图可以看出,车辆主要分布在两块红色的区域中。
问题分析:
根据题目所给的条件与优化调度方案减少成本的目的,再结合实际资源分配情况与客观因素的调整,方案的准确性与可行性进行数学建模。在建模过程中设立前提假设,避免其他客观因素对数学模型造成误差,导致优化方案的拟合度降低,最终导致方案的执行可能性下降。
根据附录所给的数据,对数据进行处理和可视化,先对经纬度进行处理,确定该城市大致位置,再借助相关地图软件进一步确定数据分析结果的准确区域。根据附录中提供的车辆相关数据绘制该城市的共享单车使用分布情况(从宏观和围观入手),并求解模型参数得出最终结论。
在问题一结果的基础上,结合实际情况,建立相关模型。为企业制定一个更有利的解决方案,尽可能实现企业利益的最大化,同时提高当地人民的出行效率以及共享汽车使用者对企业的满意度,根据所划分区域的范围、经纬度、车辆数目相关信息建立数学模型,最后建立规划模型即可完成调度方案的制定。
模型假设:
假设 1:表中的共享汽车的定位都是相对准确切没有较大误差。
假设 2:共享汽车之间的速度相同。
假设 3:该城市的共享汽车的数量是一定的,即不存在大规模的共享汽车输入与输出。
假设 4:该城市的共享汽车停放区域固定,不改变。
模型的建立与求解
绘制热力图
热力图是数据可视化项目中,比较常用的显示方式。通过颜色变化程度,它可以直观反应出热点分布,区域聚集等数据信息。为了使 csv 文件的数据更加直观直观,以便做后续分析,我们利用 python 中的地图可视化组件 folium 对数据进一步处理,绘制出相应的共享汽车数据热力图。
数据所属区域的确定
利用地图 api 软件定位,查询到数据所属区域位于以色列境内,紧邻地中海东南的城市特拉维夫市。
“微观”热力图的放大
从“宏观”角度进行数据分析后,为了探究更微观的分布情况,我们选择了共享汽车分布密度较高的区域进一步研究。
根据图像所展示的热力分布,其中红色区域代表共享汽车分布密度较高,黄色区域代表共享汽车分布密度相对均匀,而蓝色区域则代表共享汽车的分布密度较低。由此可以看出,共享汽车的分布呈高度集中化,且向四周密度逐渐降低。与人口流动密度呈正相关,且具有较高的拟合优度。
气泡图的绘制
大概观察宏观热点图与微观热点图之后,再加上之前的数据分析,我们决定利用python 中的 matplotlib 模块以经度,纬度,停车点上停放的数量为参数变量绘制气泡图,以此帮助后续的数学建模。
初步分析
按照附录中所给的数据,通过查找相关资料,可以知道经度和纬度每相差 0.1 度就是相差十一公里,所以可以通过经度纬度每 0.1 度偏差,就被分为一个区域,被分为多个区域之后,共享汽车只能停在不同的区域内。如果某个区域满了(也就是这 11km*11km的区域内),只能在其他区域进行停车。那么如何再最短的时间内找到最近的区域停车点,可以用 Dijkstra 最短路径算法判断该区域内距离该区域最近的停车点,然后判断是否有停车位,如果有空闲的停车位,就能停,如果没有就再次通过最短路径算法找到下一个距离最短的停车区域。
调度方案
共享汽车的两端使用者和运营商, 供需平衡是城市共享汽车供给量与需求量达到平衡的一种状态,是影响运营商盈利的一个关键性因素。根据上述所有模型的求解结果我们可以知道特拉维夫市共享汽车的使用情况如下:
1. 大部分停车点的车辆滞留率较高,但是南部地区在车辆滞留率较高的同时,车流量很小
2. 大部分地区车辆的驶入驶出率约为 1,但是南部驶入驶出率相对较高
3. 大部分地区周三车辆的驶入驶出率和车流量最低,周五车辆的驶入驶出率和车流量最高。
根据是上述分析运营商车辆调度出现了问题:运营商在南部地区和北部投放的车辆太多远远超过用户需求量,导致了资源的浪费;其次,南部地区的车辆:驶入>驶出;此外,周五是用户需求量的高峰期,周三是一个低谷。为解决上述问题我们将给出以下得调度方案:
1. 运营商应适当降低南部地区和北部车辆的投放量。
2. 定期将南部的车辆调往中北部地区,在满足用户需求的同时,降低南部地区和北部地区车辆的滞留率,避免南部车辆堆积。
3. 在周五用户需求量高峰期到来之前,运营商应该提前完成车辆调度以满足用户
的需求。
论文缩略图:
程序代码:
共享汽车热力图 python 代码
import numpy as np
import pandas as pd
import seaborn as sns
import folium
import webbrowser
from folium.plugins import HeatMap
num = 1048574
lat = np.array(df["latitude"][0:num]) # 获取维度之维度值
lon = np.array(df["longitude"][0:num]) # 获取经度值
pop = np.array(df["total_cars"][0:num],dtype=float) # 获取车数,转化为 numpy 浮点型
data1 = [[lat[i],lon[i],pop[i]] for i in range(num)] #将数据制作成[lats,lons,weights]的形
式
map_osm = folium.Map(location=[35,110],zoom_start=5) #绘制 Map,开始缩放程度是
5 倍
HeatMap(data1).add_to(map_osm) # 将热力图添加到前面建立的 map 里
file_path = r"E:\2021 认证杯 c 题\C1\共享汽车使用分布.html" map_osm.save(file_path) # 保存为 html 文件
计算最近停车点
import pandas as pd
import random
from sklearn.metrics.pairwise import euclidean_distances
import numpy as np
#读取数据
data = pd.read_csv('E:\Desktop\认证杯数学建模\共享汽车定位数据.csv')
#纬度数据
lat = list(data['latitude'])
#精度数据
long = list(data['longitude'])
#停车点数据
cars = list(data['total_cars'])
# 汽车随机点位
def getRandomCarPos():
# 随机纬度
rand_lat = random.uniform(min(lat),max(lat))
#随机精度
rand_long = random.uniform(min(long),max(long))
return rand_lat,rand_long
# Dijkstra 算法/最短路径算法
def dijkstra(graph,src):
# 判断图是否为空,如果为空直接退出
if graph is None:
return None
nodes = list(range(len(graph)))
# 获取图中所有节点
visited=[]
# 表示已经路由到最短路径的节点集合
if src in nodes:
#起始节点在节点集合中
visited.append(src)
nodes.remove(src)
else:
return None
distance={src:0}
# 记录源节点到各个节点的距离
for i in nodes:
distance[i]=graph[src][i]
# 初始化
path={src:{src:[]}}
# 记录源节点到每个节点的路径
k=pre=src
while nodes:
mid_distance=float('inf')
for v in visited:
for d in nodes:
new_distance = graph[src][v]+graph[v][d]
#记录 nodes 中的最小距离节点,即将要加入 visited 集合中的节点
if new_distance < mid_distance:
mid_distance=new_distance
graph[src][d]=new_distance
# 进行距离更新
k=d
pre=v
distance[k]=mid_distance
# 最短路径
path[src][k]=list(path[src][pre])
#[i for i in path[src][pre]]
path[src][k].append(k)
# 更新两个节点集合
visited.append(k)
nodes.remove(k)
#print(visited,nodes)
# 输出节点的添加过程
return distance,path
def dijk(graph_list,int0,int1):
distance_dict,path_dict= dijkstra(graph_list, int0)
# 查找从源点 0 开始带其他节点的最短路径
distance = distance_dict[int1]
path = path_dict[int0][int1]
path = [int0] + path
return distance,path
# 获取符合经纬度范围节点
def getFitDataLimit(rand_lat,rand_long):
#存储符合范围节点经纬度信息
data_limit = []
#范围数据选取 0.055 为 5 公里范围
for i in range(len(lat)):
if (rand_lat - 0.055) <= lat[i] <= (rand_lat + 0.055) and (rand_long - 0.055) <=
long[i] <= (rand_long + 0.055):
data_limit.append([lat[i],long[i],cars[i]])
return data_limit
# 范围内距离最小且有停车位的停车点经纬度信息
def getSim(data_limit):
# 计算范围内停车点距离汽车点的距离
distance =
[euclidean_distances(np.array([[item[0],item[1]]]),np.array([[rand_lat,rand_long]]))[0][0] for
item in data_limit]
# 存储距离最小的节点索引
min_index = []
# 计数器
count = 0
# 遍历获取距离最小索引
for item in distance:
if item == min(distance):
print(count)
min_index.append(count)
count += 1
# 停车点停车数为 0 的停车点经纬度坐标
stop = [[lat[i],long[i]] for i in min_index if cars[i] == 0]
return stop
if __name__ == '__main__':
# 模拟 3 个汽车经纬度信息
for i in range(3):
#获取经纬度信息
rand_lat,rand_long = getRandomCarPos()
print('the first car position:',rand_lat,rand_long)
#获取范围
data_limit = getFitDataLimit(rand_lat,rand_long)
#计算停车点
stop = getSim(data_limit)
print(stop)