zoukankan      html  css  js  c++  java
  • GA算法-R语言实现

    GA算法-R语言实现

     

    旅行商问题

    班共有30位同学,来自22个地区,我们希望在假期来一次说走就走的旅行,将所有同学的家乡走一遍。算起来,路费是一笔很大的花销,所以希望设计一个旅行方案,确保这一趟走下来的总路程最短。

    旅行商问题是一个经典的NP问题

    NP就是Non-deterministic Polynomial,即多项式复杂程度的非确定性问题,是世界七大数学难题之一。

    如果使用枚举法求解,22个地点共有:
    (22-1)!/2 = 25545471085854720000 种路线方案

    GA算法

    遗传算法将“优胜劣汰,适者生存”的生物进化原理引入优化参数形成的编码串联群体中,按所选择的适应度函数并通过遗传中的复制、交叉及变异对个体进行筛选,使适应度高的个体被保留下来,组成新的群体,新的群体既继承了上一代的信息,又优于上一代。这样周而复始,群体中个体适应度不断提高,直到满足一定的条件。遗传算法的算法简单,可并行处理,并能到全局最优解。

    GA算法设计

    1.生成原始染色体种群

    采用实数编码,以N个城市的序号作为一条可能的路径。 例如对8个城市,可生成如下的染色体代表一条路径,8,6,4,2,7,5,3,1.重复操作生成数目等于n的染色体种群。

    2.生成适应度函数

    由于是求最短路径,适应度函数一般求函数最大值,所以取路径总长度T的倒数,即fitness=1/T。

    3.选择染色体

    采用轮盘赌的方式产生父代染色体。

    4.对染色体种群进行编码

    假设有一个含有九个城市的列表:W=(A,B,C,D,E,F,G,H,I)。
    有如下两条路线:
    W1=(A,D,B,H,F,I,G,E,C)
    W2=(B,C,A,D,E,H,I,F,G)
    则这两条路线可编码为:
    W1=(142869753)
    W2=(231458967)

    5.交叉

    以概率Pc选择参加交叉的个体(偶数个),用两点交叉算子进行操作。
    例如对于下面两个染色体个体
    (1 3 4 | 5 2 9 | 8 6 7)
    (1 7 6 | 9 5 2 | 4 3 8)
    通过两点交叉可得到子代染色体为
    (1 3 4 | 9 5 2 | 8 6 7)
    (1 7 6 | 5 2 9 | 4 3 8)

    6.变异

    以概率Pm选择参加变异的个体,用对换变异进行操作。随机的选择个体中的两个位点,进行交换基因。
    如A=123456789;如果对换点为4和7,则经过对换后为B=123756489

    7.解码

    对染色体进行解码,恢复染色体的实数表示方法。

    8.逐代进化

    根据得出的新的染色体,再次返回选择染色体的步骤,进行迭代,直到达到迭代次数,算法停止。

    算法实现

    #加载packages
    library(sp)
    library(maptools)
    library(geosphere)
    
    source("C:\Users\ShangFR\Desktop\路径优化\GA算法脚本.R")
    data=read.csv("C:\Users\ShangFR\Desktop\路径优化\143地理坐标.csv") #读取城市经纬度数据
    border <- readShapePoly("C:\Users\ShangFR\Desktop\路径优化\map\bou2_4p.shp") #读取各省的边界数据等
    
    #初始化(列出地区距离矩阵-聚类)
    da=data[,1:2]
    rownames(da)=data[,3]
    hc=hclust(dist(da))
    cutree(hc, h = 10)
    plot(hc)
    
    route=CreatDNA(data,5)  
    x = route[,1]
    y = route[,2]
    z = route[,3]
    cols=route[,4]
    
    muer.lonlat = cbind(route[,1],route[,2]) # matrix
    
    muer.dists = distm(muer.lonlat, fun=distVincentyEllipsoid) # 精确计算,椭圆
    
    ans=round(muer.dists/1000,2)
    roundots = list(x=x,y=y,ans=ans,z=z,cols=cols)
    species = GA4TSP(dots=roundots,initDNA=NULL,N=50,cp=0.1,vp=0.01,maxIter=1000,maxStay=100,maxElite=2,drawing=TRUE)
    #粗糙地计算总路程上界
    UpperBound = function(disM)
    {
        mx = apply(disM,1,max)  #两城市间最长距离
        returnsum(mx) )       #最长旅行路径
    }
     
    #生成随机染色体
    rndDNA = function(n)
    {
        return( seq(1,n,1) )  #随机生成n条旅行路径
    }
     
    #对一个解计算总路程的距离
    calcScores = function(dna,disM)
    {
        = length(dna)         #城市总数
        tmp = cbind(dna[1:n],c(dna[2:n],dna[1])) #生成起始点城市
        len = apply(tmp,1,function(x) disM[x[1],x[2]])
        len = sum(len)
        return(len)      #返回此条旅行路径总距离
    }
     
    #根据每条染色体的分数计算权重,并以此抽样
    roller = function(scores,k)
    {
        scores = max(scores)-scores+1
        props = scores/sum(scores)
        = length(scores)
        mxind = which.max(scores)#保留最优染色体
        ans = sample((1:N)[-mxind],k-1,replace = F,prob = props[-mxind])
        return(c(mxind,ans))
    }
     
    #种群中的繁殖过程
    crossEvolve = function(i,nGroup,crossGroup,prop)
    {
        = nGroup[i,]
        = crossGroup[i,]
        = length(a)
        = max(1,trunc(n*prop))
     
        tmpa = a
     
        st = sample(1:n,1)
        ind = st:(st+m)      #indication 指示、索引
        if (st+m>n)
        {
            bind = which(ind>n)
            ind[bind] = ind[bind] %% + 1
        }
        cross = intersect(b,a[ind])
        tmpa[ind] = cross
        return(tmpa)
    }
     
    #染色体的自我变异
    selfVariation = function(dna,prop)
    {
        = length(dna)
        pos = which(runif(n)<prop)
        if (length(pos)==0)
            return(dna)
        pos = sample(pos,1)
        newind = sample((1:n)[-pos],1)
     
        if (pos>newind)
        {
            tmp = dna[newind:n]
            tmp = tmp[-(pos-newind+1)]
            dna[newind] = dna[pos]
            dna[(newind+1):n] = tmp
        }
        else
        {
            tmp = dna[1:newind]
            tmp = tmp[-pos]
            dna[newind] = dna[pos]
            dna[1:(newind-1)] = tmp
        }
        return(dna)
    }
     
    #以某条染色体代表的解做图
    drawIt = function(dots,dna,xlab=NULL,ylab=NULL,main=NULL,sub=NULL,col=NULL)
    {
    #win.graph(width=800, height=800, pointsize=12)
     
        = dots[[1]]
        = dots[[2]]
          = dots[[4]]
          cols=dots[[5]]+10
        if (is.null(main))
        {
            scores = calcScores(dna,dots[[3]])
    #画地图
     plot(border,border="#BBFFFF",col="#FF7F00",ylim = c(1854), panel.first = grid(),
          main=paste("总路程",scores,"公里"),xlab="经度",ylab="纬度",sub=paste('优化结束-第',sub,'代'));
    #增加省会城市坐标点
               points(x,y,pch=19,col=cols)
               text(x,y,z,pos=1,cex=0.5)
          = length(dna)
        for (i in 1:(n-1)){ 
          Sys.sleep(0.3)
          lines(x[dna[i:(i+1)]],y[dna[i:(i+1)]],col="#00FFFF",lwd=3)}
        lines(x[dna[c(n,1)]],y[dna[c(n,1)]],col="#00FFFF",lwd=3)
     
        }
        else{
     
    #画地图
    plot(border,border="#BBFFFF",col="#FF7F00",ylim = c(1854),main=paste("总路程",main,"公里"),
         xlab="经度",ylab="纬度",sub=paste('第',sub,'代'))
    points(x,y,pch=19,col=cols)
    if(sub==1)Sys.sleep(5)
    else{
     
          = length(dna)
        for (i in 1:(n-1)) 
          lines(x[dna[i:(i+1)]],y[dna[i:(i+1)]],col="#00FFFF",lwd=3)
        lines(x[dna[c(n,1)]],y[dna[c(n,1)]],col="#00FFFF",lwd=3)
    }}}
     
     
    #Genetic Algorithm for Traveller Salesman Problem
    GA4TSP = function(dots,initDNA=NULL,N,cp,vp,maxIter,maxStay,maxElite,drawing)
    {
        disM = dots[[3]]
        = nrow(disM)
        if (N %%2 >0)
            = N+1
        Group = t(sapply(rep(n,N),rndDNA))
         
          if (!is.null(initDNA)) Group[1,]=initDNA
             
        maxL = UpperBound(disM)
        stopFlag = FALSE
        iterCount = 1
        stayCount = 0
        allBest = maxL
        eliteBest = maxL
        elite = mat.or.vec(maxElite,n)
        elitecount = 0
        eracount = 0
     
        LastEra = maxL
        outputRecorder = NULL
        GenerationRecorder = NULL
        showScore=FALSE
        eliteInto=FALSE
        #初始化结束
         
        while (!stopFlag)
        {
            cat('Generation:',iterCount,'Era:',eracount,'Elite:',elitecount)
            scores = apply(Group,1,calcScores,disM)
            bestScore = min(scores)
            mind = which.min(scores)
            bestDNA = Group[mind,]#记录最佳染色体
     
            #更新时代、精英的信息
            if (bestScore<eliteBest)
            {
                stayCount = 0
                eliteBest = bestScore
                eliteDNA = bestDNA
                if (eliteBest<allBest)
                {
                    allBest = eliteBest
                    allDNA = eliteDNA
                    outputRecorder = rbind(outputRecorder,allDNA)
                    GenerationRecorder = c(GenerationRecorder,iterCount)
                    if (drawing)
                        drawIt(dots,allDNA,main=as.character(allBest),sub=iterCount)
                }
            }
            else
                stayCount = stayCount+1
     
            if (stayCount == maxStay)
            {
                stayCount = 0
                eliteBest = maxL
                elitecount = elitecount+1
                elite[elitecount,] = eliteDNA
                scores = apply(Group,1,calcScores,disM)
                = which(scores == min(scores))
                nind = sample((1:N)[-a],length(a))
                Group[a,] = Group[nind,]
                eliteInto =TRUE
                scores = apply(Group,1,calcScores,disM)
                bestScore = min(scores)
                mind = which.min(scores)
                bestDNA = Group[mind,]
            }
     
            if (elitecount==maxElite)
            {
                Group[1:elitecount,]=elite
                elite = mat.or.vec(maxElite,n)
                elitecount = 0
                stayCount = 0
                eliteBest = maxL
                eracount = eracount+1
                maxStay = maxStay + 20
                showScore=TRUE
                scores = apply(Group,1,calcScores,disM)
                bestScore = min(scores)
                mind = which.min(scores)
                bestDNA = Group[mind,]
            }
             
            #对种群计算分数,产生繁殖与变异
            succind = roller(scores,N/2
            nGroup = Group[succind,]          #取最优和一半高权重优秀基因
            crossind = sample(succind,N/2)
            crossGroup = Group[crossind,]     #取最优和一半高权重优秀基因,打乱顺序
            crossans = t(sapply(1:(N/2),crossEvolve,nGroup,crossGroup,cp))
            crossGroup = rbind(nGroup,crossans)
     
            Group = t(apply(crossGroup,1,selfVariation,vp))
            if (eliteInto)
                eliteInto = FALSE
            else
                Group[1,] = bestDNA  
     
            stopFlag = (iterCount>=maxIter)
           iterCount = iterCount+1
            cat(' Best:',bestScore,'All:',allBest,'Stay:',paste(stayCount,'/',maxStay,sep=''),' ')
            if (showScore)
            {
                scores = apply(Group,1,calcScores,disM)
                show(scores[1:(N/2)])
                show(scores[(N/2+1):(N)])
                #Sys.sleep(1)
                showScore=FALSE
            }
        }
        if (drawing)
            drawIt(dots,allDNA,sub=maxIter)
     return(list(DNA = outputRecorder,Generation=GenerationRecorder))
    }
     
     
    #生成初始染色体
    CreatDNA = function(data,i)
    {
    hc=hclust(dist(data[,1:2]))
    data(col</code><code class="python keyword">=</code><code class="python plain">cutree(hc,&nbsp;k&nbsp;</code><code class="python keyword">=</code>&nbsp;<code class="python plain">i)&nbsp;</code><code class="python comments">#k&nbsp;=&nbsp;1&nbsp;is&nbsp;trivial</code></div><div class="line number250 index249 alt1"><code class="python plain">INITDNA</code><code class="python keyword">=</code><code class="python plain">data[order(data)col),]
    rownames(INITDNA)=NULL
        return(INITDNA)  
    }

  • 相关阅读:
    Castle 1.0 RC2 尝鲜
    关注 Web Client Software Factory [Weekly Drop 08]
    ASP.NET AJAX入门系列
    Castle 1.0 Release Candidate 2发布
    ASP.NET AJAX入门系列(2):使用ScriptManager控件
    ASP.NET AJAX 1.0 Beta 发布相关文章总结及推荐
    关于ASP.NET AJAX的三个视频
    企业库2.0培训系列课程大纲[意见征询]
    Visual Studio“Orcas”October 2006 CTP版下载
    ASP.NET AJAX入门系列(4):使用UpdatePanel控件(一)
  • 原文地址:https://www.cnblogs.com/zhp2016/p/6005612.html
Copyright © 2011-2022 走看看