遗传算法(Genetic Algorithm)之deap学习笔记(二): 使用GA分类

简介

这篇文章主要内容是对不同类型的鸢尾花进行分类,主要分为三个类型:

  • Versicolor (0)

  • Setosa (1)

  • Virginica (2)

这里只对Versicolor (0)和Setosa (1)使用二分类进行分类。

整理数据集

加载数据集

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()

# Convert it into a Pandas dataframe
iris_data = pd.DataFrame(data= np.c_[iris['data'], iris['target']],
                     columns= iris['feature_names'] + ['target'])

常规的阅读数据集里的各类数据

# 加载前一百个数据
iris_data.head(100)

# 打印数据集的简要摘要
iris_data.info

# 生成描述性统计数据
iris_data.describe(include='all')


# 协方差表示的是两个变量的总体的误差,这与只表示一个变量误差的方差不同。
# 如果两个变量的变化趋势一致,也就是说如果其中一个大于自身的期望值,另外一个也大于自身的期望值,那么两个变量之间的协方差就是正值。
# 如果两个变量的变化趋势相反,即其中一个大于自身的期望值,另外一个却小于自身的期望值,那么两个变量之间的协方差就是负值。 -- 《百度百科》
print('Covariance:')
iris_data.cov()
iris_data.target.value_counts()
# 2    50
# 1    50
# 0    50
# Name: target, dtype: int64
# 这里每种花的个数很平衡,都是50

# 统计每列缺失值的个数
iris_data.isnull().sum()
'''
sepal length (cm)    0
sepal width (cm)     0
petal length (cm)    0
petal width (cm)     0
target               0
dtype: int64
'''

# 这里只对Versicolor和Setosa进行逻辑回归二分类,如果要对三种花都分类的话可以使用Softmax
iris_data = iris_data[ iris_data['target'] < 2 ]
iris_data.target.value_counts()
# 1    50
# 0    50
# Name: target, dtype: int64

这里把数据集分成test和train

# 因为数据集比较小,所以可以使用Stratified方法把数据集分成比例一样的test set和train set
from sklearn.model_selection import StratifiedShuffleSplit

ss = StratifiedShuffleSplit(n_splits = 1, test_size=0.3)
ss.get_n_splits(iris_data)

for train_index, test_index in ss.split(iris_data, iris_data['target']):
    print('Train: ', train_index)
    train_data = iris_data.loc[train_index]
    print('Test:', test_index)
    test_data = iris_data.loc[test_index]

'''
Train:  [32 18 88 87 55 28 84 66 93 37 70 12 45 72  6 31 65  4  7 58 39 17 67 68
 76  2 56 30 34 46 42 71 24  3 13 26 41 69 44 61 11  5 97 91 35 54 29 51
 36 27  1 90 96 16 75 52 38 53 81 10  0 95 89 48 98 64 99 85 80 92]
Test: [94 78 47 23 79 73 22 86 25 33  8 59 74 14 83  9 43 15 62 50 57 60 40 77
 21 49 19 63 82 20]
'''
# 统计一下个数
train_data.target.value_counts()
# 1    35
# 0    35
# Name: target, dtype: int64

test_data.target.value_counts()
# 1    15
# 0    15
# Name: target, dtype: int64

分成目标和特征

y_train = iris_data['target']
X_train = iris_data.drop(labels='target', axis=1)
y_test = iris_data['target']
X_test = iris_data.drop(labels='target', axis=1)

进化算法

from deap import base
from deap import creator
from deap import tools
import random

# 定义个体,特征,族群...,详情可以看我的上一篇博客
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

toolbox = base.Toolbox()
toolbox.register("attr_float", random.uniform, -1.0, 1.0)
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_float, 5)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

定义一个分类函数

我们需要定义一个函数在数据集中的给定行上对个体进行分类。 这里可以使用逻辑回归。 然而,因为我们想要第一个预测(0 或 1)而不是概率,所以我们在 0 处应用阈值,使其成为二元回归。

我们可以将数据集中的四个特征每一个都代表 1 个权重并添加一个intercept。 所以每个个体将有五个基因。

import math

def sigmoid(x):
  return 1 / (1 + math.exp(-x))

def prediction(individual,row):
    regr = individual[0] + sum(i * r for i , r in zip(individual[1:4], row ) )
    return( sigmoid(regr) )

上面函数代表:

y = a + x1w1 + x2w2 + x3w3 + x4w4 + x5w5

y = (sigmoid(y))

a是intercept,xi是特征,wi是权重

def evalAccuracyTrain(individual, X_train, y_train):
    y_pred = [None] * X_train.shape[0]
    
    index = 0
    for i, row in X_train.iterrows():
        y_pred[index] = prediction(individual,row)
        index += 1
        
    # 用training set计算均方误差(MSD)
    diff = (np.array(y_pred) - np.array(y_train)) ** 2
    
    return( sum(diff), )

通常逻辑回归不使用均方误差(常用于线性回归),因为它h会有一些局部最优。 但是,均方误差可以解决现在这个问题。

# 将上面函数添加
toolbox.register("evaluate", evalAccuracyTrain)

使用预估函数前先测试一下

import random
indv1 = [random.random() for iter in range(5)]

y_pred = [None] * iris_data.shape[0]

prediction(indv1,X_train.iloc[50])
# 0.9989328383466446

prediction(indv1,X_train.iloc[50]) > 0.5
# True

现在继续实现GA算法

# 这些函数的具体解释可以看上一篇博客
# 也可以看官网
# https://deap.readthedocs.io/en/master/api/tools.html
toolbox.register("mutate", tools.mutGaussian, mu=0.0, sigma=0.4, indpb=0.2)
toolbox.register("mate", tools.cxOnePoint)
toolbox.register("select", tools.selTournament, tournsize=3)

NGEN, CXPB = 30, 0.2
pop = toolbox.population(n=200)

fitnesses = [toolbox.evaluate(ind, X_train, y_train) for ind in pop]
for ind, fit in zip(pop, fitnesses):
    ind.fitness.values = fit
# 这里会算出30个最佳个体
for g in range(NGEN):
    print("-- Generation %i --" % g)
    offspring = toolbox.select(pop, len(pop))
    offspring = list(map(toolbox.clone, offspring))

    for child1, child2 in zip(offspring[::2], offspring[1::2]):
        if random.random() < CXPB:
            toolbox.mate(child1, child2)
            del child1.fitness.values
            del child2.fitness.values

    for mutant in offspring:
        toolbox.mutate(mutant)
        del mutant.fitness.values

    invalid_inds = [ind for ind in offspring if not ind.fitness.valid]
    fitnesses = [toolbox.evaluate(ind, X_train, y_train) for ind in invalid_inds]
    for ind, fit in zip(invalid_inds, fitnesses):
        ind.fitness.values = fit    
    
    best_ind = tools.selBest(pop, 1)[0]
    print("Best individual is %s, %s" % (best_ind, best_ind.fitness.values))
    pop[:] = offspring

评估

from sklearn.metrics import accuracy_score

y_pred = [None] * X_test.shape[0]
index = 0
for i, row in X_test.iterrows():
    y_pred[index] = prediction(best_ind,row)
    index += 1

y_bin_pred = np.array(y_pred) > 0.5
accuracy = accuracy_score(y_test, y_bin_pred)
print("Accuracy: %.2f%%" % (accuracy * 100.0))

# 百分之百的准确率
# Accuracy: 100.00%

这篇文章主要使用GA和逻辑回归实战实现了简单的二分类。

后面会更新更深层的GA学习内容,欢迎一起学习指正和讨论。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
遗传算法是一种模拟自然进化过程的优化算法,主要用于解决复杂的优化问题。在遗传算法中,通过对个体(解)进行基因操作(交叉、变异等),不断地产生新的个体,并通过选择机制,筛选出适应度高的个体,从而逐步优化得到最优解。 下面是一个简单的遗传算法Python实现代码: ```python import random # 定义适应度函数 def fitness(individual): # 适应度函数为 x^2 的形式,其中 x 为个体的染色体长度 return sum([gene**2 for gene in individual]) # 初始化种群 def init_population(pop_size, gene_size): population = [] for i in range(pop_size): individual = [random.randint(0, 1) for j in range(gene_size)] population.append(individual) return population # 选择操作 def selection(population): # 轮盘赌选择 fitness_values = [fitness(individual) for individual in population] total_fitness = sum(fitness_values) probabilities = [fitness/total_fitness for fitness in fitness_values] selected_population = [] for i in range(len(population)): selected_individual = None while selected_individual is None: for j in range(len(population)): if random.random() < probabilities[j]: selected_individual = population[j] break selected_population.append(selected_individual) return selected_population # 交叉操作 def crossover(parent1, parent2, crossover_rate): # 一点交叉 if random.random() > crossover_rate: return parent1, parent2 crossover_point = random.randint(1, len(parent1)-1) child1 = parent1[:crossover_point] + parent2[crossover_point:] child2 = parent2[:crossover_point] + parent1[crossover_point:] return child1, child2 # 变异操作 def mutation(individual, mutation_rate): # 每个基因以 mutation_rate 的概率发生变异 for i in range(len(individual)): if random.random() < mutation_rate: individual[i] = 1 - individual[i] return individual # 遗传算法 def genetic_algorithm(pop_size, gene_size, max_generation, crossover_rate, mutation_rate): population = init_population(pop_size, gene_size) for i in range(max_generation): population = selection(population) new_population = [] while len(new_population) < pop_size: parent1, parent2 = random.sample(population, 2) child1, child2 = crossover(parent1, parent2, crossover_rate) child1 = mutation(child1, mutation_rate) child2 = mutation(child2, mutation_rate) new_population.append(child1) new_population.append(child2) population = new_population best_individual = min(population, key=lambda individual: fitness(individual)) return best_individual # 测试 best_individual = genetic_algorithm(pop_size=100, gene_size=10, max_generation=1000, crossover_rate=0.8, mutation_rate=0.1) print(best_individual, fitness(best_individual)) ``` 在上面的代码中,定义了适应度函数、初始化种群、选择、交叉、变异等操作,并通过遗传算法不断迭代,最终得到最优解。在测试中,我们设定种群大小为100,染色体长度为10,最大迭代次数为1000,交叉率为0.8,变异率为0.1,得到的最优解为[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],适应度函数的值为0。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值