遗传算法求解背包问题
其實遺傳算法是一種處理問題的思想,因為遺傳算法整個體系都是在說對于一種問題的處理思路和原則,而不是一個具體的代碼編寫過程。
1. 算法過程
關鍵步驟如下:
(1)基因編碼:在這個過程中,嘗試對一些個體的基因做一個描述,構造這些基因的結構,有點像確定函數自變量的過程。
(2)設計初始群體:在這里需要造一個種群出來,這些種群有很多生物個體但基因不同。
(3)適應度計算(剪枝):這里對那些不符合要求的后代進行剔除,不讓他們產生后代。否則他們產生的后代只會讓計算量更大而對逼近目標沒有增益。
(4)產生下一代:有3種方法,即:直接選擇,基因重組,基因突變
而后回到步驟(3)進行循環,適應度計算,產生下一代,這樣一代一代找下去,直到找到最優解為止。
遺傳算法的應用領域:如TSP問題(旅行商問題),九宮問題,生產調度問題,背包問題等。
2. 背包問題
這里用一個具體的示例來說明遺傳算法的應用。
背包問題是一種組合優化的NP(多項式復雜程度的非確定性問題)完全問題,這類問題的特點很明顯,即“生成問題的一個解通常比驗證一個給定的解需要花更多的時間”。
背包問題的大意是,有N件物品和一個容量為V的背包,第i件物品的重量是w[i],價值是v[i],求解將哪些物品裝入背包可使這些物品的重量總和不超過背包容量,且價值的總和最大。
這種問題就是典型的NP問題,驗證一個猜想的解比算出一組解要快的多。
例:假設有一個背包,可以放置80公斤的物品,此外還有表:
這時如果用普通的算法就有一種是窮舉法,這里還可以實施,但如果有128種物品的話,就不能再用窮舉法了,這時遺傳算法就派上用場了。
(1)基因編碼:一共有6種物品,每種物品的有無可以作為一個獨立的基因片段,如:
假如只有物品2,3,6,這時的染色體是:011001
(2)設計初始群體:
為了計算方便設置初始群體為4個初始生物個體,隨機產生。注意:這里的初始個數的選擇要視具體情況而定,如果初始數量太少可能會導致在向量空間中覆蓋面積過小而導致收斂到了非最優解就終止了算法。
(3)適應度計算:首先適應度計算要用一個適應函數來做標尺,設計適應度的函數為物品的總價值。這里同時還要計算物品的重量,超過80公斤的直接淘汰。然后對剩下的染色體進行一個用類似輪盤賭來進行遴選的過程,每次輪盤轉動中獎的基因組就允許繁殖一次,如果一次都沒中的基因組將無法得到延續。而遴選的原則是從生物多樣化中進行挑選,淘汰比較弱的是可以的,但不建議淘汰的比例太大。
(4)生產下一代
被輪盤賭選中的基因需要進行基因重組產生下一代,計算過程如下:
其實就是把基因片段從中間的某個地方斷開,然后交叉進行組合來形成新的基因,如:
這里基因重組的斷開的位置是可以隨意進行的,同時注意不要一個基因自身和自身去做重組,沒有意義,因為怎樣重組還是自己。
這里先暫不考慮基因突變的情況。。。
(5)迭代計算
這里一代一代用這種規則做下去,直接求重量和價值。這里可以發現一個現象,就是適應度函數的值比上一代的適應度更好了。在迭代的過程中如果發現連續幾代的適應度函數值基本不增加或者甚至減少的情況,那說明函數已經收斂了。其實收斂的速度會受到很多因素而變化,如基因的長度,基因重組時的方案,基因變異的程度,每一代產生個體的數量等。
3. 代碼實現
# coding=utf-8 import random#背包問題 # 物品 重量 價格 X = {1: [10, 15],2: [15, 25],3: [20, 35],4: [25, 45],5: [30, 55],6: [35, 70]}#終止界限 FINISHED_LIMIT = 5#重量界限 WEIGHT_LIMIT = 80#染色體長度 CHROMOSOME_SIZE = 6#遴選次數 SELECT_NUMBER = 4max_last = 0 diff_last = 10000#判斷退出 def is_finished(fitnesses):global max_lastglobal diff_lastmax_current = 0for v in fitnesses:if v[1] > max_current:max_current = v[1]print 'max_current:',max_current # 得到當前最大的價值diff = max_current - max_last # 價值差,也就是適應度的改變的大小# 這里判斷連續兩代的改變量如果都小于5,則停止迭代if diff < FINISHED_LIMIT and diff_last < FINISHED_LIMIT: return Trueelse:diff_last = diffmax_last = max_currentreturn False#初始染色體樣態 def init():chromosome_state1 = '100100'chromosome_state2 = '101010'chromosome_state3 = '010101'chromosome_state4 = '101011'chromosome_states = [chromosome_state1,chromosome_state2,chromosome_state3,chromosome_state4]return chromosome_states#計算適應度 def fitness(chromosome_states):fitnesses = []for chromosome_state in chromosome_states: # 遍歷所有的染色體value_sum = 0 # 物品重量weight_sum = 0 # 物品價值# 將一個可遍歷的數據對象組合為一個索引序列,同時列出數據和數據下標for i, v in enumerate(chromosome_state): # 對染色體中的1,即存在的物品體重和價格求和if int(v) == 1:weight_sum += X[i + 1][0] value_sum += X[i + 1][1]fitnesses.append([value_sum, weight_sum])return fitnesses#篩選 def filter(chromosome_states, fitnesses):#重量大于80的被淘汰index = len(fitnesses) - 1while index >= 0:index -= 1if fitnesses[index][1] > WEIGHT_LIMIT:chromosome_states.pop(index) # 彈出不符合條件的染色體fitnesses.pop(index) # 彈出不符合條件的適應度#print chromosome_states,'\n',fitnesses#遴選selected_index = [0] * len(chromosome_states) # 如果[0]*3得到的是[0,0,0]for i in range(SELECT_NUMBER):# 隨機選擇染色體,然后得到相應的索引j = chromosome_states.index(random.choice(chromosome_states)) selected_index[j] += 1return selected_index# 交叉產生下一代 def crossover(chromosome_states, selected_index):chromosome_states_new = []index = len(chromosome_states) - 1#print 'index:',indexwhile index >= 0: # 遍歷完所有的染色體組的染色體(其中下標-1代表最后一個染色體的索引)print 'index:',indexindex -= 1chromosome_state = chromosome_states.pop(index)print 'chromosome_states_3:',chromosome_states # 彈出后的染色體組print 'chromosome_state:',chromosome_state # 彈出的染色體for i in range(selected_index[index]): chromosome_state_x = random.choice(chromosome_states) # 隨機選擇一個染色體print 'chromosome_state_x:',chromosome_state_xpos = random.choice(range(1, CHROMOSOME_SIZE - 1)) # 隨機[1, 2, 3, 4]其中的一個數print 'pos:',poschromosome_states_new.append(chromosome_state[:pos] + chromosome_state_x[pos:])print 'chromosome_states_new:',chromosome_states_newchromosome_states.insert(index, chromosome_state) # 恢復原染色體組print 'chromosome_states_4:', chromosome_statesreturn chromosome_states_new # 返回得到的新的染色體組if __name__ == '__main__':# 初始群體chromosome_states = init() # 是全局的print 'chromosome_states:',chromosome_statesn = 100 # 迭代次數while n > 0:n -= 1#適應度計算fitnesses = fitness(chromosome_states)#print 'fitnesses:',fitnessesif is_finished(fitnesses):break # 如果符合條件,立刻停止循環print '1:', fitnesses#遴選selected_index = filter(chromosome_states, fitnesses)print '2:', selected_indexprint 'chromosome_states_2:',chromosome_states#產生下一代chromosome_states = crossover(chromosome_states, selected_index)print '3:', chromosome_statesprint str(n)+'..................................' # 迭代次數fitnesses = fitness(chromosome_states)print 'fitnesses:',fitnessesprint chromosome_states運行結果:
chromosome_states: ['100100', '101010', '010101', '101011'] max_current: 95 1: [[60, 35], [105, 60], [140, 75], [175, 95]] 2: [1, 2, 1] chromosome_states_2: ['100100', '101010', '010101'] index: 2 chromosome_states_3: ['100100', '010101'] chromosome_state: 101010 chromosome_state_x: 010101 pos: 4 chromosome_states_new: ['101001'] chromosome_state_x: 100100 pos: 1 chromosome_states_new: ['101001', '100100'] chromosome_states_4: ['100100', '101010', '010101'] index: 1 chromosome_states_3: ['101010', '010101'] chromosome_state: 100100 chromosome_state_x: 010101 pos: 4 chromosome_states_new: ['101001', '100100', '100101'] chromosome_states_4: ['100100', '101010', '010101'] index: 0 chromosome_states_3: ['100100', '101010'] chromosome_state: 010101 chromosome_state_x: 101010 pos: 2 chromosome_states_new: ['101001', '100100', '100101', '011010'] chromosome_states_4: ['100100', '010101', '101010'] 3: ['101001', '100100', '100101', '011010'] 99.................................. max_current: 70 1: [[120, 65], [60, 35], [130, 70], [115, 65]] 2: [1, 2, 0, 1] chromosome_states_2: ['101001', '100100', '100101', '011010'] index: 3 chromosome_states_3: ['101001', '100100', '011010'] chromosome_state: 100101 chromosome_states_4: ['101001', '100100', '100101', '011010'] index: 2 chromosome_states_3: ['101001', '100101', '011010'] chromosome_state: 100100 chromosome_state_x: 011010 pos: 2 chromosome_states_new: ['101010'] chromosome_state_x: 011010 pos: 2 chromosome_states_new: ['101010', '101010'] chromosome_states_4: ['101001', '100100', '100101', '011010'] index: 1 chromosome_states_3: ['100100', '100101', '011010'] chromosome_state: 101001 chromosome_state_x: 100100 pos: 2 chromosome_states_new: ['101010', '101010', '100100'] chromosome_states_4: ['101001', '100100', '100101', '011010'] index: 0 chromosome_states_3: ['101001', '100100', '100101'] chromosome_state: 011010 chromosome_state_x: 100101 pos: 4 chromosome_states_new: ['101010', '101010', '100100', '011001'] chromosome_states_4: ['101001', '100100', '011010', '100101'] 3: ['101010', '101010', '100100', '011001'] 98.................................. max_current: 70 fitnesses: [[105, 60], [105, 60], [60, 35], [130, 70]] ['101010', '101010', '100100', '011001']從運行結果可以看出詳細的運行過程,但每次的運行結果不同,如果基于代碼中的各種條件設置,最終的效果應該是最大的適應度(總價值)為130,即物品2,3,6的組合。
這里用的收斂條件是連續兩代的適應函數最大值不再增加,出現這種情況則判斷為收斂。
4. 筆記
1. Python enumerate() 函數:
enumerate() 函數用于將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,同時列出數據和數據下標,一般用在 for 循環當中。
enumerate(sequence, [start=0]):
- sequence – 一個序列、迭代器或其他支持迭代對象。
- start – 下標起始位置。
- 返回 enumerate(枚舉) 對象
示例:
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter'] >>> tt=enumerate(seasons) <enumerate object at 0x00000000063B1630> >>> tt <enumerate object at 0x00000000063B1678> >>> list(tt) [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] >>> list(enumerate(seasons, start=1)) # 小標從 1 開始 [(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]用在for循環中:
- 普通的for循環
- for 循環使用 enumerate
參考:http://www.runoob.com/python/python-func-enumerate.html
2.
chromosome_states.index(random.choice(chromosome_states))使用:
>>> chromosome_states=['100100', '101010', '010101'] >>> import random >>>chromosome_states.index(random.choice(chromosome_states)) 1 >>> chromosome_states.index(random.choice(chromosome_states)) 0 >>> random.choice(chromosome_states) '101010' >>> chromosome_states.index(random.choice(chromosome_states)) 2 >>> chromosome_states.index(random.choice(chromosome_states)) 0 >>> chromosome_states.index(random.choice(chromosome_states)) 0 >>>參考:《白話大數據與機器學習》
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的遗传算法求解背包问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聚类实例
- 下一篇: 五金店取店名生意红火名大全