天天看点

⚡自组织映射(SOM)神经网络⚡Python实现 |Python技能树征题Minisom

❤九月❤份了,车神哥又回归了校园

❉冬天❉还会远吗

♪推荐一首最近很⚡喜欢⚡的歌♪

❀No Fear In My Heart -朴树❀

⚡自组织映射(SOM)神经网络⚡Python实现 |Python技能树征题Minisom
由于最近在写一篇相关的论文,就说说其中遇到的一些问题吧~

Minisom

之前做过一个对minisom的第三方开源库的介绍,可以点击看

这里

对相应的代码添加了注释:

导入各种库吧

# 导入库
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
import pandas as pd
from minisom import MiniSom
import math
import xlrd
from icecream import ic
from tqdm import tqdm
from openpyxl import load_workbook
import openpyxl
from time import time      

第一步是导入数据的Function,这很简单就不解释了

# 传入数据成DataFrame的矩阵格式
def loaddata(datafile, num_name):
    df = pd.read_excel(datafile, sheet_name=num_name, index_col=0)   # 导入数据

    return df  # 返回值      

由于代码不是很长,就没有按照模块来写了

⚡自组织映射(SOM)神经网络⚡Python实现 |Python技能树征题Minisom

然后是导入源文件及其标签。

说实话,在现实项目中,想要找到不同特征的标签是真的真的真的太难了!!!

不要问为什么,当你实践你就知道了~

# 导入原始数据
# 1.导入训练和测试数据集
datafile = "*********.xls"  # 原始数据文件名
# 2.导入标签数据
y = pd.DataFrame(pd.read_csv('label****.csv'))    # 读取你的标签数据或者原有的标签是最好的

yy = []   # 设置空矩阵

# 循环将标签导入yy矩阵中
for iy in range(y.shape[0]):
    Uy = y.iloc[iy, 0]
    yy.append(int(Uy))

y = yy   # 赋值给y      

再读取每个sheet中的不同特征名称,我的数据集是这样,如果你没有特征名称,最好对其进行标记,这样会更加有效。

# 3.读取特征标签
feature_names = pd.DataFrame(pd.read_excel(datafile, index_col=0)).columns   # 取数据的列:特征标签
class_names = [0, 1]  # 标签名称

feat = []   # 设置空矩阵
# 循环将特征名称添加到feat矩阵中
for tz in range(feature_names.shape[0]):
    tezh = feature_names[tz]

    feat.append(tezh)  # 逐步添加进feat

feature_names = feat   # 赋值给feature_names

print('特征名称:', feature_names)      

由于我的源文件会有很多个sheet,所以需要对每一个sheet进行训练及测试,再进行保存操作,如果你只要一个数据表的话,可以对此进行相应的改进。

# 按照每一个数据Sheet读取每一层的数据
# 读取文件数据集
workbook = xlrd.open_workbook(datafile)  # 打开数据文件
sheets = workbook.sheet_names()   # 读取原始数据的数据表sheet名
SheetNames = []   # 设置空矩阵
# 循环输出
for sheetname in tqdm(sheets):
    print("表格的名称是:", sheetname)
    SheetNames.append(sheetname)   # 循环添加进空矩阵SheetNames中

print('原始数据表的表单名称为:', SheetNames)
num_n = pd.DataFrame(SheetNames).shape[0]  # 获取表单的个数
print('表单的个数为:', num_n)

# 设置空数据表1
dff = pd.DataFrame(columns=["title", "content"])    # 添加列名
dff.to_excel('SOM_Result.xlsx')   # 保存到'SOM_Result.xlsx'

## 设置空数据表2
dff2 = pd.DataFrame(columns=["title1", "content1"])   # 添加列名
dff2.to_excel('SOM_label_result.xlsx')  # 保存到'SOM_label_result.xlsx'

start_time = time()    # 记录设置开始的时间      

接下来也是对我的每一个表单进行循环遍历训练及其测试的过程,如果只需要进行一次,那么只需要取消循环过程,更改其中的一些变量即可。

其中包含SOM的训练及测试,权值矩阵、map、聚类结果的可视化,精确度等操作。

for i_c in range(num_n):
    if i_c < num_n:
        print('程序目前处在第%r层数.' % SheetNames[i_c])
        XMat = loaddata(datafile, num_name=SheetNames[i_c])  # 返回得到浮点型矩阵

        # 设置空数据表1
        dff = pd.DataFrame(columns=["title", "content"])  # 添加列名
        dff.to_excel('SOM_Result_'+ SheetNames[i_c] +'.xlsx')  # 保存到'SOM_Result.xlsx'

        ## 设置空数据表2
        dff2 = pd.DataFrame(columns=["title1", "content1"])  # 添加列名
        dff2.to_excel('SOM_label_result_'+ SheetNames[i_c] +'.xlsx')  # 保存到'SOM_label_result.xlsx'


        X =  XMat.values    # 将DataFrame格式改为np.array矩阵


        # 划分训练集、测试集  7:3
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)  # X为原始数据,y为标签数据,test_size为训练集和测试集划分比例,random_state为选择随机打乱的方式,可设置为0或1方式


        N = X_train.shape[0]  #样本数量
        M = X_train.shape[1]  #维度/特征数量

        '''
        设置超参数
        '''
        size = math.ceil(np.sqrt(5 * np.sqrt(N)))  # 经验公式:决定输出层尺寸
        print("训练样本个数:{}  测试样本个数:{}".format(N, X_test.shape[0]))
        print("输出网格最佳边长为:", size)

        max_iter = 1000  # 迭代次数

        # Initialization and training(初始化及其训练) size为神经元数,M为输入维度/特征数量, learning——rate为学习率
        som = MiniSom(size, size, M, sigma=3, learning_rate=0.5,
                      neighborhood_function='bubble')    # Neighborhood_function’近邻函数‘可选的设置有'gaussian'、'mexican_hat'、'bubble'. 调参的时候可以都试一遍,看效果

        '''
        初始化权值,有2个API
        '''

        som.pca_weights_init(X_train)   # PCA降维初始化

        som.train_batch(X_train, max_iter, verbose=False)  # train_batch 每次按顺序取一个样本,用过最后一个样本后跳回第一个样本,循环直到迭代次数满足max_iter


        winmap = som.labels_map(X_train, y_train)   # 求取获胜神经元

        # 判断样本的类别
        def classify(som,data,winmap):
            from numpy import sum as npsum   # 导入库
            default_class = npsum(list(winmap.values())).most_common()[0][0]   # 获取获胜神经元的值
            result = []   # 设置空矩阵
            for d in data:   # 循环迭代
                win_position = som.winner(d)   # 获胜神经元的权值位置
                if win_position in winmap:    # 判断是否属于获胜神经元
                    result.append(winmap[win_position].most_common()[0][0])  # 将其添加进空矩阵result中
                else:
                    result.append(default_class)   # 若不满足上面的条件则将default_class添加进result中

            print('输出result结果:', result)
            return result   # 返回值

        # 输出混淆矩阵
        y_pred = classify(som, X_test, winmap)   # 调用classify函数
        print(classification_report(y_test, np.array(y_pred)))   # 输出混淆矩阵

        # 绘制各种图
        # U-Matrix
        heatmap = som.distance_map()  #生成U-Matrix
        plt.imshow(heatmap, cmap='bone_r')      #miniSom案例中用的pcolor函数,需要调整坐标
        plt.colorbar()   # 颜色卡

        plt.figure(figsize=(9, 9))   # 设置图像大小
        # 背景上画U-Matrix
        heatmap = som.distance_map()  # 热力图
        plt.pcolor(heatmap, cmap='bone_r')  # plotting the distance map as background 设置样式

        # 定义不同标签的图案标记
        markers = ['o', 's']   # 设置图案样式
        colors = ['C0', 'C1']   # 定义不同标签图案的颜色
        category_color = {'Normal': 'C0',
                          'fault': 'C1',
                          }   # 设置对应字典

        for cnt, xx in enumerate(X_train):  # 迭代获取X_train训练数据
            w = som.winner(xx)  # getting the winner
            # 在样本Heat的地方画上标记
            plt.plot(w[0]+.5, w[1]+.5, markers[y_train[cnt]], markerfacecolor='None',
                     markeredgecolor=colors[y_train[cnt]], markersize=12, markeredgewidth=2) # plot绘制图像,markerfacecolor:标记颜色,markersize:标记尺寸,markeredgewidth:标记宽度
        plt.axis([0, size, 0, size])  # 设置坐标系
        ax = plt.gca()    # 进行坐标轴的移动,gca就是get current axes
        ax.invert_yaxis() #颠倒y轴方向
        legend_elements = [Patch(facecolor=clr,
                                 edgecolor='w',
                                 label=l) for l, clr in category_color.items()]
        plt.legend(handles=legend_elements, loc='center left', bbox_to_anchor=(1, .95))  # 设置图像界面细节
        # plt.show()  # 显示图


        label_name_map_number = {"Normal":0,"Fault":1}

        # 神经元占比饼图
        from matplotlib.gridspec import GridSpec
        plt.figure(figsize=(9, 9))    # 设置图像界面大小
        the_grid = GridSpec(size, size)   # 神经元个数
        for position in winmap.keys():   # 迭代获取获胜神经元位置
            label_fracs = [winmap[position][label] for label in [0,1]]  # 获取标签
            plt.subplot(the_grid[position[1], position[0]], aspect=1)    # 表示把显示界面分割成the_grid[position[1]*position[0]的网格
            patches, texts = plt.pie(label_fracs)    # 用于绘制饼图
            plt.text(position[0]/100, position[1]/100,  str(len(list(winmap[position].elements()))),
                      color='black', fontdict={'weight': 'bold',  'size': 15},
                      va='center', ha='center')  # 给图中加标签
        plt.legend(patches, class_names, loc='center right', bbox_to_anchor=(-1, 9), ncol=3)  # 显示图中的各种标签
        # plt.show()   # 输出显示图像

        # 权重热力图
        plt.figure(figsize=(10, 10))   # 设置图像大小
        for i, f in enumerate(feature_names):  # 迭代循环获取feature_names特征
            plt.subplot(4, 4, i+1)    # 表示把显示界面分割成 4*4 的网格
            plt.title(f)   # 设置标题
            W = som.get_weights()  # 获得权重数据
            plt.imshow(W[:,:,i], cmap='coolwarm')   # 输出热力图,W[:,:,i]变量存储图像,可以是浮点型数组、unit8数组以及PIL图像,参数cmap用于设置热图的Colormap,代表热力块的样式颜色
            plt.colorbar()   # colorbar,颜色卡尺
            plt.xticks(np.arange(size+1))   # 设置主图的横坐标的刻度字体大小
            plt.yticks(np.arange(size+1))   # 设置主图的纵坐标的刻度字体大小

        # plt.show()  # 输出显示图像

        # 保存result——label
        print('开始SOM标签Result保存!')
        df_winmap = pd.DataFrame.from_dict(winmap, orient='index')  # 读取转换winmap
        ic(df_winmap)  # 输出显示df_winmap
        writer1 = pd.ExcelWriter('SOM_label_result_'+ SheetNames[i_c] +'.xlsx', engine='openpyxl')   # 读取'SOM_label_result.xlsx'
        book1 = load_workbook(writer1.path)  # 获取文件路径
        writer1.book = book1  # 赋值
        df_winmap.to_excel(excel_writer=writer1, sheet_name=str(SheetNames[i_c]))  # 建立为数据表
        writer1.save()   # 保存数据表
        writer1.close()  # 关闭数据表
        print('SOM标签Result保存结束!')


        # 保存result_data
        print('开始SOM最终Result坐标保存!')
        winner = som.win_map(X_train, return_indices=True)   # 获取SOM的获胜神经元结果

        my_df = pd.DataFrame.from_dict(winner, orient='index')  # 转换输出赋值给my_df
        ic(my_df)   # 显示输出
        writer = pd.ExcelWriter('SOM_Result_'+ SheetNames[i_c] +'.xlsx', engine='openpyxl')   # 建立数据表'SOM_Result.xlsx'
        book = load_workbook(writer.path)   # 获取文件路径
        writer.book = book   # 赋值
        my_df.to_excel(excel_writer=writer, sheet_name=str(SheetNames[i_c]))   # 保存数据表

        writer.save()   # 保存操作
        writer.close()  # 关闭操作
        print('SOM最终Result坐标保存结束!')      

大体的流程就是这样了,minisom的库训练起来比Matlab快了不知道多少倍,⚡yyds⚡!!!