用Python+粒子群算法搞定多仓库物流配送:一个完整可运行的代码实例
用Python粒子群算法搞定多仓库物流配送一个完整可运行的代码实例当你在电商平台下单时是否好奇过商品是如何从不同仓库快速配送到你手中的这背后隐藏着一个复杂的物流优化问题——多配送中心车辆路径问题MDCVRP。本文将带你用Python和粒子群算法PSO亲手构建一个完整的解决方案从数据准备到结果可视化一步步实现高效的物流配送规划。1. 环境准备与问题定义在开始编码前我们需要明确几个关键概念。多配送中心VRPMDCVRP是经典VRP问题的扩展它需要考虑多个配送中心商品可能从不同仓库发出车辆路径优化每辆车的行驶路线需要科学规划成本最小化包括车辆启动成本和行驶成本先安装必要的Python库pip install pandas matplotlib numpy典型的MDCVRP问题包含以下约束条件约束类型说明示例值车辆容量单次运输最大载重120单位行驶距离单辆车最大行驶距离250公里客户需求每个客户点的需求量随机生成配送中心仓库位置和数量3个中心提示实际应用中这些参数需要根据业务数据调整本文使用模拟数据进行演示。2. 数据准备与预处理我们先定义配送中心和客户点的位置坐标以及各自的需求量# 配送中心与客户点坐标 (前3个是配送中心) Customer [(50, 25),(25,75),(75,75),(96, 24),(40, 5),(49, 8),(13, 7), (29, 89),(48, 30),(84, 39),(14, 47),(2, 24),(3, 82),(65, 10), (98, 52),(84, 25),(41, 69),(1, 65),(51, 71),(75, 83),(29, 32), (83, 3),(50, 93),(80, 94),(5, 42),(62, 70),(31, 62),(19, 97), (91, 75),(27, 49),(23, 15),(20, 70),(85, 60),(98, 85)] # 各点需求量 (前3个配送中心需求为0) Demand [0,0,0,16,11,6,10,7,12,16,6,16,8,14,7,16,3,22,18,19,1,14, 8,12,4,8,24,24,2,10,15,2,14,9]计算各点间距离的函数import math import pandas as pd def calDistance(CityCoordinates): dis_matrix pd.DataFrame(dataNone,columnsrange(len(CityCoordinates)), indexrange(len(CityCoordinates))) for i in range(len(CityCoordinates)): xi,yi CityCoordinates[i][0],CityCoordinates[i][1] for j in range(len(CityCoordinates)): xj,yj CityCoordinates[j][0],CityCoordinates[j][1] dis_matrix.iloc[i,j] round(math.sqrt((xi-xj)**2(yi-yj)**2),2) return dis_matrix3. 两阶段求解策略MDCVRP的复杂性在于需要同时解决两个问题客户点分配和路径优化。我们采用分而治之的策略分配阶段将客户点分配给最近的配送中心优化阶段对每个配送中心独立进行路径优化3.1 客户点分配实现def assign_distribution_center(dis_matrix, DC, C): d [[] for i in range(DC)] # 存储分配的列表 for i in range(DC, DCC): # 遍历所有客户点 d_i [dis_matrix.loc[i,j] for j in range(DC)] # 计算与各配送中心的距离 min_dis_index d_i.index(min(d_i)) # 找出最近配送中心 d[min_dis_index].append(i) # 分配客户点 return d注意这种简单分配策略可能不是最优的但能大幅降低问题复杂度。更高级的方法可以考虑负载均衡等因素。3.2 粒子群算法设计PSO算法需要特别设计以适应VRP问题def greedy(CityCoordinates, dis_matrix, DC, certer_number): 贪婪算法生成初始解 dis_matrix dis_matrix.iloc[[certer_number]CityCoordinates, [certer_number]CityCoordinates].astype(float64) for i in CityCoordinates: dis_matrix.loc[i,i] math.pow(10,10) dis_matrix.loc[:,certer_number] math.pow(10,10) line [] # 初始化路径 now_cus random.sample(CityCoordinates,1)[0] # 随机起点 line.append(now_cus) dis_matrix.loc[:,now_cus] math.pow(10,10) for i in range(1,len(CityCoordinates)): next_cus dis_matrix.loc[now_cus,:].idxmin() # 最近邻 line.append(next_cus) dis_matrix.loc[:,next_cus] math.pow(10,10) now_cus next_cus return line关键参数设置# 车辆参数 CAPACITY 120 # 车辆最大容量 DISTABCE 250 # 车辆最大行驶距离 C0 30 # 车辆启动成本 C1 1 # 单位距离成本 # PSO参数 birdNum 30 # 粒子数量 w 0.2 # 惯性因子 c1 0.4 # 自我认知因子 c2 0.4 # 社会认知因子 iterMax 100 # 迭代次数4. 完整实现与结果可视化将所有组件整合成完整解决方案def main(): # 初始化 dis_matrix calDistance(Customer) distribution_centers assign_distribution_center(dis_matrix, DC, C) bestfit_list, gLine_car_list [], [] for certer_number in range(len(distribution_centers)): # 初始化粒子群 birdPop [greedy(distribution_centers[certer_number], dis_matrix, DC, certer_number) for _ in range(birdNum)] # 评估初始解 birdPop_car, fits calFitness(birdPop, certer_number, Demand, dis_matrix, CAPACITY, DISTABCE, C0, C1) # 迭代优化 gBest pBest min(fits) gLine pLine birdPop[fits.index(min(fits))] gLine_car pLine_car birdPop_car[fits.index(min(fits))] for iterI in range(1, iterMax1): for i in range(birdNum): birdPop[i] crossover(birdPop[i], pLine, gLine, w, c1, c2) birdPop_car, fits calFitness(birdPop, certer_number, Demand, dis_matrix, CAPACITY, DISTABCE, C0, C1) current_best min(fits) if current_best pBest: pBest, pLine, pLine_car current_best, birdPop[fits.index(current_best)], birdPop_car[fits.index(current_best)] if current_best gBest: gBest, gLine, gLine_car current_best, birdPop[fits.index(current_best)], birdPop_car[fits.index(current_best)] bestfit_list.append(gBest) gLine_car_list.append(gLine_car) print(最优总成本:, sum(bestfit_list)) draw_path(gLine_car_list, Customer) if __name__ __main__: main()可视化函数实现import matplotlib.pyplot as plt def draw_path(car_routes, CityCoordinates): colors [red, blue, green] for i in range(len(car_routes)): route_i car_routes[i] for route in route_i: x, y [], [] for node in route: coord CityCoordinates[node] x.append(coord[0]) y.append(coord[1]) # 回到配送中心 x.append(CityCoordinates[route[0]][0]) y.append(CityCoordinates[route[0]][1]) plt.plot(x, y, colorcolors[i], alpha0.6, linewidth1.5) # 标记配送中心 for i in range(3): plt.scatter(CityCoordinates[i][0], CityCoordinates[i][1], cblack, markers, s100, labelDC if i0 else ) plt.title(MDCVRP Solution Visualization) plt.xlabel(X Coordinate) plt.ylabel(Y Coordinate) plt.legend() plt.grid(True) plt.show()运行结果示例最优总成本761.2配送路线配送中心12条路线配送中心21条路线配送中心31条路线5. 性能优化与扩展思路虽然基础实现已经能解决问题但在实际应用中还可以考虑以下优化算法改进方向引入模拟退火机制避免局部最优结合遗传算法的交叉变异操作采用自适应参数调整策略业务约束扩展时间窗约束客户指定服务时间多车型混合调度动态实时路径调整工程化建议使用更高效的距离矩阵计算如KD-Tree并行化处理各配送中心的优化过程集成实时交通数据# 示例自适应惯性权重调整 def adaptive_weight(iter, max_iter): w_start 0.9 w_end 0.4 return w_start - (w_start - w_end) * (iter / max_iter)实际项目中我们曾遇到一个有趣的现象当客户点呈现明显聚类特征时先进行聚类分析再分配配送中心比简单的最远邻分配能降低约8%的总成本。这提示我们在算法选择时要充分考虑数据本身的特性。