简介
这篇文章主要内容是对不同类型的鸢尾花进行分类,主要分为三个类型:
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学习内容,欢迎一起学习指正和讨论。