该环节需要基于python的networkx库进行。实验中所用到的excel文件内容如图8所示。Python中的部分操作内容可以参考如下链接:
[4] https://zhuanlan.zhihu.com/p/164470586
图8
通过以下代码可以构建复杂网络,节点为道路端点,连边为道路。
#节点经纬度字典
dict_loc=dict(zip(df_node['节点ID'],list(zip(df_node['经度'],df_node['纬度']))))
# 创建空的交通网络
G = nx.Graph()
# 添加节点到交通网络
for index, row in df_node.iterrows():
node_id = row['节点ID']
longitude = row['经度']
latitude = row['纬度']
G.add_node(node_id, pos=(longitude, latitude))
# 添加边到交通网络
for index, row in df_edge.iterrows():
road_id = row['道路ID']
start_node = row['节点1']
end_node = row['节点2']
road_length = row['长度']
G.add_edge(start_node, end_node, road_id=road_id, length=road_length)
4**、最短路径计算**
以下代码以节点“19814”与节点“30073”为例展示了最短路径的计算方式,批量计算可以通过For循环实现。另外,由于实际计算中所需的POI(如配送中心)并不一定是道路的端点,此时可以通过一些判断准则,选取合适的道路端点代表POI(如选取距离POI最近的端点)。
# 计算最短路径
start_node = 19814
end_node = 30073
shortest_path = nx.shortest_path(G, source=start_node, target=end_node, weight='length')
shortest_distance = nx.shortest_path_length(G, source=start_node, target=end_node, weight='length')
# 打印最短路径和最短距离
print(f"最短路径: {shortest_path}")
print(f"最短距离: {shortest_distance}")
5**、蒙特卡洛模拟**
此处主要参考蒙特卡洛模拟的思想,进行多次随机实验。如存在配送中心A与100个配送点,每次配送需要运送5个配送点,需要计算最短的配送距离。所以每次模型都要从100个配送点中随机抽取5个点。假设5个配送点分别为a、b、c、d、e,前往各个配送点的配送顺序将决定整体的配送距离。以下代码展示了利用穷举法进行相关实验所构建的相关函数。
#计算节点之间的最短路径
def cal_path(start,end):
distance = nx.shortest_path_length(G, source=start, target=end, weight='length')
return distance
#蒙特卡洛模拟
def monte_carlo_sim(data,num_samples,num_sim):
list_sample=[]
for _ in range(num_sim):
sample = random.sample(data, num_samples)
sample_key = tuple(sorted(sample))
list_sample.append(sample_key)
return list_sample
#生成列表元素的全排列
def all_permutations(lst):
# 使用permutations函数生成所有排列
perm_list = list(permutations(lst))
return perm_list
#列表最小元素位置
def min_position(lst):
min_value = min(lst)
min_position = lst.index(min_value)
return min_position
#对于每条配送路径选取最优路径
#穷举法
def select_path_all(start,list_data):
#蒙特卡洛模拟每次抽取的一个送货目的地列表进行全排列
list_choose=all_permutations(list_data)
list_result=[]
for i in list_choose:
#首先计算起点到第一个点的距离
length_all=cal_path(start,i[0])
#计算剩余节点间的距离
for j in range(0,len(i)-1):
distance=cal_path(i[j],i[j+1])
length_all=length_all+distance
#返程
length_end= cal_path(i[-1],start)
length_all=length_all+length_end
list_result.append(length_all)
index=min_position(list_result)
list_out=list(list_choose[index])
list_out.insert(0,start)
list_out.append(start)
return list_out,list_result
穷举法存在计算时间较长的问题,可以结合一些智能算法进行优化求解,如遗传算法等。主要针对“select_path_all”函数代码进行改进。以下代码使用精英策略的遗传算法进行求解。
#对于每条配送路径选取最优路径
#遗传算法
def calculate_total_distance(graph, path):
total_distance = 0
#计算某条路径的总长度
for i in range(len(path) - 1):
total_distance += graph[path[i]][path[i+1]]['weight']
return total_distance
def generate_random_route(graph, start):
nodes = list(graph.nodes())
nodes.remove(start)
random.shuffle(nodes)
return [start] + nodes + [start]
def crossover(parent1, parent2):
crossover_point = random.randint(1, len(parent1) - 2)
child = parent1[:crossover_point]
for node in parent2:
if node not in child:
child.append(node)
child.append(child[0])
return child
def mutate(route):
mutation_point1 = random.randint(1, len(route) - 2)
mutation_point2 = random.randint(1, len(route) - 2)
route[mutation_point1], route[mutation_point2] = route[mutation_point2], route[mutation_point1]
def genetic_algorithm(graph, start, population_size, generations):
#随机生成路径,含起始点,生成种群大小
population = [generate_random_route(graph, start) for _ in range(population_size)]
for _ in range(generations):
population = sorted(population, key=lambda x: calculate_total_distance(graph, x))
new_population = [population[0]] # Elitism: keep the best route from the previous generation
while len(new_population) < population_size:
parent1, parent2 = random.sample(population, 2)
child = crossover(parent1, parent2)
if random.random() < 0.1: # Mutation rate
mutate(child)
new_population.append(child)
population = new_population
return population[0], calculate_total_distance(graph, population[0])
def pair_elements(lst):
#生成节点之间两两的组合,用于创建网络
return list(combinations(lst, 2))
def GA_sim(list_path,start,population_size,generations):
#构建路径图
G_cal=nx.Graph()
nodes=start+list_path
pairs = pair_elements(nodes)
for i in pairs:
length_edge=cal_path(i[0],i[1])
#weight与函数遗传算法中计算距离保持一致
G_cal.add_edge(i[0],i[1],weight=length_edge)
optimal,result=genetic_algorithm(G_cal, start[0], population_size, generations)
return optimal,result
下面代码为路径求解及文件导出过程,最后将得到各起点(start/配送中心)到多种终点(end/配送点)组合的配送距离结果。
#循环求解配送中心到各个配送点组合的最短距离
for i in list_start:
df_out=pd.DataFrame([])
list_out=[]
# for i in list_choose_path:
list_monte_path=monte_carlo_sim(list_end,10,1000)
for j in tqdm(list_monte_path, desc="Processing paths"):
_,result=GA_sim(list(j),start,1000,100)
list_out.append(result)
file_name=str(i)+'.csv'
df_out.to_csv(file_name)
6**、结语**
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)
blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以扫码获取!!!(备注Python)