【机器学习】自组织映射神经网络

目录

一、引言

二、核心原理与网络结构

三、完整训练流程

四、关键特性

五、优缺点

六、典型应用场景

七、与相关算法对比

八、实现要点与优化方向

九、自组织映射神经网络的Python代码完整实现(代码会自动下载鸢尾花数据集)

十、程序运行结果展示

十一、总结


一、引言

自组织映射(Self-Organizing Map, SOM),又称 Kohonen 网络,是 1982 年由芬兰学者 Teuvo Kohonen 提出的无监督学习神经网络,核心是将高维数据非线性映射到低维(常为二维)网格并保持拓扑结构,兼具聚类、降维和可视化能力。本文将详细介绍自组织映射神经网络的基本原理以及Python代码完整实现。

二、核心原理与网络结构

SOM 基于竞争学习与拓扑保持机制,通过 "竞争 - 合作 - 自适应" 三阶段循环实现自组织学习,其结构简洁且功能明确。

  1. 网络结构
    • 输入层:接收高维输入向量,神经元数量等于数据维度,无计算仅负责数据传递。
    • 输出层:呈规则网格(常见二维矩形 / 六边形),每个神经元对应一个与输入维度相同的权重向量,是映射与计算核心,神经元位置决定拓扑关系。
  2. 核心机制
    • 竞争机制:输入样本与所有输出神经元权重向量计算距离(常用欧氏距离),距离最小者为获胜神经元(BMU)。
    • 合作机制:BMU 通过邻域函数(如高斯函数)激活周围神经元,邻域范围随训练迭代逐渐收缩。
    • 自适应机制:BMU 及其邻域内神经元按更新公式调整权重,使权重向输入样本靠拢,学习率随迭代衰减。权重更新公式:

其中η(t)为学习率,为邻域函数,x(t)为输入样本,为神经元权重。

三、完整训练流程

  1. 初始化 :随机初始化输出层所有神经元权重向量(常与输入数据同分布),设置初始学习率、初始邻域半径、最大迭代次数T。
  2. 迭代训练(竞争→合作→自适应)
    • 随机选取输入样本x。
    • 计算x与各输出神经元权重的距离,确定 BMU。
    • 计算邻域函数,确定参与更新的神经元范围。
    • 按权重更新公式调整 BMU 及邻域内神经元权重。
    • 更新学习率与邻域半径,随迭代线性衰减。
  3. 终止条件:迭代达到最大次数,或权重、学习率 / 邻域半径变化小于设定阈值,网络收敛。

四、关键特性

特性 说明
无监督学习 无需标注数据,仅通过数据内在特征完成映射与聚类
拓扑保持性 高维相似样本在低维映射空间中位置相邻,区别于 K-Means 等传统聚类
非线性映射 实现高维到低维的非线性降维,保留数据流形结构
可视化优势 二维映射结果可直观呈现数据分布与聚类情况,便于分析
竞争学习 神经元间竞争响应输入,BMU 主导权重更新,提升对同类数据敏感度

五、优缺点

  1. 优点
    • 兼具降维、聚类与可视化功能,适合高维数据探索。
    • 拓扑保持性有助于发现数据潜在结构与关联。
    • 无监督学习,降低数据标注成本。
  2. 缺点
    • 训练时间随输出层神经元数量增加而显著增长。
    • 超参数(网格大小、学习率、邻域半径等)需经验调优,影响结果稳定性。
    • 对噪声敏感,需预处理数据。
    • 聚类结果受初始权重影响,可能陷入局部最优,可通过多次初始化缓解。

六、典型应用场景

  1. 数据可视化与探索:将高维数据(如基因表达、图像特征)映射到二维平面,直观展示数据分布与聚类,辅助发现潜在模式。
  2. 聚类分析:用于客户分群、文本聚类、异常检测等,如根据用户行为特征划分客户群体。
  3. 特征提取与降维:作为预处理步骤,提取关键特征并降低数据维度,为后续分类 / 回归任务提供高质量输入。
  4. 信号处理与模式识别:应用于语音识别、图像处理、故障诊断等,如语音信号特征映射与分类。
  5. 推荐系统:通过用户 / 物品特征映射,挖掘相似用户 / 物品,实现精准推荐。

七、与相关算法对比

算法 核心差异 优势 劣势
SOM 拓扑保持,非线性映射 可视化好,揭示数据关联 训练慢,超参数敏感
K-Means 硬聚类,无拓扑保持 训练快,易实现 聚类数需预设,丢失拓扑信息
PCA 线性降维,无聚类 计算高效,去冗余 仅线性映射,无法处理非线性数据
t-SNE 非线性降维,可视化优 降维效果好,适合可视化 训练慢,对参数敏感

八、实现要点与优化方向

  1. 数据预处理:对输入数据标准化 / 归一化,消除量纲影响,提升训练稳定性。
  2. 超参数选择
    • 网格大小:根据数据规模与聚类粒度调整,常用8×8、10×10等。
    • 学习率与邻域半径:初始值需合理,衰减策略可采用线性或指数衰减。
  3. 优化策略
    • 批量训练:每次迭代使用多个样本,提升训练效率。
    • 并行计算:利用 GPU 加速距离计算与权重更新,缩短训练时间。
    • 初始化优化:基于数据分布初始化权重,降低局部最优概率。

九、自组织映射神经网络的Python代码完整实现(代码会自动下载鸢尾花数据集)

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from matplotlib.gridspec import GridSpec
import time
import pandas as pd
import json
import os
from minisom import MiniSom  # 导入minisom库

# ====================== 基础配置 ======================
# 配置中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False
# 创建结果保存目录
save_dir = "som_iris_results"
os.makedirs(save_dir, exist_ok=True)

# ====================== 1. 手动实现SOM类(保留增强版) ======================
class SelfOrganizingMapManual:
    """手动实现SOM"""
    def __init__(self, x_dim, y_dim, input_len, sigma=1.0, learning_rate=0.5, random_seed=None):
        if random_seed is not None:
            np.random.seed(random_seed)
        self.x_dim = x_dim
        self.y_dim = y_dim
        self.input_len = input_len
        self.initial_sigma = sigma
        self.initial_lr = learning_rate
        self.weights = np.random.rand(x_dim, y_dim, input_len)
        self.neuron_coords = np.array([(i, j) for i in range(x_dim) for j in range(y_dim)]).reshape(x_dim, y_dim, 2)
        self.learning_rates = []
        self.sigmas = []
        self.quantization_errors = []
        self.training_time = 0

    def _find_bmu(self, x):
        distances = np.linalg.norm(self.weights - x, axis=2)
        bmu_idx = np.unravel_index(np.argmin(distances), distances.shape)
        min_distance = distances[bmu_idx]
        return bmu_idx, min_distance

    def _decay_functions(self, iteration, max_iter):
        lr = self.initial_lr * np.exp(-iteration / max_iter)
        sigma = self.initial_sigma * np.exp(-iteration / max_iter)
        return lr, sigma

    def _gaussian_neighborhood(self, bmu_coord, sigma):
        bmu_distances = np.linalg.norm(self.neuron_coords - bmu_coord, axis=2)
        neighborhood = np.exp(-(bmu_distances ** 2) / (2 * sigma ** 2))
        return neighborhood

    def update_weights(self, x, iteration, max_iter):
        bmu_coord, min_distance = self._find_bmu(x)
        lr, sigma = self._decay_functions(iteration, max_iter)
        neighborhood = self._gaussian_neighborhood(bmu_coord, sigma)
        neighborhood = neighborhood[:, :, np.newaxis]
        self.weights += lr * neighborhood * (x - self.weights)
        self.learning_rates.append(lr)
        self.sigmas.append(sigma)
        self.quantization_errors.append(min_distance)

    def train(self, data, num_iteration):
        start_time = time.time()
        data_shuffled = data.copy()
        for i in range(num_iteration):
            x = data_shuffled[np.random.randint(0, len(data))]
            self.update_weights(x, i, num_iteration)
        self.training_time = time.time() - start_time
        self.final_quantization_error = np.mean(self.quantization_errors)

    def distance_map(self):
        umatrix = np.zeros((self.x_dim, self.y_dim))
        for i in range(self.x_dim):
            for j in range(self.y_dim):
                neighbors = []
                if i > 0: neighbors.append(self.weights[i-1, j])
                if i < self.x_dim-1: neighbors.append(self.weights[i+1, j])
                if j > 0: neighbors.append(self.weights[i, j-1])
                if j < self.y_dim-1: neighbors.append(self.weights[i, j+1])
                if neighbors:
                    umatrix[i, j] = np.mean(np.linalg.norm(self.weights[i,j] - np.array(neighbors), axis=1))
        return umatrix

    def get_neuron_stats(self, data, target):
        num_classes = len(np.unique(target))
        neuron_samples = np.zeros((self.x_dim, self.y_dim), dtype=int)
        neuron_class_dist = np.zeros((self.x_dim, self.y_dim, num_classes))
        for x, cls in zip(data, target):
            bmu, _ = self._find_bmu(x)
            neuron_samples[bmu] += 1
            neuron_class_dist[bmu, cls] += 1
        return neuron_samples, neuron_class_dist

# ====================== 2. minisom库封装类 ======================
class SelfOrganizingMapMiniSom:
    """minisom库封装"""
    def __init__(self, x_dim, y_dim, input_len, sigma=1.0, learning_rate=0.5, random_seed=None):
        # 初始化minisom核心对象
        self.som = MiniSom(x=x_dim, y=y_dim, input_len=input_len, sigma=sigma,
                          learning_rate=learning_rate, random_seed=random_seed)
        self.x_dim = x_dim
        self.y_dim = y_dim
        self.input_len = input_len
        self.initial_sigma = sigma
        self.initial_lr = learning_rate
        # 对齐手动版的记录变量
        self.learning_rates = []
        self.sigmas = []
        self.quantization_errors = []
        self.training_time = 0
        self.final_quantization_error = 0

    def _find_bmu(self, x):
        """对齐手动版的BMU查找接口"""
        bmu_idx = self.som.winner(x)  # minisom的winner方法返回BMU坐标
        min_distance = np.linalg.norm(self.som.get_weights()[bmu_idx] - x)
        return bmu_idx, min_distance

    def train(self, data, num_iteration):
        """训练(记录学习率、邻域半径、量化误差,对齐手动版)"""
        start_time = time.time()
        # 手动记录训练过程(模拟minisom的内部衰减)
        for i in range(num_iteration):
            # 随机选样本
            x = data[np.random.randint(0, len(data))]
            # 记录量化误差
            _, min_distance = self._find_bmu(x)
            self.quantization_errors.append(min_distance)
            # 计算衰减后的学习率和邻域半径(和手动版一致)
            lr = self.initial_lr * np.exp(-i / num_iteration)
            sigma = self.initial_sigma * np.exp(-i / num_iteration)
            self.learning_rates.append(lr)
            self.sigmas.append(sigma)
        # 执行minisom的训练
        self.som.train_random(data, num_iteration)
        # 记录时间和最终误差
        self.training_time = time.time() - start_time
        self.final_quantization_error = np.mean(self.quantization_errors)

    def distance_map(self):
        """对齐手动版的U-Matrix接口"""
        return self.som.distance_map()

    def get_neuron_stats(self, data, target):
        """对齐手动版的神经元统计接口"""
        num_classes = len(np.unique(target))
        neuron_samples = np.zeros((self.x_dim, self.y_dim), dtype=int)
        neuron_class_dist = np.zeros((self.x_dim, self.y_dim, num_classes))
        for x, cls in zip(data, target):
            bmu, _ = self._find_bmu(x)
            neuron_samples[bmu] += 1
            neuron_class_dist[bmu, cls] += 1
        return neuron_samples, neuron_class_dist

    @property
    def weights(self):
        """对齐手动版的权重属性"""
        return self.som.get_weights()

# ====================== 3. 可视化函数(通用,支持双版本) ======================
def plot_som_analysis(som_model, data_scaled, target, feature_names, class_names, title_prefix, save_path):
    """通用SOM可视化函数"""
    # 统计神经元信息
    neuron_samples, neuron_class_dist = som_model.get_neuron_stats(data_scaled, target)
    # 计算类别纯度
    neuron_purity = np.zeros((som_model.x_dim, som_model.y_dim))
    for i in range(som_model.x_dim):
        for j in range(som_model.y_dim):
            total = neuron_samples[i, j]
            if total > 0:
                neuron_purity[i, j] = np.max(neuron_class_dist[i, j]) / total
            else:
                neuron_purity[i, j] = 0

    # 创建可视化
    fig = plt.figure(figsize=(18, 20))
    gs = GridSpec(3, 2, figure=fig, height_ratios=[1, 1, 1.2])

    # 1. 训练过程监控
    ax1 = fig.add_subplot(gs[0, 0])
    ax1.plot(som_model.learning_rates, label='学习率', color='blue', linewidth=2)
    ax1.plot(np.array(som_model.sigmas)/som_model.initial_sigma*som_model.initial_lr,
             label='邻域半径(归一化)', color='orange', linewidth=2)
    ax1.plot(np.array(som_model.quantization_errors)/np.max(som_model.quantization_errors)*som_model.initial_lr,
             label='量化误差(归一化)', color='red', linestyle='--', linewidth=2)
    ax1.set_title('SOM训练过程监控', fontsize=14, fontweight='bold')
    ax1.set_xlabel('迭代次数', fontsize=12)
    ax1.set_ylabel('数值(归一化)', fontsize=12)
    ax1.legend(fontsize=10)
    ax1.grid(alpha=0.3)

    # 2. U-Matrix距离图
    ax2 = fig.add_subplot(gs[0, 1])
    umatrix = som_model.distance_map()
    im2 = ax2.pcolor(umatrix.T, cmap='coolwarm', shading='auto')
    ax2.set_title('SOM距离图(U-Matrix)', fontsize=14, fontweight='bold')
    ax2.set_xlabel('神经元X坐标', fontsize=12)
    ax2.set_ylabel('神经元Y坐标', fontsize=12)
    cbar2 = plt.colorbar(im2, ax=ax2)
    cbar2.set_label('神经元与邻域的平均距离', fontsize=10)

    # 3. 神经元样本数量
    ax3 = fig.add_subplot(gs[1, 0])
    im3 = ax3.pcolor(neuron_samples.T, cmap='Blues', shading='auto')
    for i in range(som_model.x_dim):
        for j in range(som_model.y_dim):
            ax3.text(i+0.5, j+0.5, str(neuron_samples[i,j]),
                     ha='center', va='center', fontsize=8, fontweight='bold')
    ax3.set_title('神经元样本数量分布', fontsize=14, fontweight='bold')
    ax3.set_xlabel('神经元X坐标', fontsize=12)
    ax3.set_ylabel('神经元Y坐标', fontsize=12)
    cbar3 = plt.colorbar(im3, ax=ax3)
    cbar3.set_label('样本数量', fontsize=10)

    # 4. 类别纯度热力图
    ax4 = fig.add_subplot(gs[1, 1])
    im4 = ax4.pcolor(neuron_purity.T, cmap='Greens', vmin=0, vmax=1, shading='auto')
    for i in range(som_model.x_dim):
        for j in range(som_model.y_dim):
            if neuron_samples[i,j] > 0:
                ax4.text(i+0.5, j+0.5, f'{neuron_purity[i,j]:.2f}',
                         ha='center', va='center', fontsize=8, fontweight='bold')
    ax4.set_title('神经元类别纯度(最大类别占比)', fontsize=14, fontweight='bold')
    ax4.set_xlabel('神经元X坐标', fontsize=12)
    ax4.set_ylabel('神经元Y坐标', fontsize=12)
    cbar4 = plt.colorbar(im4, ax=ax4)
    cbar4.set_label('纯度(0=混杂,1=纯类别)', fontsize=10)

    # 5. 神经元权重特征分布
    ax5 = fig.add_subplot(gs[2, 0])
    weights_flat = som_model.weights.reshape(-1, som_model.input_len)
    im5 = ax5.pcolor(weights_flat.T, cmap='viridis', shading='auto')
    ax5.set_yticks(np.arange(som_model.input_len)+0.5)
    ax5.set_yticklabels(feature_names, fontsize=10)
    ax5.set_xticks(np.arange(0, som_model.x_dim*som_model.y_dim, 10)+5)
    ax5.set_xticklabels([f'({i},0)' for i in range(som_model.x_dim)], fontsize=8)
    ax5.set_title('神经元权重特征分布', fontsize=14, fontweight='bold')
    ax5.set_xlabel('神经元(按X=0~9,Y=0~9顺序)', fontsize=12)
    ax5.set_ylabel('鸢尾花特征', fontsize=12)
    cbar5 = plt.colorbar(im5, ax=ax5)
    cbar5.set_label('标准化后的特征权重', fontsize=10)

    # 6. 类别映射图
    ax6 = fig.add_subplot(gs[2, 1])
    ax6.pcolor(umatrix.T, cmap='coolwarm', alpha=0.3, shading='auto')
    markers = ['o', 's', 'D']
    colors = ['red', 'green', 'blue']
    for cls in range(3):
        cls_data = data_scaled[target == cls]
        bmu_coords = [som_model._find_bmu(x)[0] for x in cls_data]
        bmu_x = [c[0]+0.5 for c in bmu_coords]
        bmu_y = [c[1]+0.5 for c in bmu_coords]
        ax6.scatter(bmu_x, bmu_y, marker=markers[cls], color=colors[cls],
                    label=class_names[cls], s=60, edgecolors='black', alpha=0.8)
    ax6.set_title('SOM类别映射图', fontsize=14, fontweight='bold')
    ax6.set_xlabel('神经元X坐标', fontsize=12)
    ax6.set_ylabel('神经元Y坐标', fontsize=12)
    ax6.legend(fontsize=10, loc='upper right')

    # 整体标题
    fig.suptitle(f'{title_prefix} - 鸢尾花数据集SOM深度分析', fontsize=18, fontweight='bold')
    plt.tight_layout()
    # 保存图表
    plt.savefig(save_path, dpi=300, bbox_inches='tight')
    plt.show()

    # 返回纯度用于对比
    return np.mean(neuron_purity[neuron_samples > 0])

# ====================== 4. 数据加载与预处理 ======================
iris = load_iris()
data = iris.data
target = iris.target
feature_names = iris.feature_names
class_names = iris.target_names

scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)

# ====================== 5. 训练双版本SOM ======================
# 公共参数
som_x, som_y = 10, 10
input_len = data_scaled.shape[1]
sigma = 1.0
learning_rate = 0.5
max_iter = 1000
random_seed = 42

# 5.1 训练手动版
print("开始训练手动实现的SOM...")
som_manual = SelfOrganizingMapManual(x_dim=som_x, y_dim=som_y, input_len=input_len,
                                     sigma=sigma, learning_rate=learning_rate, random_seed=random_seed)
som_manual.train(data_scaled, num_iteration=max_iter)
# 手动版可视化+保存
manual_avg_purity = plot_som_analysis(
    som_model=som_manual,
    data_scaled=data_scaled,
    target=target,
    feature_names=feature_names,
    class_names=class_names,
    title_prefix="手动实现版",
    save_path=os.path.join(save_dir, "som_manual_iris.png")
)

# 5.2 训练minisom版
print("开始训练minisom库版SOM...")
som_minisom = SelfOrganizingMapMiniSom(x_dim=som_x, y_dim=som_y, input_len=input_len,
                                       sigma=sigma, learning_rate=learning_rate, random_seed=random_seed)
som_minisom.train(data_scaled, num_iteration=max_iter)
# minisom版可视化+保存
minisom_avg_purity = plot_som_analysis(
    som_model=som_minisom,
    data_scaled=data_scaled,
    target=target,
    feature_names=feature_names,
    class_names=class_names,
    title_prefix="minisom库版",
    save_path=os.path.join(save_dir, "som_minisom_iris.png")
)

# ====================== 6. 双版本对比 ======================
# 6.1 量化对比表
comparison_data = {
    "指标": ["最终平均量化误差", "平均类别纯度", "训练时间(秒)", "初始学习率", "初始邻域半径", "迭代次数"],
    "手动实现版": [
        round(som_manual.final_quantization_error, 4),
        round(manual_avg_purity, 4),
        round(som_manual.training_time, 4),
        som_manual.initial_lr,
        som_manual.initial_sigma,
        max_iter
    ],
    "minisom库版": [
        round(som_minisom.final_quantization_error, 4),
        round(minisom_avg_purity, 4),
        round(som_minisom.training_time, 4),
        som_minisom.initial_lr,
        som_minisom.initial_sigma,
        max_iter
    ]
}
# 保存对比表为CSV
comparison_df = pd.DataFrame(comparison_data)
comparison_df.to_csv(os.path.join(save_dir, "som_comparison.csv"), index=False, encoding="utf-8-sig")

# 6.2 打印对比结果
print("\n====================== 双版本SOM对比结果 ======================")
print(comparison_df.to_string(index=False))

# 6.3 核心结果持久化(JSON)
results = {
    "手动版": {
        "final_quantization_error": som_manual.final_quantization_error,
        "avg_class_purity": manual_avg_purity,
        "training_time": som_manual.training_time,
        "neuron_samples": som_manual.get_neuron_stats(data_scaled, target)[0].tolist()
    },
    "minisom版": {
        "final_quantization_error": som_minisom.final_quantization_error,
        "avg_class_purity": minisom_avg_purity,
        "training_time": som_minisom.training_time,
        "neuron_samples": som_minisom.get_neuron_stats(data_scaled, target)[0].tolist()
    },
    "参数配置": {
        "som_size": f"{som_x}x{som_y}",
        "sigma": sigma,
        "learning_rate": learning_rate,
        "max_iter": max_iter
    }
}
with open(os.path.join(save_dir, "som_results.json"), "w", encoding="utf-8") as f:
    json.dump(results, f, ensure_ascii=False, indent=4)

# 6.4 训练时间对比可视化
fig, ax = plt.subplots(figsize=(8, 5))
methods = ["手动实现版", "minisom库版"]
times = [som_manual.training_time, som_minisom.training_time]
colors = ["#1f77b4", "#ff7f0e"]
bars = ax.bar(methods, times, color=colors, width=0.6)
# 添加数值标签
for bar, t in zip(bars, times):
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.01,
            f"{t:.4f}秒", ha='center', va='bottom', fontweight='bold')
ax.set_title("SOM双版本训练时间对比", fontsize=14, fontweight='bold')
ax.set_ylabel("训练时间(秒)", fontsize=12)
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig(os.path.join(save_dir, "som_training_time_comparison.png"), dpi=300, bbox_inches='tight')
plt.show()

# ====================== 7. 输出最终提示 ======================
print(f"\n所有结果已保存至目录:{os.path.abspath(save_dir)}")
print("保存内容包括:")
print("1. 手动版SOM可视化图表(som_manual_iris.png)")
print("2. minisom库版SOM可视化图表(som_minisom_iris.png)")
print("3. 双版本量化对比表(som_comparison.csv)")
print("4. 核心结果JSON文件(som_results.json)")
print("5. 训练时间对比图(som_training_time_comparison.png)")

十、程序运行结果展示

开始训练手动实现的SOM...

开始训练minisom库版SOM...

====================== 双版本SOM对比结果 ======================

指标 手动实现版 minisom库版

最终平均量化误差 0.3055 1.0757

平均类别纯度 1.7025 1.7024

训练时间(秒) 0.0340 0.0510

初始学习率 0.5000 0.5000

初始邻域半径 1.0000 1.0000

迭代次数 1000.0000 1000.0000

所有结果已保存至目录:C:\Users\ABC\PycharmProjects\PythonProject41\som_iris_results

保存内容包括:

  1. 手动版SOM可视化图表(som_manual_iris.png)
  1. minisom库版SOM可视化图表(som_minisom_iris.png)
  1. 双版本量化对比表(som_comparison.csv)
  1. 核心结果JSON文件(som_results.json)
bash 复制代码
{
    "手动版": {
        "final_quantization_error": 0.30554112518960386,
        "avg_class_purity": 1.7025316455696207,
        "training_time": 0.03400135040283203,
        "neuron_samples": [
            [
                1,
                1,
                2,
                2,
                1,
                1,
                3,
                0,
                4,
                2
            ],
            [
                1,
                0,
                2,
                2,
                0,
                0,
                1,
                1,
                1,
                2
            ],
            [
                1,
                3,
                2,
                1,
                2,
                2,
                0,
                2,
                3,
                3
            ],
            [
                3,
                1,
                2,
                1,
                1,
                1,
                3,
                1,
                3,
                1
            ],
            [
                0,
                0,
                1,
                2,
                1,
                3,
                1,
                0,
                1,
                2
            ],
            [
                2,
                1,
                0,
                0,
                1,
                2,
                2,
                2,
                2,
                2
            ],
            [
                2,
                0,
                2,
                2,
                1,
                0,
                4,
                1,
                1,
                3
            ],
            [
                2,
                4,
                4,
                2,
                1,
                0,
                1,
                1,
                1,
                1
            ],
            [
                0,
                2,
                1,
                3,
                3,
                4,
                0,
                1,
                0,
                0
            ],
            [
                0,
                2,
                3,
                5,
                3,
                1,
                0,
                0,
                0,
                1
            ]
        ]
    },
    "minisom版": {
        "final_quantization_error": 1.075708283214084,
        "avg_class_purity": 1.7024444444444444,
        "training_time": 0.05095386505126953,
        "neuron_samples": [
            [
                0,
                1,
                0,
                1,
                1,
                1,
                0,
                3,
                4,
                4
            ],
            [
                0,
                3,
                1,
                2,
                1,
                1,
                1,
                1,
                1,
                2
            ],
            [
                2,
                1,
                1,
                2,
                1,
                0,
                1,
                3,
                2,
                1
            ],
            [
                0,
                4,
                0,
                1,
                1,
                0,
                2,
                2,
                1,
                1
            ],
            [
                2,
                0,
                2,
                0,
                1,
                1,
                1,
                2,
                1,
                4
            ],
            [
                0,
                0,
                0,
                0,
                2,
                2,
                1,
                4,
                0,
                0
            ],
            [
                3,
                1,
                1,
                0,
                1,
                3,
                3,
                1,
                4,
                1
            ],
            [
                1,
                3,
                4,
                4,
                0,
                0,
                3,
                1,
                2,
                0
            ],
            [
                3,
                2,
                5,
                2,
                4,
                1,
                0,
                1,
                0,
                1
            ],
            [
                3,
                3,
                2,
                2,
                3,
                3,
                0,
                0,
                0,
                2
            ]
        ]
    },
    "参数配置": {
        "som_size": "10x10",
        "sigma": 1.0,
        "learning_rate": 0.5,
        "max_iter": 1000
    }
}
  1. 训练时间对比图(som_training_time_comparison.png)

十一、总结

本文详细介绍了自组织映射(SOM)神经网络的原理与Python实现。SOM是一种无监督学习算法,通过竞争学习机制将高维数据映射到低维空间,保持拓扑结构。文章包含手动实现和MiniSom库实现两种方式,并应用于鸢尾花数据集进行可视化分析。实验结果显示,手动实现版在量化误差(0.3055 vs 1.0757)和训练时间(0.034s vs 0.051s)上表现更优,但两种实现方式在类别纯度(1.7025 vs 1.7024)上相当。文章还提供了完整的训练过程监控、U-Matrix距离图、神经元样本分布等可视化方法,为数据聚类和降维提供了实用工具。

相关推荐
程序员小远12 小时前
UI自动化测试框架:PO模式+数据驱动
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
权泽谦12 小时前
医疗预测项目:CNN + XGBoost 实战全流程
人工智能·神经网络·cnn
2501_9418053112 小时前
从微服务网关到统一安全治理的互联网工程语法实践与多语言探索
前端·python·算法
汗流浃背了吧,老弟!12 小时前
Transformer-初识
人工智能·深度学习·transformer
源代码•宸12 小时前
Leetcode—1161. 最大层内元素和【中等】
经验分享·算法·leetcode·golang
Lkygo12 小时前
Embedding 和 Reranker 模型
人工智能·embedding·vllm·sglang
竹君子12 小时前
英伟达的AI芯片架构演进的三个阶段
人工智能
Chris_121912 小时前
Halcon学习笔记-Day5
人工智能·笔记·python·学习·机器学习·halcon
蓝程序12 小时前
Spring AI学习 程序接入大模型
java·人工智能·spring
西柚小萌新12 小时前
【论文阅读】--PEACE:基于多模态大语言模型的地质图全息理解赋能框架
人工智能·语言模型·自然语言处理