利用遺傳演算法是如何做特徵工程的?
遺傳演算法是計算機科學領域的先進演算法之一,其靈感來自於人類遺傳過程中基因的代代相傳不斷進化。是一種透過模擬自然進化過程搜尋最優解的方法,可用於各種領域。例如,解決NP問題、博弈論、密碼破譯等。
瞭解資料集
這裡資料集是根據
breast cancer
檢查報告來推測樣本是否患有
breast cancer
。569 個樣本,每個樣本有 30 項指標供參考,我們學習出一個模型根據輸入樣本給出一個分類,也就是 2 分類問題,也就是樣本是否患有 breath cancer。
基本思路
其實這裡遺傳演算法解決問題是模型引數空間內搜尋到一組最優引數來作為 LR 模型引數,問題和方法都比較簡單,主要是開啟大家的思路。資料每個樣本有 30 特徵,其實這些特徵可能有些特徵間是相關的,或者有些特徵對最終結果並沒有多大幫助,甚至有可能對預測結果起到反作用。
初始化種群
chromesome 可以看成個體,每一個樣本都是對樣本一個特徵選擇方案
population 是由一定數量的個體組成,我們接下來就是透過不斷迴圈、選擇、交叉和變異這個過程不斷去最佳化種群,也就是最佳化方案。
def
initilization_of_population
(
size
,
n_feat
):
population
=
[]
for
i
in
range
(
size
):
chromosome
=
np
。
ones
(
n_feat
,
dtype
=
np
。
bool
)
chromosome
[:
int
(
0。3
*
n_feat
)]
=
False
np
。
random
。
shuffle
(
chromosome
)
population
。
append
(
chromosome
)
return
population
所謂群體就是解集,種群則由經過基因(gene)編碼的一定數目的個體(individual)組成,所謂個體就是這裡顏色體(chromosome)。這裡 n_feat 需要和資料特徵維數保持一致,
有關上面程式碼出現語法給出點解釋
temp = np。ones(10,dtype=bool)
temp[:int(0。3*10)] = False
print(temp)
np。random。shuffle(temp)
print(temp)
[False False False True True True True True True True]
[ True True True True False False True True False True]
評估種群個體適應度
這個函式有點類似機器學習中目標函式,遺傳演算法中每一條染色體,對應著遺傳演算法的一個解決方案,用適應性函式(fitness function)來衡量這個解決方案的優劣。
def fitness_score(population):
scores = []
for chromosome in population:
#
logmodel。fit(X_train。iloc[:,chromosome],y_train)
predictions = logmodel。predict(X_test。iloc[:,chromosome])
scores。append(accuracy_score(y_test,predictions))
scores, population = np。array(scores), np。array(population)
inds = np。argsort(scores)
return list(scores[inds][::-1]), list(population[inds,:][::-1])
這裡個體主要從樣本眾多特徵中選擇一些特徵進行分析,然後經過特徵篩選的樣本投入到logistic 分類器進行訓練,從而得到一個分類器,用這個分類器進行預測的結果和真實值進行對比來評估每個個體。
選擇
選擇這裡比較簡單,通常不會僅選取最優的個體,而是進行隨機選取只不過選取不適應環境個體機率會小一些
def selection(pop_after_fit,n_parents):
population_nextgen = []
for i in range(n_parents):
population_nextgen。append(pop_after_fit[i])
return population_nextgen
交叉
在生物學中,就是基因重組,這裡就是用個體某一個片段與其他個體同一個位置片段進行對調產生新的個體。
def crossover(pop_after_sel):
population_nextgen=pop_after_sel
for i in range(len(pop_after_sel)):
child=pop_after_sel[i]
child[3:7]=pop_after_sel[(i+1)%len(pop_after_sel)][3:7]
population_nextgen。append(child)
return population_nextgen
變異
這裡所謂變異還是比較好理解,也就是將個體(染色體)某一個位置進行取反,也就是如果原來 True 變異後為 False 反之亦然
def mutation(pop_after_cross,mutation_rate):
population_nextgen = []
for i in range(0,len(pop_after_cross)):
chromosome = pop_after_cross[i]
for j in range(len(chromosome)):
if random。random() < mutation_rate:
chromosome[j]= not chromosome[j]
population_nextgen。append(chromosome)
#print(population_nextgen)
return population_nextgen
迭代過程
迭代過程也是進化的過程,種群透過一次次迭代不斷進化,最佳化引數
def generations(size,n_feat,n_parents,mutation_rate,n_gen,X_train,
X_test, y_train, y_test):
best_chromo= []
best_score= []
# 初始化迭代
population_nextgen=initilization_of_population(size,n_feat)
for i in range(n_gen):
# 200
scores, pop_after_fit = fitness_score(population_nextgen)
print(scores[:2])
# 200 -> 100
pop_after_sel = selection(pop_after_fit,n_parents)
# 100 -> 200
pop_after_cross = crossover(pop_after_sel)
# 200 -> 200
population_nextgen = mutation(pop_after_cross,mutation_rate)
best_chromo。append(pop_after_fit[0])
best_score。append(scores[0])
return best_chromo,best_score
執行程式碼
最後執行
chromo,score=generations(size=200,n_feat=30,n_parents=100,mutation_rate=0。10,
n_gen=38,X_train=X_train,X_test=X_test,y_train=y_train,y_test=y_test)
logmodel。fit(X_train。iloc[:,chromo[-1]],y_train)
predictions = logmodel。predict(X_test。iloc[:,chromo[-1]])
print(“Accuracy score after genetic algorithm is= ”+str(accuracy_score(y_test,predictions)))