python 寻找优化使成本函数最小的最优解的方法 今天来学习变量优化问题。寻找使成本函数最小的题解。适用于题解相互独立的情况,设计随机优化算法、爬山法、模拟退火算法、遗传算法。 优化问题的的精髓是:1、将题解转化为数字序列化,可以写出题解范围。2、成本函数能返回值 问题场景: 所有乘客从不同的地方飞到同一个目的地,服务人员等待所有人到来以后将人一次性接走。 离开时,服务人员将人一次性带到飞机场,所有乘客等待自己的航班离开。 要解决的问题: 如何设置乘客的到来和离开航班,以及接送机的时间,使得总代价最小。 将题解设为数字序列。 数字表示某人乘坐的第几次航班,从0开始,例如[1,4,3,2,7,3,6,3,2]表示第1个人做第2个航班来,第5个航班走,第2个人做第4个航班来,第3个航班走 题解相互独立:组团旅游问题,举办会议的人员接送问题 首先从网上采集航班信息,存储到schedule.txt文件中。共6个起始点,和共同的目的地。每个起止点之间包含多道航班。在txt中记录的就是起飞点、着陆点、起飞时间、着陆时间、价钱。 des_place,src6_place,6:19,8:13,239 src6_place,des_place,6:11,8:31,249 des_place,src6_place,8:04,10:59,136 src6_place,des_place,7:39,10:24,219 des_place,src6_place,9:31,11:43,210 src6_place,des_place,9:15,12:03,99 des_place,src6_place,11:07,13:24,171 src6_place,des_place,11:08,13:07,175 des_place,src6_place,12:31,14:02,234 src6_place,des_place,12:18,14:56,172 des_place,src6_place,14:05,15:47,226 src6_place,des_place,13:37,15:08,250 des_place,src6_place,15:07,17:21,129 src6_place,des_place,15:03,16:42,135 des_place,src6_place,16:35,18:56,144 src6_place,des_place,16:51,19:09,147 des_place,src6_place,18:25,20:34,205 src6_place,des_place,18:12,20:17,242 des_place,src6_place,20:05,21:44,172 src6_place,des_place,20:05,22:06,261 des_place,src5_place,6:03,8:43,219 src5_place,des_place,6:05,8:32,174 des_place,src5_place,7:50,10:08,164 src5_place,des_place,8:25,10:34,157 des_place,src5_place,9:11,10:42,172 src5_place,des_place,9:42,11:32,169 des_place,src5_place,10:33,13:11,132 src5_place,des_place,11:01,12:39,260 des_place,src5_place,12:08,14:47,231 src5_place,des_place,12:44,14:17,134 des_place,src5_place,14:19,17:09,190 src5_place,des_place,14:22,16:32,126 des_place,src5_place,15:04,17:23,189 src5_place,des_place,15:58,18:40,173 des_place,src5_place,17:06,20:00,95 src5_place,des_place,16:43,19:00,246 des_place,src5_place,18:33,20:22,143 src5_place,des_place,18:48,21:45,246 des_place,src5_place,19:32,21:25,160 src5_place,des_place,19:50,22:24,269 des_place,src4_place,6:33,9:14,172 src4_place,des_place,6:25,9:30,335 des_place,src4_place,8:23,11:07,143 src4_place,des_place,7:34,9:40,324 des_place,src4_place,9:25,12:46,295 src4_place,des_place,9:15,12:29,225 des_place,src4_place,11:08,14:38,262 src4_place,des_place,11:28,14:40,248 des_place,src4_place,12:37,15:05,170 src4_place,des_place,12:05,15:30,330 des_place,src4_place,14:08,16:09,232 src4_place,des_place,14:01,17:24,338 des_place,src4_place,15:23,18:49,150 src4_place,des_place,15:34,18:11,326 des_place,src4_place,16:50,19:26,304 src4_place,des_place,17:07,20:04,291 des_place,src4_place,18:07,21:30,355 src4_place,des_place,18:23,21:35,134 des_place,src4_place,20:27,23:42,169 src4_place,des_place,19:53,22:21,173 des_place,src1_place,6:39,8:09,86 src1_place,des_place,6:17,8:26,89 des_place,src1_place,8:23,10:28,149 src1_place,des_place,8:04,10:11,95 des_place,src1_place,9:58,11:18,130 src1_place,des_place,9:45,11:50,172 des_place,src1_place,10:33,12:03,74 src1_place,des_place,11:16,13:29,83 des_place,src1_place,12:08,14:05,142 src1_place,des_place,12:34,15:02,109 des_place,src1_place,13:39,15:30,74 src1_place,des_place,13:40,15:37,138 des_place,src1_place,15:25,16:58,62 src1_place,des_place,15:27,17:18,151 des_place,src1_place,17:03,18:03,103 src1_place,des_place,17:11,18:30,108 des_place,src1_place,18:24,20:49,124 src1_place,des_place,18:34,19:36,136 des_place,src1_place,19:58,21:23,142 src1_place,des_place,20:17,22:22,102 des_place,src2_place,6:09,9:49,414 src2_place,des_place,6:12,10:22,230 des_place,src2_place,7:57,11:15,347 src2_place,des_place,7:53,11:37,433 des_place,src2_place,9:49,13:51,229 src2_place,des_place,9:08,12:12,364 des_place,src2_place,10:51,14:16,256 src2_place,des_place,10:30,14:57,290 des_place,src2_place,12:20,16:34,500 src2_place,des_place,12:19,15:25,342 des_place,src2_place,14:20,17:32,332 src2_place,des_place,13:54,18:02,294 des_place,src2_place,15:49,20:10,497 src2_place,des_place,15:44,18:55,382 des_place,src2_place,17:14,20:59,277 src2_place,des_place,16:52,20:48,448 des_place,src2_place,18:44,22:42,351 src2_place,des_place,18:26,21:29,464 des_place,src2_place,19:57,23:15,512 src2_place,des_place,20:07,23:27,473 des_place,src3_place,6:58,9:01,238 src3_place,des_place,6:08,8:06,224 des_place,src3_place,8:19,11:16,122 src3_place,des_place,8:27,10:45,139 des_place,src3_place,9:58,12:56,249 src3_place,des_place,9:15,12:14,247 des_place,src3_place,10:32,13:16,139 src3_place,des_place,10:53,13:36,189 des_place,src3_place,12:01,13:41,267 src3_place,des_place,12:08,14:59,149 des_place,src3_place,13:37,15:33,142 src3_place,des_place,13:40,15:38,137 des_place,src3_place,15:50,18:45,243 src3_place,des_place,15:23,17:25,232 des_place,src3_place,16:33,18:15,253 src3_place,des_place,17:08,19:08,262 des_place,src3_place,18:17,21:04,259 src3_place,des_place,18:35,20:28,204 des_place,src3_place,19:46,21:45,214 src3_place,des_place,20:30,23:11,114 构建6名游客的航班信息 # 人员的名称和来源地信息 peoplelist = [('name1','src1_place'), ('name2','src2_place'), ('name3','src3_place'), ('name4','src4_place'), ('name5','src5_place'), ('name6','src6_place')] # 目的机场 destination='des_place' flights={} #加载所有航班信息。 # 查询所有的航班信息 for line in open('schedule.txt'): origin,dest,depart,arrive,price=line.strip().split(',') #源地址、目的地址、离开时间、到达时间、价格 flights.setdefault((origin,dest),[]) #航班信息已起止点为键值,每个起止点有多个航班 # 将航班信息添加到航班列表中 flights[(origin,dest)].append((depart,arrive,int(price))) #按时间顺序扩展每次航班 为了实现优化,我们将题解转变为数字序列,为了理解更加方便的理解数字序列代表的含义。实现一个函数,接受数字序列,打印输出航班信息。 # 将数字序列转换为航班,打印输出。输入为数字序列 def printschedule(r): for d in range(int(len(r)/2)): name=peoplelist[d][0] #人员名称 origin=peoplelist[d][1] #人员来源地 out=flights[(origin,destination)][int(r[2*d])] #往程航班 ret=flights[(destination,origin)][int(r[2*d+1])] #返程航班 print('%10s %10s %5s-%5s $%3s %5s-%5s $%3s' % (name,origin,out[0],out[1],out[2],ret[0],ret[1],ret[2])) 此场景我们要解决的问题就是寻找使花费最小的每位游客应该乘坐的往返航班。 我们定义一个成本函数代表我们需要花费的资金。 # 计算某个给定时间在一天中的分钟数 def getminutes(t): x = time.strptime(t, '%H:%M') return x[3] * 60 + x[4] # 成本函数。输入为数字序列 def schedulecost(sol): totalprice=0 latestarrival=0 earliestdep=24*60 for d in range(int(len(sol)/2)): # 得到往返航班 origin=peoplelist[d][1] #获取人员的来源地 outbound=flights[(origin,destination)][int(sol[2*d])] #获取往程航班 returnf=flights[(destination,origin)][int(sol[2*d+1])] #获取返程航班 # 总价格等于所有往返航班的价格之和 totalprice+=outbound[2] totalprice+=returnf[2] # 记录最晚到达和最早离开的时间 if latestarrivalgetminutes(returnf[0]): earliestdep=getminutes(returnf[0]) # 接机服务:每个人必须在机场等待直到最后一个人到达位置 # 送机服务:他们必须同时达到机场,并等待他们的返程航班 totalwait=0 for d in range(int(len(sol)/2)): origin=peoplelist[d][1] outbound=flights[(origin,destination)][int(sol[2*d])] returnf=flights[(destination,origin)][int(sol[2*d+1])] totalwait+=latestarrival-getminutes(outbound[1]) totalwait+=getminutes(returnf[0])-earliestdep # 这个题解要求多付一天的汽车出租费用么?如果是,则费用为50美元 if latestarrival>earliestdep: totalprice+=50 return totalprice+totalwait 1、随机搜索算法:随机选择题解,计算成本值,成本值最小的题解为确定题解。domain为题解范围(可选航班范围),costf为成本函数。 def randomoptimize(domain,costf): best=999999999 bestr=None for i in range(0,1000): # 创建随机解 sol=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))] #计算成本值 cost=costf(sol) # 与目前得到的最优解进行比较 if costdomain[j][0]: neighbors.append(sol[0:j]+[sol[j]-1]+sol[j+1:]) #向近0偏移 if sol[j]0.1: # 选择一个索引值 i=random.randint(0,len(domain)-1) # 选择一个改变索引值的方向 dir=random.randint(-step,step) #创建一个代表题解的新列表,改变其中一个值 vecb=vec[:] vecb[i]+=dir if vecb[i]domain[i][1]: vecb[i]=domain[i][1] #如果渐变不超出了题解的范围 # 计算当前成本与新的成本 ea=costf(vec) eb=costf(vecb) p=pow(math.e,(-eb-ea)/T) # 它是更好的解么?或者是趋向最优解的可能的临界解么 if (eb=domain[i][0]+step: return vec[0:i]+[vec[i]-step]+vec[i+1:] elif vec[i]<=domain[i][1]-step: return vec[0:i]+[vec[i]+step]+vec[i+1:] # 杂交操作(交叉) def crossover(r1,r2): i=random.randint(1,len(domain)-2) return r1[0:i]+r2[i:] # 构建初始种群 pop=[] for i in range(popsize): #随机产生50个动物的种群 vec=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))] pop.append(vec) # 每一代有多少胜出者? topelite=int(elite*popsize) # 主循环 for i in range(maxiter): scores=[(costf(v),v) for v in pop] scores.sort() ranked=[v for (s,v) in scores] # 在种群中选出优胜者 pop=ranked[0:topelite] # 为优秀基因者,添加变异和配对后的胜出者 while len(pop)getminutes(returnf[0]): earliestdep=getminutes(returnf[0]) # 接机服务:每个人必须在机场等待直到最后一个人到达位置 # 送机服务:他们必须同时达到机场,并等待他们的返程航班 totalwait=0 for d in range(int(len(sol)/2)): origin=peoplelist[d][1] outbound=flights[(origin,destination)][int(sol[2*d])] returnf=flights[(destination,origin)][int(sol[2*d+1])] totalwait+=latestarrival-getminutes(outbound[1]) totalwait+=getminutes(returnf[0])-earliestdep # 这个题解要求多付一天的汽车出租费用么?如果是,则费用为50美元 if latestarrival>earliestdep: totalprice+=50 return totalprice+totalwait # 随机搜索算法:随机选择题解,计算成本值,成本值最小的题解为确定题解。domain为题解范围(可选航班范围),costf为成本函数。 def randomoptimize(domain,costf): best=999999999 bestr=None for i in range(0,1000): # 创建随机解 sol=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))] #计算成本值 cost=costf(sol) # 与目前得到的最优解进行比较 if costdomain[j][0]: neighbors.append(sol[0:j]+[sol[j]-1]+sol[j+1:]) #向近0偏移 if sol[j]0.1: # 选择一个索引值 i=random.randint(0,len(domain)-1) # 选择一个改变索引值的方向 dir=random.randint(-step,step) #创建一个代表题解的新列表,改变其中一个值 vecb=vec[:] vecb[i]+=dir if vecb[i]domain[i][1]: vecb[i]=domain[i][1] #如果渐变不超出了题解的范围 # 计算当前成本与新的成本 ea=costf(vec) eb=costf(vecb) p=pow(math.e,(-eb-ea)/T) # 它是更好的解么?或者是趋向最优解的可能的临界解么 if (eb=domain[i][0]+step: return vec[0:i]+[vec[i]-step]+vec[i+1:] elif vec[i]<=domain[i][1]-step: return vec[0:i]+[vec[i]+step]+vec[i+1:] # 杂交操作(交叉) def crossover(r1,r2): i=random.randint(1,len(domain)-2) return r1[0:i]+r2[i:] # 构建初始种群 pop=[] for i in range(popsize): #随机产生50个动物的种群 vec=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))] pop.append(vec) # 每一代有多少胜出者? topelite=int(elite*popsize) # 主循环 for i in range(maxiter): scores=[(costf(v),v) for v in pop] scores.sort() ranked=[v for (s,v) in scores] # 在种群中选出优胜者 pop=ranked[0:topelite] # 为优秀基因者,添加变异和配对后的胜出者 while len(pop)0 and ua<1 and ub>0 and ub<1: total+=1 for i in range(len(people)): for j in range(i+1,len(people)): # 获取两个节点的位置 (x1,y1),(x2,y2)=loc[people[i]],loc[people[j]] # 获取两节点之间的距离 dist=math.sqrt(math.pow(x1-x2,2)+math.pow(y1-y2,2)) # 对间距小于50个像素的节点进行判罚 if dist<50: total+=(1.0-(dist/50.0)) return total #画图,绘制网络 from PIL import Image,ImageDraw def drawnetwork(sol): # 建立image对象 img=Image.new('RGB',(400,400),(255,255,255)) draw=ImageDraw.Draw(img) # 建立标识位置信息的字典 pos=dict([(people[i],(sol[i*2],sol[i*2+1])) for i in range(0,len(people))]) for (a,b) in links: draw.line((pos[a],pos[b]),fill=(255,0,0)) for n,p in pos.items(): draw.text(p,n,(0,0,0)) img.show() domain=[(10,370)]*(len(people)*2) #设定题解范围 if __name__=="__main__": #只有在执行当前模块时才会运行此函数 print(domain) s = optimization.randomoptimize(domain, crosscount) # 随机搜索法,寻找最优题解 print(s) drawnetwork(s) # 绘制关系网 s = optimization.hillclimb(domain, crosscount) # 爬山法,寻找最优题解 print(s) drawnetwork(s) # 绘制关系网 s = optimization.annealingoptimize(domain, crosscount) # 模拟退火算法,寻找最优题解 print(s) drawnetwork(s) # 绘制关系网 s = optimization.geneticoptimize(domain, crosscount) # 遗传算法,寻找最优题解 print(s) drawnetwork(s) # 绘制关系网 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持中文源码网。