首頁  >  文章  >  後端開發  >  Python如何實作雞群演算法

Python如何實作雞群演算法

WBOY
WBOY轉載
2023-05-10 14:01:151398瀏覽

演算法簡介

雞群演算法,縮寫為CSO(Chicken Swarm Optimization),儘管具備所謂仿生學的背景,但實質上是粒子群演算法的變體。

簡單來說,粒子群就是一群粒子,每個粒子都有自己的位置和速度,而且每個粒子都要受到最佳粒子的吸引,除了這兩個規則之外,粒子之間完全平等,彼此之間除了位置和速度之外,完全相等。

當然,粒子群演算法本身也是有仿生學背景的,據說靈感來自於鳥群覓食,這個當然不重要,無非是一群平等的粒子變成了一群平等的鳥罷了。

而雞群演算法,則是為這些粒子,或者這些鳥,添加了不同的身份特徵,使得彼此之間不再等同。

雞群中至少有三個階層,分別是公雞、母雞和小雞,每隻雞都有其位置和速度。但差別在於,

  • 公雞最神氣,原則上可以隨便踱步,只是有的時候注意到其他公雞的時候,會有搶食的想法,相當於隨機抽選一隻其他公雞,對其位置產生影響。

  • 母雞最憋屈,一方面要接受公雞的領導,另一方面還要和其他母雞搶食

  • 小雞最無憂無慮,跟著母雞走就是了。

隨著地點關係的變化,母雞和小雞可能會逐漸遺忘最初的首領,也就是說族群關係可能會改變。

Python實現雞和雞群

首先,要實作一個雞類,一隻雞,有兩種基本屬性,即位置和類別。

import numpy as np
from random import gauss, random
randint = np.random.randint
uniRand = np.random.uniform

class Chicken:
    def __init__(self, N, xRange, order=0, kind=0):
        # 生成(N)维参数
        self.x = uniRand(*xRange, (N,))
        self.best = np.inf
        self.xBest = np.zeros((N,))
        self.kind = kind            # 鸡的类别
        self.order = order          # 鸡的编号
    
    # 设置自己的首领公鸡
    def setCock(self, i):
        self.cock = i

    # 设置自己的监护母鸡
    def setHen(self, i):
        self.hen = i

其中kind分為三類,分別是公雞、母雞和小雞。其中,每隻母雞都有自己的首領公雞,每隻小雞都有自己的監護母雞。

order為這隻雞在雞群中的編號,主要在雞群中得以體現。

雞群和粒子群有一個很大的區別,後者說到底只有一個群,而雞群中,每個公雞都有自己的母雞和小雞,相當於一個小群體。但雞和雞之間的關係,並不取決於雞自己,故而需要在雞群中實現

randint = np.random.randint
class Swarm:
    # cNum 鸡数,是三个元素的列表,分别是公鸡、母鸡和小鸡数
    # N参数维度
    def __init__(self, cNum, N, xRange):
        self.initCs(cNum, N, xRange)
        self.bestCS = deepcopy(self.cs)     #最佳鸡群
        self.best = np.inf  #全局最优值
        self.xBest = np.zeros((N,)) #全局最优参数
        self.N = N

    def initCs(self, cNum, N, xRange, vRange):
        self.cs = []
        self.cNum = cNum
        self.cocks = np.arange(cNum[0])     # 公鸡编号
        self.hens = np.arange(cNum[0], cNum[0]+cNum[1]) #母鸡编号
        self.chicks = np.arange(cNum[0]+cNum[1], np.sum(cNum))  #小鸡编号
        kinds = np.repeat([0,1,2], cNum)
        for i in range(sum(cNum)):
            self.cs.append(Chicken(N,xRange, vRange, i, kinds[i]))
            if kinds[i] > 0:
                cock = randint(0, cNum[0])
                self.cs[i].setCock(cock)
            if kinds[i] > 1:
                hen = randint(cNum[0], cNum[0]+cNum[1])
                self.cs[i].setHen(hen)

其中,initCs是初始化雞群的函數,其中母雞、小雞的首領公雞,小雞的監護母雞,都是隨機產生的。

雞群更新

接下來就是演算法的核心環節,不同的雞要遵循不同的更新規則,其中,公雞最瀟灑,其下一步位置只取決於自己,以及另一隻隨便挑選的公雞。

公雞

記目前這隻公雞的編號是i,隨機挑選的公雞編號是j , j≠i,則第i隻公雞位置的更新方法為

xi(t 1)=xi(t)⋅(1 r)

其中,r是透過常態分佈生成的隨機數,可表示為1∼N(0,σ2),其中σ2

Python如何實作雞群演算法

其中f一般叫做適應因子,相當於將某隻雞塞到待搜解的函數中所得到的數值。例如要搜尋y=2的最小值,如果目前這隻雞的位置1.5,那麼f=1.52=2.25。 ε是個防止除零錯誤的小量。

但要注意,上文所有的x,表示的並非一個標量,而是一個陣列。

其Python實作為

# 写在Swarm类中
def cockStep(self):
    for i in self.cocks:
        # 第j只公鸡
        j = np.random.randint(self.cNum[0])
        if j==i:
            j = (j+1) % self.cNum[0]
        # 第i只公鸡
        ci = self.cs[i]
        # 第j只公鸡
        cj = self.cs[self.cocks[j]]
        sigma = 1 if cj.best > ci.best else np.exp(
            (cj.best-ci.best)/(np.abs(ci.best)+1e-15))
        ci.x *= 1 + gauss(0, sigma)

母雞

#設目前母雞編號為i,這隻母雞既要追隨首領公雞,又要和其他母雞搶食。

xi(t 1)=xi(t) k1r1(xc−xi) k2r2(xj−xi)

#其中,xc為其首領公雞,xj為另一隻母雞或公雞。 k1,k2為係數,其更新邏輯與公雞的k是一樣的,當fi較大時,表示為

Python如何實作雞群演算法

程式碼實作為

def henStep(self):
    nGuarder = self.cNum[0] + self.cNum[1] - 2
    for i in self.hens:
        guarders = list(self.cocks) + list(self.hens)
        c = self.cs[i].cock     #首领公鸡
        guarders.remove(i)
        guarders.remove(c)
        # 随机生成另一只监护鸡
        j = guarders[np.random.randint(nGuarder)]
        ci = self.cs[i]
        cj = self.cs[j]
        cc = self.cs[c]
        k1, k2 = random(), random()
        if cc.best > ci.best:
            k1 *= np.exp((ci.best-cc.best)/(np.abs(ci.best)+1e-15))
        if cj.best < ci.best:
            k2 *=  np.exp(cj.best-ci.best)
        ci.x += k1*(cc.x-ci.x)+k2*(cj.x-ci.x)

小雞

最後是小雞的更新邏輯,小雞在母雞的周圍找食物,其更新邏輯為

xi(t 1)=xi(t) r(xh(t)−xi(t))

其中,xh為其監護母雞,r為隨機數,演算法實作為

def chickStep(self):
    for i in self.chicks:
        ci = self.cs[i]
        ci.x += 2*random()*(self.cs[ci.hen].x-ci.x)

整隻雞群

正所謂,演算法源自於生活而高於生活,自然界裡講求輩分,但在雞群演算法裡,講究的確是實力。如果小雞運氣爆棚,得到了比公雞還厲害的優化結果,那麼這隻小雞就會進化成公雞。

也就是說,每隔一段時間,雞群裡的雞會被重新安排身份,優化效果最好的就是頭領公雞,差一點的是監護母雞,最差的就只能是小雞了。

def update(self):
    cn = np.sum(self.cNum)
    c1, c2 = self.cNum[0], self.cNum[0]+self.cNum[1]
    fitness = [self.cs[i].best for i in range(cn)]
    index = np.argsort(fitness)
    self.cocks = index[np.arange(c1)]
    self.hens = index[np.arange(c1,c2)]
    self.chicks = index[np.arange(c2,cn)]
    for i in self.cocks:
        self.cs[i].kind = 0
    for i in self.hens:
        self.cs[i].kind = 1
    for i in self.chicks:
        self.cs[i].kind = 2
    for i in range(cn):
        if self.cs[i].kind > 0:
            cock = self.cocks[randint(0, c1)]
            self.cs[i].setCock(cock)
        if self.cs[i].kind > 1:
            hen = self.hens[randint(c1,c2)]
            self.cs[i].setHen(hen)

優化迭代

至此,集群演算法的框架算是搭建成功了,接下來就實現最關鍵的部分,優化。

其基本逻辑是,输入一个待优化func,通过将每只鸡的位置x带入到这个函数中,得到一个判定值,最后通过这个判定值,来不断更新鸡群。

除了这个函数之外,还需要输入一些其他参数,比如整个鸡群算法的迭代次数,以及鸡群更新的频次等等

# func为待优化函数
# N为迭代次数
# T为鸡群更新周期
def optimize(self, func, N, T, msgT):
    for n in range(N):
        # 计算优化参数
        for c in self.cs:
            c.best = func(c.x)
        # 分别更新公鸡、母鸡和小鸡
        self.cockStep()
        self.henStep()
        self.chickStep()
        if (n+1)%T == 0:
            self.update()   #每T次更新一次种群
            self.printBest(n)
    self.printBest(n)

其中,printBest可以将当前最佳结果打印出来,其形式为

def printBest(self,n):
    fitness = [c.best for c in self.cs]
    best = np.min(fitness)
    ind = np.where(fitness==best)[0]
    msg = f"已经迭代{n}次,最佳优化结果为{np.min(fitness)},参数为:\n"
    msg += ", ".join([f"{x:.6f}" for x in self.cs[ind].x])
    print(msg)

测试

算法完成之后,当然要找个函数测试一下,测试函数为

Python如何實作雞群演算法

def test(xs):
    _sum = 0.0
    for i in range(len(xs)):
        _sum = _sum + np.cos((xs[i]*i)/5)*(i+1)
    return _sum

if __name__ == "__main__":
    cNum = [15,20,100]
    s = Swarm(cNum, 5, (-5,5))
    s.optimize(test, 20, 5)

测试结果如下

已经迭代4次,最佳优化结果为-5.793762423022024,参数为:
-6.599526, 3.117137, 5.959538, 7.225785, 5.204990
已经迭代9次,最佳优化结果为-10.61594651972434,参数为:
-7.003724, -5.589730, 0.981409, 12.920325, -19.006112
已经迭代14次,最佳优化结果为-9.143596747975293,参数为:
5.388234, -3.714421, -5.254391, -5.216215, -6.079223
已经迭代19次,最佳优化结果为-11.097888385616995,参数为:
-9.156244, -5.914600, -5.960154, 4.550833, 4.127889
已经迭代19次,最佳优化结果为-11.097888385616995,参数为:
-9.156244, -5.914600, -5.960154, 4.550833, 4.127889

以上是Python如何實作雞群演算法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除