本文小編為大家詳細(xì)介紹“Python怎么實(shí)現(xiàn)雞群算法”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Python怎么實(shí)現(xiàn)雞群算法”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
從事BGP機(jī)房服務(wù)器托管,服務(wù)器租用,云主機(jī),網(wǎng)站空間,域名注冊(cè),CDN,網(wǎng)絡(luò)代維等服務(wù)。
雞群算法,縮寫為CSO(Chicken Swarm Optimization),盡管具備所謂仿生學(xué)的背景,但實(shí)質(zhì)上是粒子群算法的一個(gè)變體。
簡(jiǎn)單來(lái)說(shuō),粒子群就是一群粒子,每個(gè)粒子都有自己的位置和速度,而且每個(gè)粒子都要受到最佳粒子的吸引,除了這兩條規(guī)則之外,粒子之間完全平等,彼此之間除了位置和速度之外,完全相等。
當(dāng)然,粒子群算法本身也是有仿生學(xué)背景的,據(jù)說(shuō)靈感來(lái)自于鳥群覓食,這個(gè)當(dāng)然不重要,無(wú)非是一群平等的粒子變成了一群平等的鳥罷了。
而雞群算法,則是為這些粒子,或者這些鳥,添加了不同的身份特征,使得彼此之間不再等同。
雞群中至少有三個(gè)階層,分別是公雞、母雞和小雞,每只雞都有其位置和速度。但區(qū)別之處在于,
公雞最神氣,原則上可以隨便踱步,只是有的時(shí)候注意到其他公雞的時(shí)候,會(huì)有搶食的想法,相當(dāng)于隨機(jī)抽選一只其他公雞,對(duì)其位置產(chǎn)生影響。
母雞最憋屈,一方面要接受公雞的領(lǐng)導(dǎo),另一方面還要和其他母雞搶食
小雞最無(wú)憂無(wú)慮,跟著母雞走就是了。
隨著位置關(guān)系的變化,母雞和小雞可能會(huì)逐漸遺忘最初的首領(lǐng),也就是說(shuō)種群關(guān)系可能會(huì)發(fā)生變化。
首先,要實(shí)現(xiàn)一個(gè)雞類,一只雞,有兩種基本屬性,即位置和類別。
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)維參數(shù) self.x = uniRand(*xRange, (N,)) self.best = np.inf self.xBest = np.zeros((N,)) self.kind = kind # 雞的類別 self.order = order # 雞的編號(hào) # 設(shè)置自己的首領(lǐng)公雞 def setCock(self, i): self.cock = i # 設(shè)置自己的監(jiān)護(hù)母雞 def setHen(self, i): self.hen = i
其中kind分為三類,分別是公雞、母雞和小雞。其中,每只母雞都有自己的首領(lǐng)公雞,每只小雞都有自己的監(jiān)護(hù)母雞。
order為這只雞在雞群中的編號(hào),主要在雞群中得以體現(xiàn)。
雞群和粒子群有一個(gè)很大的區(qū)別,后者說(shuō)到底只有一個(gè)群,而雞群中,每個(gè)公雞都有自己的母雞和小雞,相當(dāng)于一個(gè)小群體。但雞和雞之間的關(guān)系,并不取決于雞自己,故而需要在雞群中實(shí)現(xiàn)
randint = np.random.randint class Swarm: # cNum 雞數(shù),是三個(gè)元素的列表,分別是公雞、母雞和小雞數(shù) # N參數(shù)維度 def __init__(self, cNum, N, xRange): self.initCs(cNum, N, xRange) self.bestCS = deepcopy(self.cs) #最佳雞群 self.best = np.inf #全局最優(yōu)值 self.xBest = np.zeros((N,)) #全局最優(yōu)參數(shù) self.N = N def initCs(self, cNum, N, xRange, vRange): self.cs = [] self.cNum = cNum self.cocks = np.arange(cNum[0]) # 公雞編號(hào) self.hens = np.arange(cNum[0], cNum[0]+cNum[1]) #母雞編號(hào) self.chicks = np.arange(cNum[0]+cNum[1], np.sum(cNum)) #小雞編號(hào) 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是初始化雞群的函數(shù),其中母雞、小雞的首領(lǐng)公雞,小雞的監(jiān)護(hù)母雞,都是隨機(jī)生成的。
接下來(lái)就是算法的核心環(huán)節(jié),不同的雞要遵循不同的更新規(guī)則,其中,公雞最瀟灑,其下一步位置只取決于自己,以及另一只隨便挑選的公雞。
公雞
記當(dāng)前這只公雞的編號(hào)是i,隨機(jī)挑選的公雞編號(hào)是j , j=?i,則第i只公雞位置的更新方法為
xi(t+1)=xi(t)⋅(1+r)
其中,r是通過正態(tài)分布生成的隨機(jī)數(shù),可表示為1∼N(0,σ2),其中σ2為
其中f一般叫做適應(yīng)因子,相當(dāng)于將某只雞塞到待搜解的函數(shù)中得到的值。例如要搜索y=2的最小值,如果當(dāng)前這只雞的位置1.5,那么f=1.52=2.25。ε是一個(gè)防止除零錯(cuò)誤的小量。
但需要注意,上文中所有的x,表示的并非一個(gè)標(biāo)量,而是一個(gè)數(shù)組。
其Python實(shí)現(xiàn)為
# 寫在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)
母雞
設(shè)當(dāng)前母雞編號(hào)為i,這只母雞既要追隨首領(lǐng)公雞,又要和其他母雞搶食。
xi(t+1)=xi(t)+k1r1(xc−xi)+k2r2(xj−xi)
其中,xc為其首領(lǐng)公雞,xj為另一只母雞或者公雞。k1,k2為系數(shù),其更新邏輯與公雞的k是一樣的,當(dāng)fi較大時(shí),表示為
代碼實(shí)現(xiàn)為
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 #首領(lǐng)公雞 guarders.remove(i) guarders.remove(c) # 隨機(jī)生成另一只監(jiān)護(hù)雞 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為其監(jiān)護(hù)母雞,r為隨機(jī)數(shù),算法實(shí)現(xiàn)為
def chickStep(self): for i in self.chicks: ci = self.cs[i] ci.x += 2*random()*(self.cs[ci.hen].x-ci.x)
整個(gè)雞群
正所謂,算法源于生活而高于生活,自然界里講求輩分,但在雞群算法里,講究的確是實(shí)力。如果小雞運(yùn)氣爆棚,得到了比公雞還厲害的優(yōu)化結(jié)果,那么這只小雞就會(huì)進(jìn)化成公雞。
也就是說(shuō),每隔一段時(shí)間,雞群里的雞會(huì)被重新安排身份,優(yōu)化效果最好的就是頭領(lǐng)公雞,差一點(diǎn)的是監(jiān)護(hù)母雞,最差的就只能是小雞了。
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)
至此,集群算法的框架算是搭建成功了,接下來(lái)就實(shí)現(xiàn)最關(guān)鍵的部分,優(yōu)化。
其基本邏輯是,輸入一個(gè)待優(yōu)化func,通過將每只雞的位置x帶入到這個(gè)函數(shù)中,得到一個(gè)判定值,最后通過這個(gè)判定值,來(lái)不斷更新雞群。
除了這個(gè)函數(shù)之外,還需要輸入一些其他參數(shù),比如整個(gè)雞群算法的迭代次數(shù),以及雞群更新的頻次等等
# func為待優(yōu)化函數(shù) # N為迭代次數(shù) # T為雞群更新周期 def optimize(self, func, N, T, msgT): for n in range(N): # 計(jì)算優(yōu)化參數(shù) 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可以將當(dāng)前最佳結(jié)果打印出來(lái),其形式為
def printBest(self,n): fitness = [c.best for c in self.cs] best = np.min(fitness) ind = np.where(fitness==best)[0] msg = f"已經(jīng)迭代{n}次,最佳優(yōu)化結(jié)果為{np.min(fitness)},參數(shù)為:\n" msg += ", ".join([f"{x:.6f}" for x in self.cs[ind].x]) print(msg)
算法完成之后,當(dāng)然要找個(gè)函數(shù)測(cè)試一下,測(cè)試函數(shù)為
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)
測(cè)試結(jié)果如下
已經(jīng)迭代4次,最佳優(yōu)化結(jié)果為-5.793762423022024,參數(shù)為:
-6.599526, 3.117137, 5.959538, 7.225785, 5.204990
已經(jīng)迭代9次,最佳優(yōu)化結(jié)果為-10.61594651972434,參數(shù)為:
-7.003724, -5.589730, 0.981409, 12.920325, -19.006112
已經(jīng)迭代14次,最佳優(yōu)化結(jié)果為-9.143596747975293,參數(shù)為:
5.388234, -3.714421, -5.254391, -5.216215, -6.079223
已經(jīng)迭代19次,最佳優(yōu)化結(jié)果為-11.097888385616995,參數(shù)為:
-9.156244, -5.914600, -5.960154, 4.550833, 4.127889
已經(jīng)迭代19次,最佳優(yōu)化結(jié)果為-11.097888385616995,參數(shù)為:
-9.156244, -5.914600, -5.960154, 4.550833, 4.127889
讀到這里,這篇“Python怎么實(shí)現(xiàn)雞群算法”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。