基于遗传算法的特征选择器(以红酒数据集为例)

        我们结合遗传算法与KNN算法设计了基于GA-KNN的红酒特征选择器首先将红酒数据集的不同特征组合数值化为个体的基因序列,初始化种群,经过交叉、变异等进行种群的迭代,以KNN算法的预测正确率为个体的适应值,同时结合网格搜索寻找最优的估计器参数。在迭代过程中对红酒数据集的特征组合进行寻优,排除冗余特征,找出KNN测试结果最好的一组(或几组)特征集合,实现特征降维。

分文件编写,需要提前安装numpy pandas sklearn插件

代码实现如下:

Feature_selection_genetic_algorithm.py

# -*- encoding: utf-8 -*-

import random
import math
import numpy as np
import pandas as pd
from Genetic_algorithm import GA
import matplotlib.pyplot as plt
#import lightgbm as lgb
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV

class FeatureSelection(object):
    def __init__(self, aLifeCount=10):
        self.columns = ['target', 'fixed_acidity', 'volatile_acidity', 'citric_acid', 'residual_sugar', 'chlorides',
                        'free_sulfur_dioxide', 'total_sulfur_dioxide', 'density', 'pH', 'sulphates', 'alcohol']
        self.wine = pd.read_csv("winequality_red.csv", low_memory=False, usecols=self.columns)

       # self.Xtrain, self.Xtest, self.Ytrain, self.Ytest = train_test_split(self.wine , self.wine.target, test_size=0.1)

        self.lifeCount = aLifeCount
        self.ga = GA(aCrossRate=0.6,
                     aMutationRage=0.1,
                     aLifeCount=self.lifeCount,
                     aGeneLenght=len(self.columns) - 1,
                     aMatchFun=self.matchFun())

    def knn_score(self, order):

        #print("order:  " ,order)
        features = self.columns[1:]
        features_name = []
        features_name.append(self.columns[0])
        #print("features:  ", features)
        for index in range(len(order)):
            if order[index] == 1:
                features_name.append(features[index])
        #特征名
        #print("features_name:  " ,features_name)
        params = {
            'boosting': 'gbdt',
            'objective': 'binary',
            'metric': 'auc',
            'train_metric': False,
            'subsample': 0.8,
            'learning_rate': 0.8,
            'num_leaves': 96,
            'num_threads': 4,
            'max_depth': 5,
            'colsample_bytree': 0.8,
            'lambda_l2': 0.01,
            'verbose': -1,  # inhibit print info #
        }
        rounds = 100

        self.Xtrain, self.Xtest, self.Ytrain, self.Ytest = train_test_split(self.wine[features_name],self.wine[features_name].target, test_size=0.4)
        #print("self.wine[features_name]:  ", self.wine[features_name])
        #标准化
        transfer = StandardScaler()
        self.Xtrain = transfer.fit_transform(self.Xtrain)
        #print("self.Xtrain  ", self.Xtrain)
        self.Xtest = transfer.transform(self.Xtest)
        estimator = KNeighborsClassifier()
        # 加入网格搜索与交叉验证
         #参数准备
        param_dict = {"n_neighbors": [1, 3, 5, 7, 9]}
        estimator = GridSearchCV(estimator, param_grid=param_dict, cv=5)
        estimator.fit(self.Xtrain, self.Ytrain)

        # 方法2:计算准确率
        score = estimator.score(self.Xtest,self.Ytest)
        print("score:\n",score)
        # 最佳参数:best_params_
        print("最佳参数:\n", estimator.best_params_)
        # 最佳结果:best_score_
        print("最佳结果:\n", estimator.best_score_)
        # 最佳估计器:best_estimator_
        print("最佳估计器:\n", estimator.best_estimator_)
        # 交叉验证结果:cv_results_
        #print("交叉验证结果:\n", estimator.cv_results_)
        return score

    def matchFun(self):
        return lambda life: self.knn_score(life.gene)
    def run(self, n=0):
        distance_list = []
        generate = [index for index in range(1, n + 1)]
        while n > 0:
            self.ga.next()
            # distance = self.auc_score(self.ga.best.gene)
            distance = self.ga.score                      ####
            distance_list.append(distance)
            print(("第%d代 : 当前最好特征组合的线下验证结果为:%f") % (self.ga.generation, distance))
            n -= 1

        print('当前最好特征组合:')
        string = []
        flag = 0
        features = self.columns[1:]
        for index in self.ga.gene:                                  ####
            if index == 1:
                string.append(features[flag])
            flag += 1
        print(string)
        print('最高knn_score:', self.ga.score)                      ####

        '''画图函数'''
        plt.plot(generate, distance_list)
        plt.xlabel('generation')
        plt.ylabel('knn-score')
        plt.title('generation--knn-score')
        plt.grid()
        plt.show()


def main():
    fs = FeatureSelection(aLifeCount=5)
    rounds = 10    # 算法迭代次数 #
    fs.run(rounds)


if __name__ == '__main__':
    main()

Genetic_algorithm.py

# -*- coding: utf-8 -*-

import copy
import random
from Life import Life
import numpy as np

class GA(object):
    """遗传算法类"""

    def __init__(self, aCrossRate, aMutationRage, aLifeCount, aGeneLenght, aMatchFun=lambda life: 1):
        self.croessRate = aCrossRate  # 交叉概率 #
        self.mutationRate = aMutationRage  # 突变概率 #
        self.lifeCount = aLifeCount   # 个体数 #
        self.geneLenght = aGeneLenght  # 基因长度 #
        self.matchFun = aMatchFun  # 适配函数
        self.lives = []  # 种群
        self.best = None  # 保存这一代中最好的个体
        self.gene = np.random.randint(0, 2, self.geneLenght)  # 保存全局最好的个体 #
        self.score = -1   # 保存全局最高的适应度 #
        self.generation = 0  # 第几代 #
        self.crossCount = 0  # 交叉数量 #
        self.mutationCount = 0  # 突变个数 #
        self.bounds = 0.0  # 适配值之和,用于选择时计算概率
        self.initPopulation()  # 初始化种群 #

    def initPopulation(self):
        """初始化种群"""
        self.lives = []
        for i in range(self.lifeCount):
            gene = np.random.randint(0, 2, self.geneLenght)
            random.shuffle(gene)  # 随机洗牌 #
            life = Life(gene)
            self.lives.append(life)

    def judge(self):
        """评估,计算每一个个体的适配值"""
        self.bounds = 0.0
        self.best = self.lives[0]
        for life in self.lives:
            life.score = self.matchFun(life)
            self.bounds += life.score
            if self.best.score < life.score:     # score为knn_score 越大越好 #
                self.best = life

        if self.score < self.best.score:                          ####
            self.score = copy.deepcopy(self.best.score)           ####
            self.gene = copy.deepcopy(self.best.gene)             ####

        self.best.score = copy.deepcopy(self.score)               ####
        self.best.gene = copy.deepcopy(self.gene)                 ####

    def cross(self, parent1, parent2):
        """
        函数功能:交叉
        函数实现:随机交叉长度为n的片段,n为随机产生
        """
        index1 = random.randint(0, self.geneLenght - 1)  # 随机生成突变起始位置 #
        index2 = random.randint(index1, self.geneLenght - 1)  # 随机生成突变终止位置 #

        for index in range(len(parent1.gene)):
            if (index >= index1) and (index <= index2):
                parent1.gene[index], parent2.gene[index] = parent2.gene[index], parent1.gene[index]

        self.crossCount += 1
        return parent1.gene

    def mutation(self, gene):
        """突变"""
        index1 = random.randint(0, self.geneLenght - 1)
        index2 = random.randint(0, self.geneLenght - 1)
        # 随机选择两个位置的基因交换--变异 #
        newGene = gene[:]  # 产生一个新的基因序列,以免变异的时候影响父种群
        newGene[index1], newGene[index2] = newGene[index2], newGene[index1]
        self.mutationCount += 1
        return newGene

    def getOne(self):
        """选择一个个体"""
        r = random.uniform(0, self.bounds)
        for life in self.lives:
            r -= life.score
            if r <= 0:
                return life

        raise Exception("选择错误", self.bounds)

    def newChild(self):
        """产生新的后代"""
        parent1 = self.getOne()
        rate = random.random()

        # 按概率交叉 #
        if rate < self.croessRate:
            # 交叉 #
            parent2 = self.getOne()
            gene = self.cross(parent1, parent2)
        else:
            gene = parent1.gene

        # 按概率突变 #
        rate = random.random()
        if rate < self.mutationRate:
            gene = self.mutation(gene)

        return Life(gene)

    def next(self):
        """产生下一代"""
        self.judge()
        newLives = []
        # newLives.append(self.best)  # 把最好的个体加入下一代 #
        newLives.append(self.best)  # 把最好的个体加入下一代 #                 ####

        while len(newLives) < self.lifeCount:
            newLives.append(self.newChild())
        self.lives = newLives
        self.generation += 1

Life.py

# -*- encoding: utf-8 -*-

SCORE_NONE = -1

class Life(object):
      """个体类"""
      def __init__(self, aGene=None):
            self.gene = aGene
            self.score = SCORE_NONE  # 初始化生命值 #

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值