机器学习与智能优化——利用简单遗传算法优化FCM

简介: 机器学习与智能优化——利用简单遗传算法优化FCM

👉写在前面

本文的目的是要探讨利用简单遗传算法优化FCM,为什么要探讨这个话题呢?

因为单纯的FCM在处理大规模数据时,更加容易收敛到局部最优解,而将遗传算法加入后,可以降低FCM收敛到局部最优解的情况。

笔者之前写过两篇文章 《简单遗传算法优化简单一元函数(python)》《好奇的小老鼠——使用FCM对图片像素进行聚类》 ,分别介绍了简单遗传算法SGA和FCM对图像像素的聚类,有兴趣的读者可以阅读参考。本文参考了《MATLAB智能算法30个案例分析(第2版)》中第20章《基于遗传模拟退火算法的聚类算法》的内容,只不过本文只利用了遗传算法对FCM进行了优化,并未加入模拟退火算法相关的内容。

遗传算法和FCM的原理这里就不再赘述,我们直奔主题。

👉聚类数据

本文的聚类数据由400个二维平面上的点组成,这些点构成4个集合,但彼此之间并没有明显的界限。本文通过使用单纯的FCM聚类和SGA优化初始聚类中心点后的FCM聚类来说明SGA的优势。

👉主体思路

利用简单遗传算法优化FCM主要思路是:在每次遗传算法迭代中,将种群中每个个体基因型解码作为FCM的初始聚类中心坐标(实数值坐标),然后根据解码后的初始聚类中心坐标运行FCM本身的优化方法,得到的FCM目标函数值可以作为遗传个体适应度的依据。得到最优初始聚类中心的同时,也就得到了与之对应的最终的最优聚类中心。

👉编码

大家知道,遗传算法中,编码是很重要的一个环节,本文对二维数据点进行聚类,编码是针对FCM的初始聚类中心进行的,将每个聚类中心的每一个维度的坐标值编码为二进制串,然后将其串联,形成最终的个体基因型。如下图,这里是示意图,每个坐标值的基因型长度需根据实际情况而定。

👉适应度函数

遗传个体的基因型通过解码都会都到一组初始聚类中心,把该初始聚类中心带入FCM,运行FCM本身的优化方法,得到该初始聚类中心对应的最佳聚类中心,同时也会得到对应的最佳目标函数值,鉴于FCM的目标函数值越小,聚类效果越好,可以对FCM目标函数值取反,作为遗传个体的适应度。

👉代码

FCM部分代码(fcm.py):

import numpy as np
class FCM:
    def __init__(self, K, m=2, eps=0.05):
        # 聚类个数
        self.K = K
        # 加权参数
        self.m = m
        # 终止容限
        self.eps = eps
        # 最优相似度矩阵
        self.U = None
        # 最终的聚类中心
        self.centers = None
        # 目标函数值
        self.obj_val = None
    def init_by_centers(self, data, centers):
        # 初始化隶属度矩阵
        self.U = np.random.random((len(data), self.K))
        # 样本到聚类中心的距离
        dist = np.zeros((len(data), self.K))
        for i, x in enumerate(data):
            for j, c in enumerate(centers):
                dist[i][j] = np.linalg.norm(x - c, 2)
        # 计算新的隶属度矩阵
        for i, x in enumerate(data):
            for j, c in enumerate(centers):
                self.U[i][j] = 1./np.sum((dist[i][j]/dist[i]) ** (2/(self.m-1)))
        # 最初的目标函数值
        self.obj_val = np.sum((self.U ** self.m) * (dist ** 2))
    def train(self, data):
        if len(data.shape) == 1:
            data = data[:, np.newaxis]
        if self.U is None:
            # 初始化隶属度矩阵
            self.U = np.random.random((len(data), self.K))
            # 保证每个样本属于所有类的概率是1
            self.U = np.divide(self.U, np.sum(self.U, axis=1)[:, np.newaxis])
        while True:
            temp_U = self.U ** self.m
            # 计算聚类中心
            self.centers = np.divide(np.dot(temp_U.T, data), np.sum(temp_U.T, axis=1)[:, np.newaxis])
            # 样本到聚类中心的距离
            dist = np.zeros((len(data), self.K))
            for i, x in enumerate(data):
                for j, c in enumerate(self.centers):
                    dist[i][j] = np.linalg.norm(x - c, 2)
            # 计算新的隶属度矩阵
            for i, x in enumerate(data):
                for j, c in enumerate(self.centers):
                    temp_U[i][j] = 1./np.sum((dist[i][j]/dist[i]) ** (2/(self.m-1)))
            # 判断是否收敛
            if np.sum(abs(temp_U-self.U)) < self.eps:
                break
            # 更新隶属度矩阵
            self.U = temp_U
            # 更新目标函数值
            self.obj_val = np.sum((self.U ** self.m) * (dist ** 2))
        # 返回样本最大隶属度对应的类别
        return np.argmax(self.U, axis=1)
    def __str__(self) -> str:
        return f"K:{self.K}, m:{self.m}, eps:{self.eps}, U:{self.U}, centers:{self.centers}, dist: {self.dist}"

SGA优化FCM部分代码:

import math
from matplotlib import pyplot as plt
import random
import copy
from fcm import *
# 坐标变量的二进制位数
PRECI = 10
# 个体长度
CHROM_LEN = 20
# 种群大小
POP_SIZE = 10
# 最大遗传代数
MAX_GENERATION = 10
# 交叉概率
PC = 0.7
# 变异概率
PM = 0.01
# FCM指数
FCM_M = 2
# FCM容限
FCM_EPS = 10
# 解码用的参数
class FieldD:
    def __init__(self, K, dim, dim_chrom_len, lb, ub):
        # 聚类个数
        self.K = K
        # 维度个数
        self.dim = dim
        # 每个维度坐标的基因型长度
        self.dim_chrom_len = dim_chrom_len
        # 坐标下界
        self.lb = lb
        # 坐标上界
        self.ub = ub
    def __str__(self) -> str:
        return f"K:{self.K}, dim:{self.dim}, dim_chrom_len{self.dim_chrom_len}, lb:{self.lb}, ub:{self.ub}"
# 解码
def bs2rv(chroms, fieldD: FieldD):
    # 2的幂
    two_pow = np.array([2 ** m for m in range(fieldD.dim_chrom_len)])[:, np.newaxis]
    # 所有遗传个体的所有聚类中心坐标
    centers_coordinates = []
    # 遍历所有类别
    for i in range(fieldD.K):
        # 取出每个类别对应的基因型
        center_start = i * fieldD.dim * fieldD.dim_chrom_len
        center_chroms = chroms[:, center_start:center_start + fieldD.dim * fieldD.dim_chrom_len]
        # 所有遗传个体的单个聚类中心坐标
        coordinates = []
        # 遍历所有维度
        for j in range(fieldD.dim):
            # 取出每个维度对应的基因型
            dim_start = j * fieldD.dim_chrom_len
            dim_chroms = center_chroms[:, dim_start:dim_start + fieldD.dim_chrom_len]
            # 计算该维度基因型对应的表现型,即坐标值
            temp = np.dot(dim_chroms[:, ::-1], two_pow)
            dim_val = fieldD.lb + temp * (fieldD.ub - fieldD.lb) / (math.pow(2, fieldD.dim_chrom_len) - 1)
            coordinates.append(dim_val)
        centers_coordinates.append(np.concatenate(tuple(coordinates), axis=1)[:, np.newaxis, :])
    return np.concatenate(tuple(centers_coordinates), axis=1)
# 选择(复制)操作
def select(population, pop_fitness):
    # 新种群
    new_pop = copy.copy(population)
    # 当代个体适应度总和
    fitness_sum = max(np.sum(pop_fitness), 0.0001)
    # 当代个体累计适应度占比
    cfitness = np.divide(pop_fitness, fitness_sum)
    # 计算累计适应度占比
    _triu = np.triu(np.array([1] * POP_SIZE * POP_SIZE).reshape((POP_SIZE, POP_SIZE)))
    afitness = np.dot(cfitness[np.newaxis, :], _triu).flatten()
    # 依据累计适应度占比进行选择复制,随机数大于对应的累计适应度占比,则进行复制
    for k in range(POP_SIZE):
        index = 0
        while index < POP_SIZE and np.random.random() > afitness[index]:
            index += 1
        # 若无法找到要复制的其他个体,则沿用当前个体
        if index < POP_SIZE:
            new_pop[k] = population[index]
    return new_pop
# 交叉操作
def crossover(population):
    # 随机产生个体配对索引,类似于洗牌的效果
    index = [i for i in range(POP_SIZE)]
    for i in range(POP_SIZE):
        point = random.randint(0, POP_SIZE - i - 1)
        temp = index[i]
        index[i] = index[point + i]
        index[point + i] = temp
    # 两个个体进行交叉
    for i in range(0, POP_SIZE, 2):
        if np.random.random() > PC:
            # 随机选择交叉开始位置
            cross_start = np.random.randint(0, CHROM_LEN - 2) + 1
            # 需要交换的基因
            cross_gene1 = population[index[i]][cross_start:]
            cross_gene2 = population[index[i + 1]][cross_start:]
            # 交叉操作
            population[index[i]] = np.array(population[index[i]][0: cross_start].tolist() + cross_gene2.tolist())
            population[index[i + 1]] = np.array(population[index[i + 1]][0: cross_start].tolist() + cross_gene1.tolist())
# 变异操作
def mutation(population):
    for individual in population:
        for i in range(CHROM_LEN):
            # 随机数小于变异概率,则进行变异操作
            if random.random() < PM:
                individual[i] = 1 if individual[i] is 0 else 0
# 绘制进化过程
def draw_evolution(evolution):
    x = [i for i in range(len(evolution))]
    plt.plot(x, evolution)
    # plt.show()
    plt.savefig('fcm_sga_evolution.png', dpi=800)
    plt.close()
# 得到种群所有个体的适应度值
def get_fitness(pop, data, f: FieldD):
    # 解码为初始聚类中心
    centers = bs2rv(pop, f)
    # 所有个体的适应度
    fitness = []
    # 所有个体最终的聚类中心
    final_centers = []
    # 种群中样本类别
    labels = []
    # 循环所有初始聚类中心
    for center in centers:
        # FCM模型
        fcm_model = FCM(K=f.K, m=FCM_M, eps=FCM_EPS)
        # 通过初始聚类中心计算相似度矩阵
        fcm_model.init_by_centers(data, center)
        # 训练
        _y = fcm_model.train(data)
        # 记录信息
        fitness.append(0-np.max([0., fcm_model.obj_val]))
        final_centers.append(fcm_model.centers)
        labels.append(_y)
    return np.array(fitness), np.array(final_centers), np.array(labels)
    
# 绘制结果
def draw_result(data, best_centers, best_labels):
    plt.scatter(data[:, 0], data[:, 1], c=best_labels, alpha=.1, edgecolors='black')
    # 绘制最优解
    plt.scatter(best_centers[:, 0], best_centers[:, 1], s=100, c='red', marker='*', zorder=2)
    # plt.show()
    plt.savefig('fcm_sga.png', dpi=800)
    plt.close()
def run():
    # 样本数量
    N = 400
    # 测试数据
    X = np.random.rand(N, 2)
    # 聚类个数
    cluster_num = 4
    # 维度个数
    dim_num = 2
    #
    #
    # 原始方法优化FCM
    # FCM模型
    my_fcm = FCM(K=cluster_num, m=FCM_M, eps=FCM_EPS)
    # 训练
    y = my_fcm.train(X)
    print("单纯使用FCM聚类的结果:{}".format(my_fcm.obj_val))
    # 绘图
    plt.scatter(X[:, 0], X[:, 1], c=y, alpha=.1, edgecolors='black')
    plt.scatter(my_fcm.centers[:, 0], my_fcm.centers[:, 1], s=100, c='red', marker='*')
    # plt.show()
    plt.savefig('fcm_only.png', dpi=800)
    plt.close()
    #
    #
    # 利用简单遗传算法进行优化
    
    # 下界
    lb = np.min(X)
    # 上界
    ub = np.max(X)
    # 基因型解析参数
    # K, dim, dim_chrom_len, lb, ub
    f = FieldD(cluster_num, dim_num, PRECI, lb, ub)
    global CHROM_LEN
    CHROM_LEN = cluster_num * dim_num * PRECI
    # 初始种群
    population = np.random.randint(2, size=(POP_SIZE, CHROM_LEN))
    # 初始种群适应度
    pop_fitness, pop_centers, pop_labels = get_fitness(population, X, f)
    # 初始种群最佳和最差个体索引
    best_idx, worst_idx = np.argmax(pop_fitness), np.argmin(pop_fitness)
    # 历史最佳个体及其适应度
    current_best = population[best_idx]
    current_best_fit = pop_fitness[best_idx]
    # 最佳初始聚类中心
    best_centers = pop_centers[best_idx]
    # 最初分类结果
    best_labels = pop_labels[best_idx]
    # 进化过程,每一代的最佳个体的函数值
    evolution = []
    # 循环直到最大代数
    for _ in range(MAX_GENERATION):
        # 选择复制
        population = select(population, pop_fitness)
        # 交叉
        crossover(population)
        # 变异
        mutation(population)
        # 重新计算种群适应度
        pop_fitness, pop_centers, pop_labels = get_fitness(population, X, f)
        # 当前种群最佳和最差个体
        best_idx, worst_idx = np.argmax(pop_fitness), np.argmin(pop_fitness)
        # 利用精英模型执行进化操作,用历史最佳个体代替当代的最差个体
        if pop_fitness[best_idx] > current_best_fit:
            current_best = population[best_idx]
            current_best_fit = pop_fitness[best_idx]
            best_centers = pop_centers[best_idx]
            best_labels = pop_labels[best_idx]
        else:
            population[worst_idx] = current_best
        # 更新进化过程
        evolution.append(0-round(current_best_fit, 4))
    print("使用遗传算法优化FCM聚类的结果:{}".format(0-current_best_fit))
    # 绘制进化过程
    draw_evolution(evolution)
    # 绘制结果
    draw_result(X, best_centers, best_labels)
if __name__ == "__main__":
    run()

FCM目标函数值对比:

单纯使用FCM聚类的结果:10.232015239531716
使用遗传算法优化FCM聚类的结果:10.169934869980217

结果显示,使用SGA优化FCM的效果更好。

单纯使用FCM进行聚类效果

使用SGA优化FCM的效果

遗传算法进化过程

作者这水平有限,有不足之处欢迎留言指正

相关文章
|
7天前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
37 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
7天前
|
机器学习/深度学习 安全 网络安全
利用机器学习优化网络安全威胁检测
【9月更文挑战第20天】在数字时代,网络安全成为企业和个人面临的重大挑战。传统的安全措施往往无法有效应对日益复杂的网络攻击手段。本文将探讨如何通过机器学习技术来提升威胁检测的效率和准确性,旨在为读者提供一种创新的视角,以理解和实施机器学习在网络安全中的应用,从而更好地保护数据和系统免受侵害。
|
2天前
|
机器学习/深度学习 算法 物联网
探究操作系统的心脏:调度算法的演变与优化
本文旨在深入探讨操作系统中核心组件——调度算法的发展脉络与优化策略。通过分析从单任务到多任务、实时系统的演进过程,揭示调度算法如何作为系统性能瓶颈的解决关键,以及在云计算和物联网新兴领域中的应用前景。不同于传统摘要,本文将注重于概念阐释与实例分析相结合,为读者提供直观且全面的理解视角。
|
5天前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
17 4
|
8天前
|
机器学习/深度学习 存储 人工智能
文本情感识别分析系统Python+SVM分类算法+机器学习人工智能+计算机毕业设计
使用Python作为开发语言,基于文本数据集(一个积极的xls文本格式和一个消极的xls文本格式文件),使用Word2vec对文本进行处理。通过支持向量机SVM算法训练情绪分类模型。实现对文本消极情感和文本积极情感的识别。并基于Django框架开发网页平台实现对用户的可视化操作和数据存储。
19 0
文本情感识别分析系统Python+SVM分类算法+机器学习人工智能+计算机毕业设计
|
15天前
|
机器学习/深度学习 算法
深度学习中的优化算法:从梯度下降到Adam
本文深入探讨了深度学习中的核心——优化算法,重点分析了梯度下降及其多种变体。通过比较梯度下降、动量方法、AdaGrad、RMSProp以及Adam等算法,揭示了它们如何更高效地找到损失函数的最小值。此外,文章还讨论了不同优化算法在实际模型训练中的表现和选择依据,为深度学习实践提供了宝贵的指导。
37 7
|
7天前
|
算法
基于ACO蚁群优化的UAV最优巡检路线规划算法matlab仿真
该程序基于蚁群优化算法(ACO)为无人机(UAV)规划最优巡检路线,将无人机视作“蚂蚁”,巡检点作为“食物源”,目标是最小化总距离、能耗或时间。使用MATLAB 2022a版本实现,通过迭代更新信息素浓度来优化路径。算法包括初始化信息素矩阵、蚂蚁移动与信息素更新,并在满足终止条件前不断迭代,最终输出最短路径及其长度。
|
10天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于PSO粒子群优化的GroupCNN分组卷积网络时间序列预测算法matlab仿真
本项目展示了一种结合粒子群优化(PSO)与分组卷积神经网络(GroupCNN)的时间序列预测算法。该算法通过PSO寻找最优网络结构和超参数,提高预测准确性与效率。软件基于MATLAB 2022a,提供完整代码及详细中文注释,并附带操作步骤视频。分组卷积有效降低了计算成本,而PSO则智能调整网络参数。此方法特别适用于金融市场预测和天气预报等场景。
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的优化算法
本文将探讨深度学习中的几种常见优化算法,包括梯度下降、动量方法、AdaGrad、RMSProp和Adam。这些算法在训练神经网络时发挥着重要作用,通过调整学习率和更新策略,能够显著提高模型的训练效率和性能。了解这些优化算法有助于更好地应用深度学习技术解决实际问题。
|
18天前
|
算法 Python
群智能算法:灰狼优化算法(GWO)的详细解读
在优化问题中,寻找最优解是核心目标。灰狼优化算法(GWO)受到自然界灰狼狩猎行为和社会等级结构的启发,通过模拟Alpha(头狼)、Beta(助手狼)、Delta(支配狼)和Omega(普通狼)的角色,高效搜索最优解。本文详细解析GWO的原理与步骤,并提供Python代码实现,帮助读者理解并应用这一算法。