全栈工程师开发手册 (作者:栾鹏)

python数据挖掘系列教程

举个例子我们来了解一下优化问题,学校为2n个同学分配n个宿舍,每个宿舍两个床铺,每个同学提交了自己最想住的宿舍和其次想住的宿舍(只选房间,不选床位)。但是有可能有多个同学想住同一个宿舍,有的宿舍没有人想住。学校为了能尽量同学们住进自己想住的宿舍,同时让每个宿舍都住进学生。设计了一套方案,使的在满足一定条件的情况下(每个宿舍都住满人),尽可能满足目的(学生住进自己想住的宿舍)。这就是优化问题。

优化问题就是寻找使成本函数最小的题解(题解就是函数自变量),也就是求解函数极值问题。这与线性回归非常相似,不过优化问题面临不是线性问题,变量的取值为离散值。适用于题解相互独立的情况,本文的内容包含随机优化算法、爬山法、模拟退火算法、遗传算法。

优化问题的的精髓是:1、将题解转化为数字序列化,并可以写出题解范围。2、成本函数能返回值

问题场景:

所有乘客在同一天不同时间点从不同的地方飞到同一个目的地参加会议,服务人员在目的地等待所有人到来以后将乘客一次性接走到酒店。

在会议结束,服务人员将所有人一次性带到飞机场,所有乘客等待自己的航班离开。

要解决的问题:

如何设置乘客的来目的时的航班和离开目的地的航班,以及接送机的时间,使得总代价最小。

将题解设为数字序列

数字表示某人乘坐的航班序号,从0开始。由于每个人涉及到往返两次航班,因此每个人需要两个数字表示。例如[1,4,3,2,7,3,6,3,2]中1,4表示第一个人的航班序号(第1个人坐第2个航班来,第5个航班回),3,2表示第二个人的航班序号(第2个人做第4个航班来,第3个航班回)

找出题解取值范围
题解为这一串数字序列,每个数字的可取值为所对应的可取航班号。如数字序列[1,4,3,2,7,3,6,3,2]第一个数字的除了取值为1,还可以取0-9之间的任意一个数,分别代表第一个人的第1个航班到第10个航班。

适用场景:

组团旅游人员接送问题问题,举办会议的人员接送问题

首先从网上采集航班信息,存储到schedule.txt文件中。共6个乘客,来自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=0latestarrival=0earliestdep=24*60for 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 latestarrival<getminutes(outbound[1]): latestarrival=getminutes(outbound[1])if earliestdep>getminutes(returnf[0]): earliestdep=getminutes(returnf[0])# 接机服务:每个人必须在机场等待直到最后一个人到达目的地时才会被一次性接送到酒店。# 送机服务:所有旅客必须同时从酒店被送往机场,并等待他们的返程航班。totalwait=0for 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+=50return totalprice+totalwait

上面的教程我们已经知道了我们面临的问题的场景和所要解决的问题,以及自变量的取值范围(每个人的航班号)

下面我们就来学习怎么找到使成本函数最小的题解。

当然最直接的方法是遍历每一个题解的取值,计算成本函数,然后取使成本函数最小的题解。但是对于大数据来说这是不现实的。

注意下面的函数不一定是找到最优解。

1、随机搜索算法:随机选择题解,计算成本值,成本值最小的题解为确定题解。函数中domain为题解范围(可选航班范围),costf为成本函数。

在本场景中随机解就是数字序列,为每一个数字在可取值范围内随意选一个值。也就是随意为每个人安排往、返航班。

def randomoptimize(domain,costf):best=999999999bestr=Nonefor i in range(0,1000):# 创建随机解sol=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))]#计算成本值cost=costf(sol)# 与目前得到的最优解进行比较if cost<best:best=costbestr=solreturn sol  #返回随机最优解

2、爬山法:对于成本函数连续的情况,题解向成本值减小的地方渐变,直到成本值不再变化。domain为题解范围(可选航班范围),costf为成本函数。在只有一个极低点时最有效。可以采用随机重复爬山法优化。

爬山法是为了寻找路径达到成本函数的最低值,所以我们更愿意称呼他为下山法。

在此场景下,就是先随意为每个乘客安排往返航班,再尝试计算每个人的原航班前后的一次航班产生的成本值。选择成本值小的为航班继续下山。

def hillclimb(domain,costf):# 创建一个随机解sol=[random.randint(domain[i][0],domain[i][1]) for i in range(len(domain))]# 主循环while 1:# 创建相邻解的列表neighbors=[]for j in range(len(domain)):   #在j等于0和末尾的时候存在问题# 在每个方向上相对于原值偏离一点。每个方向上的偏离不相互影响if sol[j]>domain[j][0]:neighbors.append(sol[0:j]+[sol[j]-1]+sol[j+1:])  #向近0偏移if sol[j]<domain[j][1]:neighbors.append(sol[0:j]+[sol[j]+1]+sol[j+1:])  #远0偏移# 在相邻解中寻找最优解current=costf(sol)best=currentfor j in range(len(neighbors)):cost=costf(neighbors[j])if cost<best:best=costsol=neighbors[j]# 如果没有更好的解,则退出循环。即寻找了极低点if best==current:breakreturn sol

3、模拟退火算法:概率性接收更优解(更差解),时间越久,概率越大(越低)。如果说爬山法是指向低处走。那么模拟退火算法是一定概率的允许向高处走的改进的爬山算法。

#domain为题解范围。由12个区间范围组成。costf为成本函数,cool为概率变化进度,step为步长
def annealingoptimize(domain,costf,T=10000.0,cool=0.95,step=1):# 随机初始化题解。一共12个人次(6个人来回,为12个人次)。在每个人次的航班范围内随机选一个航班vec=[float(random.randint(domain[i][0],domain[i][1])) for i in range(len(domain))]while T>0.1:# 随意选择一个题解分量。(随机选择一个人次)i=random.randint(0,len(domain)-1)# 选择一个改变索引值的方向dir=random.randint(-step,step)#创建一个代表题解的新列表,改变其中一个值vecb=vec[:]vecb[i]+=dirif vecb[i]<domain[i][0]: vecb[i]=domain[i][0]   #如果某个分量低于了该分量的最小值elif vecb[i]>domain[i][1]: vecb[i]=domain[i][1] #如果某个分量大于了该分量的最大值# 计算当前成本与新的成本ea=costf(vec)eb=costf(vecb)p=pow(math.e,(-eb-ea)/T)# 它是更好的解么?或者是趋向最优解的可能的临界解么# random.random()<p的结果是True的概率是p,因为random.random()是均匀分布产生0-1之间的数。if (eb<ea or random.random()<p):vec=vecb# 降低温度T=T*coolreturn vec

4、遗传算法:基因杂交(交叉)或基因变异。domain题解范围,costf成本函数,popsize种群大小,step变异基因量,mutprob变异比例,elite优秀基因者的比例,maxiter运行多少代。

其中涉及到生物学的概念。

基因也就是特征属性。
携带优秀基因的对象,能比其他对象产生的成本值更小。
变异就是在原有在原有基因(属性)的基础上改变一个或一部分基因的值。
杂交就是从两个对象中,随意各取一部分基因组成新的对象。
近亲杂交就是一直在一个小范围对象中进行杂交。近亲杂交能保留优势但也能方法劣势。

def geneticoptimize(domain,costf,popsize=50,step=1,mutprob=0.2,elite=0.2,maxiter=100):# 变异操作,存在变异失败的情况def mutate(vec):i=random.randint(0,len(domain)-1)if random.random()<0.5 and vec[i]>=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)<popsize:if random.random()<mutprob:   #变异所占的比例# 变异c=random.randint(0,topelite-1)newanimal = mutate(ranked[c])if newanimal!=None:    #有可能存在变异死亡者pop.append(newanimal)else:# 相互杂交。以后会遇到近亲结婚的问题c1=random.randint(0,topelite-1)c2=random.randint(0,topelite-1)newanimal = crossover(ranked[c1], ranked[c2])pop.append(newanimal)# 打印当前最优解和成本# print(scores[0])return scores[0][1]  #返回最优解

上面的教程讲述了如何寻找一个比较好的解,下面我们就来尝试一下如何应用这些算法。

测试程序

if __name__=="__main__":     #只有在执行当前模块时才会运行此函数print(flights)   #打印所有航班信息domain=[]for start_stop in flights:              #查询每个起止点的航班个数domain.append((0,len(flights[start_stop])-1))    #获取题解范围,两边必区间(航班范围的数据序列)# domain=[(0,9)]*(len(peoplelist)*2)print(domain)s=randomoptimize(domain,schedulecost)  # 随机搜索法,寻找最优题解print(s)printschedule(s)  #打印最优航班信息s = hillclimb(domain, schedulecost)  # 爬山法,寻找最优题解print(s)printschedule(s)  # 打印最优航班信息s = annealingoptimize(domain, schedulecost)  # 模拟退火算法,寻找最优题解print(s)printschedule(s)  # 打印最优航班信息s = geneticoptimize(domain, schedulecost)  # 遗传算法,寻找最优题解print(s)printschedule(s)  # 打印最优航班信息

优化算法的讲述到此结束。下面我们来用上面形成的优化算法试着解决另一个问题。

将上面的代码合并在optimization.py文件中。在下面的案例中调用。

使用优化算法解决房间住宿问题

场景:n个宿舍,每个房间有两个床位。2n个学生,每个学生有自己首选房间和次选房间(只选房间,不选床位)。将所有学生安排到所有房间

目标:在尽量满足学生的选择的情况下,为学生安排宿舍,但是需要所有学生住满所有床铺。

将题解转化为数字间皆没有联系的数字序列。可以让每个数字代表可选床位的第几个,索引从0开始

例如:[0,2,1,1,1,2,0,1]表示第1个人选可选床位的第1个,第2个人选剩余可选床位的第3个床位,第3个人选剩余可选床位的第2个。。。

测试代码

# 利用之前设计好的优化算法,解决涉及偏好的优化问题。1、将题解转化为数字序列化,可以写出题解范围。2、成本函数能返回值
import random
import math
import optimization# 场景:每个房间有两个床位,每个学生有自己首选房间和次选房间(只选房间,不选床位)。将所有学生安排到所有房间
# 目标:在尽量满足学生的选择的情况下,为学生安排宿舍# 将题解转化为数字间没有联系的数字序列。可以让每个数字代表可选床位的第几个,索引从0开始
# 例如:[0,2,1,1,1,2,0,1]表示第1个人选可选床位的第1个,第2个人选剩余可选床位的第3个床位,第3个人选剩余可选床位的第2个。。。# 代表宿舍,每个宿舍有两个床位。5个房间
dorms=['Zeus','Athena','Hercules','Bacchus','Pluto']# 代表学生及其首选房间和次选房间。10个人
prefs=[('Toby', ('Bacchus', 'Hercules')),('Steve', ('Zeus', 'Pluto')),('Karen', ('Athena', 'Zeus')),('Sarah', ('Zeus', 'Pluto')),('Dave', ('Athena', 'Bacchus')), ('Jeff', ('Hercules', 'Pluto')), ('Fred', ('Pluto', 'Athena')), ('Suzie', ('Bacchus', 'Hercules')), ('Laura', ('Bacchus', 'Hercules')), ('James', ('Hercules', 'Athena'))]# [(0,9),(0,8),(0,7),(0,6),...,(0,0)]   题解范围。因为前面选择了一个,后面的可选范围就会变少
domain=[(0,(len(dorms)*2)-i-1) for i in range(0,len(dorms)*2)]   #题解的可选范围# 打印输出题解。输入为题解序列
def printsolution(vec):slots=[]# 为每个宿舍键两个槽for i in range(len(dorms)): slots+=[i,i]# 遍历每一名学生的安置情况for i in range(len(vec)):x=int(vec[i])# 从剩余槽中选择dorm=dorms[slots[x]]# 输出学生及其被分配的宿舍print(prefs[i][0],dorm)# 删除该槽,这样后面的数字列表才能正确翻译成“剩余床位”del slots[x]# 成本函数:
def dormcost(vec):cost=0# 创建一个槽序列slots=[0,0,1,1,2,2,3,3,4,4]# 遍历每一名学生for i in range(len(vec)):x=int(vec[i])dorm=dorms[slots[x]]pref=prefs[i][1]# 首选成本值为0,次选成本值为1if pref[0]==dorm: cost+=0elif pref[1]==dorm: cost+=1else: cost+=3# 不在选择之列则成本值为3# 删除选中的槽del slots[x]return costif __name__=="__main__":     #只有在执行当前模块时才会运行此函数print(domain)s = optimization.randomoptimize(domain, dormcost)  # 随机搜索法,寻找最优题解print(s)printsolution(s)  # 打印最优解代表的含义s = optimization.hillclimb(domain, dormcost)  # 爬山法,寻找最优题解print(s)printsolution(s)  # 打印最优解代表的含义s = optimization.annealingoptimize(domain, dormcost)  # 模拟退火算法,寻找最优题解print(s)printsolution(s)  # 打印最优解代表的含义s = optimization.geneticoptimize(domain, dormcost)  # 遗传算法,寻找最优题解print(s)printsolution(s)  # 打印最优解代表的含义

上面的教程我们又解决了一个优化问题,下面我们再来解决一个优化问题。

使用优化算法解决绘制关系网问题

场景:在绘制关系网图中,每个人在图中都有位置x,y坐标,在有关联的两个人中间添加连线。

目标:是所有连线的交叉数最少

将题解转化为数字间没有联系的数字序列。可以让每个数字代表人物在图形中的位置x,y
例如:[200,120,250,230…]表示第1个人坐标为200,120,第2个人坐标为250,230…

测试代码

# 将优化算法应用到绘制关系网图中,使得交叉线最少import math
import optimization# 场景:在绘制关系网图中,每个人在图中都有位置x,y坐标,在有关联的两个人中间添加连线。
# 目标:是所有连线的交叉数最少# 将题解转化为数字间没有联系的数字序列。可以让每个数字代表人物在图形中的位置x,y
# 例如:[200,120,250,230..]表示第1个人坐标为200,120,第2个人坐标为250,230...# 关系网中涉及的人员
people=['Charlie','Augustus','Veruca','Violet','Mike','Joe','Willy','Miranda']# 关联关系
links=[('Augustus', 'Willy'), ('Mike', 'Joe'), ('Miranda', 'Mike'), ('Violet', 'Augustus'), ('Miranda', 'Willy'), ('Charlie', 'Mike'), ('Veruca', 'Joe'), ('Miranda', 'Augustus'), ('Willy', 'Augustus'), ('Joe', 'Charlie'), ('Veruca', 'Augustus'), ('Miranda', 'Joe')]# 计算交叉线,作为成本函数
def crosscount(v):# 将数字序列转化为一个person:(x,y)的字典loc=dict([(people[i],(v[i*2],v[i*2+1])) for i in range(0,len(people))])total=0# 遍历每一对连线for i in range(len(links)):for j in range(i+1,len(links)):# 获取坐标位置(x1,y1),(x2,y2)=loc[links[i][0]],loc[links[i][1]](x3,y3),(x4,y4)=loc[links[j][0]],loc[links[j][1]]den=(y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)# 如果两线平行,则den==0。两条线是线段,不是直线if den==0: continue# 否则,ua与ub就是两条交叉线的分数值。# line where they crossua=((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/denub=((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/den# 如果两条线的分数值介于0和1之间,则两线彼此交叉if ua>0 and ua<1 and ub>0 and ub<1:total+=1for 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,ImageDrawdef 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)  # 绘制关系网

最后我们再来回顾一下本文的优化问题。

优化问题就是寻找使成本函数最小的题解(题解就是函数自变量)。适用于题解相互独立的情况,本文的内容包含随机优化算法、爬山法、模拟退火算法、遗传算法。

优化问题的的精髓是:1、将题解转化为数字序列化,并可以写出题解范围。2、成本函数能返回值

python机器学习案例系列教程——优化,寻找使成本函数最小的最优解相关推荐

  1. python机器学习案例系列教程——K最近邻算法(KNN)、kd树

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 K最近邻简介 K最近邻属于一种估值或分类算法,他的解释很容易. 我们假设一个人的优秀成为设定为1.2.3.4.5.6.7.8.9.10 ...

  2. python机器学习案例系列教程——极大似然估计、EM算法

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 极大似然 极大似然(Maximum Likelihood)估计为用于已知模型的参数估计的统计学方法. 也就是求使得似然函数最大的代估参 ...

  3. python机器学习案例系列教程——集成学习(Bagging、Boosting、随机森林RF、AdaBoost、GBDT、xgboost)

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 可以通过聚集多个分类器的预测结果提高分类器的分类准确率,这一方法称为集成(Ensemble)学习或分类器组合(Classifier C ...

  4. python机器学习案例系列教程——支持向量机SVM、核函数

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 线性函数.线性回归.线性分类 参考:http://blog.csdn.net/luanpeng825485697/article/de ...

  5. python机器学习案例系列教程——决策树(ID3、C4.5、CART)

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 决策树简介 决策树算是最好理解的分类器了.决策树就是一个多层if-else函数,就是对对象属性进行多层if-else判断,获取目标属性 ...

  6. python机器学习案例系列教程——GBDT算法、XGBOOST算法

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 GBDT概述 GBDT也是集成学习Boosting家族的成员,但是却和传统的Adaboost有很大的不同.回顾下Adaboost,我们 ...

  7. python机器学习案例系列教程——k均值聚类、k中心点聚类

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 上一篇我们学习了层次聚类.层次聚类只是迭代的把最相近的两个聚类匹配起来.并没有给出能给出多少的分组.今天我们来研究一个K均值聚类.就是 ...

  8. python机器学习案例系列教程——文档分类器,朴素贝叶斯分类器,费舍尔分类器

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 github地址:https://github.com/626626cdllp/data-mining/tree/master/Bay ...

  9. python机器学习案例系列教程——推荐系统

    全栈工程师开发手册 (作者:栾鹏) python数据挖掘系列教程 主流的推荐系统算法大致分为两类: 基于用户行为数据的协同过滤算法 基于内容数据的过滤算法 大致而言,基于内容数据的算法适用于cold ...

最新文章

  1. Java并发学习一:CPU缓存导致的可见性问题带来的并发Bug
  2. oracle 按日输出 取整数,Oracle按日周月分組統計,及next_day()函數詳解
  3. 【强化学习】Actor-Critic
  4. python网络编程学习笔记(二)
  5. Ubuntu查看及修改IP地址
  6. 第十五章 面向对象程序设计
  7. WinPE启动盘制作
  8. 使用 Python 批量下载喜马拉雅有声书音频
  9. 版本管理工具之ClearCase
  10. RapidMiner介绍与实践(二)贝叶斯分类器
  11. js判断数组key是否存在
  12. webpack ——css兼容性处理
  13. MySQL临时表的作用
  14. scratch五彩缤纷多瓣花 电子学会图形化编程scratch等级考试二级真题和答案解析2021-6
  15. MPC-HC视频播放器
  16. 江恩 计算机,江恩理论基础篇
  17. Qt实现在QLabel上显示图片并进行线条/矩形框/多边形的绘制
  18. T54 Origin导出图片
  19. 记微信开发者工具登录网络连接失败
  20. 二叉树的遍历 详解及实现

热门文章

  1. 智能语音识别系统_语音识别技术原理_智能语音识别系统如何识别用户意图_企业服务汇...
  2. Linux下科大讯飞语音识别全面总结
  3. 有道口语大师APP评测:语音识别准确度低
  4. boost.asio mysql_boost asio学习笔记
  5. vue + wangeditor封装富文本组件
  6. matlab中 mcc、mbuild和mex命令详解
  7. HEVC学习 —— HM的使用
  8. 计算机组成mod2是什么意思,计算机组成原理 第2讲_数据表示.ppt
  9. c语言字符串反转栈,【C语言】利用栈将数组中字符串逆序
  10. springboot打成jar包,在windows上运行出现乱码