通過遺傳算法來優化特徵工程

瞭解數據集

這裏數據集是根據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)))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章