(四) 計算統(tǒng)計
- Computing Statistics
通常情況下传睹,我們想要在優(yōu)化過程中編輯數(shù)據(jù)惨撇。Statistic模塊可以在任何設計好的目標上改變一些本不可改變的數(shù)據(jù)岳守。為了達到這個目的床绪,需要使用與工具箱中完全相同的語法在靜態(tài)數(shù)據(jù)中注冊統(tǒng)計函數(shù)。
states = tools.Statistics(key = lambda ind : ind.fitness.values)
使用key的第一個參數(shù)作為統(tǒng)計對象迅细。這個key必須支持一個可以在之后被應用到數(shù)據(jù)上的函數(shù)從而得到統(tǒng)計結果。之前的例子使用了fitness.values()中每一個元素的屬性淘邻。
states.register('avg', numpy.mean)
states.register('std', numpy.std)
states.register('min', numpy.min)
states.register('max', numpy.max)
這些統(tǒng)計函數(shù)現(xiàn)在被注冊了茵典。register函數(shù)希望alias(‘名字’)作為第一個屬性以及一個在向量上操作的函數(shù)(numpy.mean)作為第二個屬性。在調(diào)用時宾舅,任何在后面的元素都會傳到函數(shù)上统阿。統(tǒng)計目標的創(chuàng)建已經(jīng)完成彩倚。
- Predefined Algorithms
當使用一個預定義的算法時,例如esSimple()/eaMuPlusLambada()/eaMuCommaLambda()/eaGenerateUpdata()扶平,之前創(chuàng)建的統(tǒng)計目標可以作為算法的屬性帆离。
pop, logbook = algorithms.esSimple(pop, toolbox, cxpb = 0.5, mutpb = 0.2, ngen = 0, stats = stats, verbose = True)
統(tǒng)計將會在每一次迭代中自動的進行計算。詳細參數(shù)在優(yōu)化過程中會打印在屏幕上结澄。一旦算法返回盯质,最終的種群和一個logbook將會返回。在下一節(jié)可以看到更詳細的信息概而。
- Writing Your Own Algorithm
當編寫自己的算法時呼巷,包含統(tǒng)計時十分簡單的。只需要去在需要的目標上編寫統(tǒng)計赎瑰。例如王悍,在一個給定種群上編寫統(tǒng)計需要調(diào)用compile()方法完成。
record = stats.compile(pop)
這些用于編輯函數(shù)的屬性必須在一個迭代元素中餐曼,這樣這些key才會被調(diào)用压储。這里,我們的種群(pop)包含了許多個體源譬。統(tǒng)計目標將會在每一個個體上調(diào)用key函數(shù)獲取fitness.values屬性的值集惋。這個結果數(shù)組的值最終會給到每一個統(tǒng)計函數(shù)并且將結果輸入到record字典中,每一個key都會與相應的函數(shù)相關聯(lián)踩娘。
在你的main函數(shù)中把這個命令放在更新種群之后就可以得到一系列的統(tǒng)計值:標準差-最大值-平均值-最小值刮刑。
- Multi-objective Statistics
正如統(tǒng)計可以通過numpy函數(shù)直接進行計算,所有的目標將會通過默認numpy的屬性聯(lián)合在一起养渴。接下來雷绢,一個需要明確的事情是每一個axis的操作。這會通過給予axis一個額外的屬性作為注冊函數(shù)達成理卑。
stats = tools.Statistics(key=lambda ind: ind.fitness.values)
stats.register("avg", numpy.mean, axis=0)
stats.register("std", numpy.std, axis=0)
stats.register("min", numpy.min, axis=0)
stats.register("max", numpy.max, axis=0)
- Multiple Statistics
計算種群個體的不同屬性也是可以的翘紊。例如,在遺傳程序設計(GP)中除了對適應度統(tǒng)計之外藐唠,對表達式樹的高度統(tǒng)計也是常見的帆疟。一個可以使用多元Statistics目標的函數(shù)是MultiStatistics。
stats_fit = tools.Statistics(ket= lambda ind: ind.fitness.values)
stats_size = tools.Statistics(key = len)
mstats = tools.MultiStatistics(fitness = stats_fit, size = stats_size)
兩個統(tǒng)計目標使用與之前相同的方式被創(chuàng)建宇立。第二個目標將會通過調(diào)用len()獲取每一個個體的長度踪宠。一旦創(chuàng)建完成,統(tǒng)計目標將會被給到MultiStatistics函數(shù)中泄伪,這里地元素都是使用keywords來定義的殴蓬。這些keywords將會提供不同統(tǒng)計量的定義。這些統(tǒng)計函數(shù)僅僅可以在multi-statistics被注冊一次
mstats.register("avg", numpy.mean)
mstats.register("std", numpy.std)
mstats.register("min", numpy.min)
mstats.register("max", numpy.max)
多元統(tǒng)計目標可以給到一個算法當中,或者他們可以以相似的形式運用到單一統(tǒng)計中
record = mstats.compile(pop)
在這種情況下染厅,record就是一個字典的字典類型(嵌套)痘绎。第一個等級包括一些統(tǒng)計信息的關鍵字,第二個等級包括一些預制件相似的簡單統(tǒng)計目標
>>> print(record)
{'fitness': {'std': 1.64, 'max': 6.86, 'avg': 1.71, 'min': 0.166},
'size': {'std': 1.89, 'max': 7, 'avg': 4.54, 'min': 3}}
- Logging Data
一旦數(shù)據(jù)通過統(tǒng)計產(chǎn)生肖粮,我們可以使用Logbook對它進行存儲孤页。Logbook是用來
按時間順序排列的條目(如字典)。它會直接兼容數(shù)據(jù)類型并且返回統(tǒng)計目標涩馆,但是不會被數(shù)據(jù)限制行施。實際上,任何東西都可以包含在日志的條目中魂那。
logbook = tools.Logbook()
logbook.record(gen=0, evals=30, **record)
record()方法采用可變數(shù)字作為參數(shù)蛾号,每一個參數(shù)作為數(shù)據(jù)都會被記錄。在最后一個例子中涯雅,我們保存了一代鲜结,結果的數(shù)量和任何包含在record()中的東西都會通過這個方法產(chǎn)生統(tǒng)計學目標。所有的記錄都會被保存在Logicbook中活逆,直到它被銷毀精刷。在一些列的記錄之后,我們可能會想去調(diào)用logbook中的信息
gen, avg = logbook.select("gen", "avg")
select()方法提供了一種方法去調(diào)用所有的與record中keyword相關的信息蔗候。這個方法采取了可變數(shù)量的字符串元素怒允,就是在record或者statistics中的keywords。這里锈遥,我們調(diào)用代數(shù)和平均適應度纫事,使用一個單獨的select進行調(diào)用。一個logbook是一個可選擇的目標(只要插入數(shù)據(jù)是可選擇的)迷殿,它可以提供一種很好的方法去存儲演化過程中的統(tǒng)計參數(shù)儿礼。
import pickle
pickle.dump(logbook, lb_file)
注意:每一個算法返回的logbook包含著每一代的信息和適應度在整個進化過程中的數(shù)目。
- Printing to Screen
一個logbook可以打印在屏幕或者文檔中庆寺。它的str()方法在第一個key中返回每一個key的頭,同時使用這些keys完成logbook诉字。按照行插入的時間順序排列懦尝,而列將處于未定義的順序。指定順序的最簡單方法是將header屬性設置為指定列順序的字符串列表壤圃。
logbook.header = 'gen', 'avg', 'spam'
結果為
>>>print(logbook)
gen avg spam
0 [ 50, 2 ]
每一個列名包含了沒有明確記錄的列名陵霉,它將會被空著,就像spam一樣彻坛。
一個logbook同樣包含尚未打印的條目的流屬性东囚。
>>> print(logbook.stream)
gen avg spam
0 [ 50.2]
>>> logbook.record(gen=1, evals=15, **record)
>>> print(logbook.stream)
1 [ 50.2]
- Dealing with Multi-statistics
Logbook可以與字典類型合作棺聊,返回MultiStatistics目標侯养。事實上剩檀,它將在chapters中為每一個包含在字典中的子字典記錄數(shù)據(jù),接下來沪猴,一個multi record可以被看做一個record
logbook = tools.Logbook()
logbook.record(gen=0, evals=30, **record)
與列排序不同的一點是辐啄,當我們明確chapters的順序時,它們的內(nèi)容如下
logbook.header = "gen", "evals", "fitness", "size"
logbook.chapters["fitness"].header = "min", "avg", "max"
logbook.chapters["size"].header = "min", "avg", "max"
(看起來就是fitness包含min运嗜、avg壶辜、max担租;size也包含這些,然后它們的輸出就都分別包含這些)
>>> print(logbook)
fitness size
------------------------- ---------------
gen evals min avg max min avg max
0 30 0.165572 1.71136 6.85956 3 4.54 7
這些數(shù)據(jù)的調(diào)用同樣也可以通過chapter進行調(diào)用
gen = logbook.select("gen")
fit_mins = logbook.chapters["fitness"].select("min")
size_avgs = logbook.chapters["size"].select("avg")
迭代次數(shù)阱洪、最小適應度和平均尺寸就可以按照時間順序獲得了菠镇。如果一些數(shù)據(jù)不可用,一個None會出現(xiàn)在向量中利耍。
- Some Plotting Sugar
在優(yōu)化過程中最常用的操作就是在圖中顯示進化過程。Logbook可以有效地執(zhí)行這一操作隘梨。使用選擇方法轴猎,我們可以調(diào)用需要的數(shù)據(jù)并且使用matplotlib去繪制圖形。
gen = logbook.select("gen")
fit_mins = logbook.chapters["fitness"].select("min")
size_avgs = logbook.chapters["size"].select("avg")
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
line1 = ax1.plot(gen, fit_mins, "b-", label="Minimum Fitness")
ax1.set_xlabel("Generation")
ax1.set_ylabel("Fitness", color="b")
for tl in ax1.get_yticklabels():
tl.set_color("b")
ax2 = ax1.twinx()
line2 = ax2.plot(gen, size_avgs, "r-", label="Average Size")
ax2.set_ylabel("Size", color="r")
for tl in ax2.get_yticklabels():
tl.set_color("r")
lns = line1 + line2
labs = [l.get_label() for l in lns]
ax1.legend(lns, labs, loc="center right")
plt.show()
當添加到符號回歸實例時锐峭,它將會給出下面圖像:
10 總結
這一節(jié)主要講的是
1可婶、在迭代過程中輸出統(tǒng)計學信息的方法,包括適應度值矛渴、種群平均數(shù)、方差等等蚕涤。針對不同的目標可以設置多組統(tǒng)計數(shù)據(jù)并行輸出。
2钻趋、在迭代過程中輸出種群信息,將他們保存在文件或者輸出到屏幕上较沪。以及繪制它們在演化過程中的適應度圖像等失仁。