SOM网络--机器学习(郑捷 著)

SOM是一类“无监督学习”模型,一般的用法是将高维的input数据在低维的空间表示,因此SOM天然是一种降维方法。除了降维,SOM还可以用于数据可视化,以及聚类等应用中[1]
SOM网络结构:
SOM网络结构

  1. 定义
    自组织特征映射神经网络(Self-Organizing Feature Map,也称Kohomen映射),简称为SOM网络,主要用于解决模式识别类的问题。SOM网络属于无监督学习算法,与Kmeans算法相似。所不同的是,SOM网络不需要预先提供聚类数量,类别的数据由网络自动识别出来。它的基本思想是:将距离小的个体集合划分为同一类别,而将距离大的个体集合划分为不同的类别。
  2. 相似性测量
    神经网络的输入模式向量的相似性测量可用向量之间的距离来衡量。常用的方法有欧氏距离法和余弦法两种。
  3. 网络框架
    SOM特点:只有两层,即输入层和输出层。输出层与其他神经网络不同的是,它与同层的神经元之间建立侧向连接,并可以通过权值的学习形成特定的模式。如一维线阵、二维平面阵和三维栅格阵等。对于二维的训练数据,排列一般是二维的平面阵。
    Kohonen认为,一个神经网络接受外界输入模式时,将会分为不同的对应区域,各区域对输入模式有不同的响应特征,而这个过程是自动完成的。SOM网络正是根据这一看法提出的,其特点与人脑的自组织特性相类似
  4. SOM网络实现步骤
    1)输入层网网络
    输入层网络节点与数据集同行数,同列数,但数据集需要归一化。
    2)输出层网络
    一般根据数据集的维度来构建输出层网络。eg:二维情况,希望分为4类,输出层可设计为4*2的矩阵。
    3)权重节点
    根据输入层的数据集的维度和输出层的的预估分类数,定义权重节点的维度。例如,数据集是二维的,权重的行数就定为2,分4类,权重的列数就选4。权重值一般给定一个0-1之间的随机值。
    4)定义学习率
    学习率会影响收敛速度,可以定义一个动态的学习函数,随着迭代次数的增加而收敛。
    例如: = ( + 1.0 ) ( ) 学习函数=最大学习率 -\dfrac{(当前迭代次数+1.0)* (最大学习率-最小学习率)}{最大迭代次数}
    L e a r n r a t e ( i ) = m a x L r a t e ( i + 1.0 ) ( m a x L r a t e m i n L r a t e ) M a x I t e r a t i o n Learn_rate(i)=maxLrate -\dfrac{(i+1.0)* (maxLrate-minLrate)}{MaxIteration}
    5)定义聚类半径函数
    学习半径影聚类效果,可以定义一个动态收缩的半径函数,随着迭代次数的增加而收缩。定义半径函数为:
    例如: = ( + 1.0 ) ( ) 半径函数=最大半径 -\dfrac{(当前迭代次数+1.0)* (最大半径-最小半径)}{最大迭代次数}
    R r a t e ( i ) = m a x R ( i + 1.0 ) ( m a x R m i n R ) M a x I t e r a t i o n R_rate(i)=maxR -\dfrac{(i+1.0)* (maxR-minR)}{MaxIteration}
  5. 聚类过程
    1)接受输入:首先计算本次迭代的学习率和学习半径,并且从训练集中随机选取一个样本。
    2)寻找获胜节点:计算数据集中其他样本与此样本的距离,从中找到点积最小的获胜节点。
    3)计算优胜领域:根据这两个节点计算出聚类的领域,并找出此领域中的所有节点。
    4)调整权值:根据学习率、样本数据调整权重。
    5)根据计算结果,为数据集分配类别和标签。
    6)评估结果:SOM网络属于无监督聚类,输出的结果就是聚类后的标签。如果训练集已经被分好类,即具有分类标签,那么通过新旧标签的比较就可以反映聚类结果的准确度。
# -*- coding:utf-8 -*-

"""
SOM神经网络类,处理SOM聚类
python3
"""
from numpy import *
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
class SOMnet(object):
    def __init__(self):      # 设计网络参数初始值
        self.lratemax = 0.8; # 最大学习率--欧式距离
        self.lratemin = 0.05 # 最小学习率--欧式距离
        self.rmax = 5.0      # 最大聚类半径--根据数据集
        self.rmin = 0.5      # 最小聚类半径--根据数据集
        self.Steps = 1000    # 迭代次数
        self.lratrlist = []  # 学习率收敛曲线
        self.rlist = []      # 学习半径收敛曲线
        self.w = []          # 权重向量组
        self.M = 2           # M*N 表示聚类总数
        self.N = 2           # M,N表示领域的参数
        self.dataMat = []    # 外部导入数据集
        self.classLabel = [] # 聚类后的类别标签
    """
    def loadDataSet(self,filename): # 加载数据文件
        numFeat = len(open(filename).readline().split('\t ')) -1
        fr = open(filename)
        for line in fr.readline():
            lineArr = []
            curLine = line.strip().split("\t")
            lineArr.append(float(curLine[0]))
            lineArr.append(float(curLine[1]))
            #print(shape(lineArr))
            self.dataMat.append(lineArr)
        self.dataMat = mat(self.dataMat)
    """
    def loadDataSet(self, iris):  # 加载数据集
        # 将sklearn中的数据集datasets.load_iris()的特征作分类,每班样品50,样品总数150,维数4
        self.dataMat = iris["data"]
        self.dataMat = mat(self.dataMat)

    """
    def file2matrix(self,path,delimiter):
        recordlsit = []
        fp = open(path)
        content = fp.read()
        fp.close()
        rowlist = content.splitlines()#按行转换为一维表
        # 逐行遍历 结果按分隔符分隔为行向量
        recordlsit = list(map(eval,row.split(delimiter)) for row in rowlist if row.strip())
        self.dataMat = mat(recordlsit)
    """
    def normalize(self, dataMat):  # 数据归一化
        [m, n] = shape(dataMat)
        for i in arange(n - 1):
            dataMat[:, i] = (dataMat[:, i] - mean(dataMat[:, i])) / (std(dataMat[:, i]) + 1.0e-10)
        return dataMat

    def distEclud(self, matA, matB):  # 计算欧式距离
        ma,na = shape(matA)
        mb,nb = shape(matB)
        rtnmat = zeros((ma,nb))
        for i in arange(ma):
            for j in arange(nb):
                rtnmat[i,j]=np.linalg.norm(matA[i,:]-matB[:,j].T)
        return rtnmat


    def init_grid(self):  # 初始化第二层网络
        k=0 # 构建第二层网络模型
        grid = mat(zeros((self.M * self.N,2)))
        for i in arange(self.M):
            for j in arange(self.N):
                grid[k,:] = [i,j]
                k += 1
        return grid

    def ratecalc(self,i): # 学习率 和 聚类半径
        lrate = self.lratemax - ((i+1.0) * (self.lratemax - self.lratemin)) / self.Steps
        r = self.rmax - ((i+1.0) * (self.rmax - self.rmin)) / self.Steps
        return lrate,r

    def trainSOM(self): # SOM网络的实现
        dm,dn = shape(self.dataMat) # 1. 构建输入层网络
        normDataset = self.normalize(self.dataMat) # 归一化数据
        grid = self.init_grid() # 2. 初始化第二层分类网络
        self.w = np.random.rand(dn,self.M*self.N) # 3. 随机初始化两层之间的权值向量
        distM = self.distEclud # 确定距离公式
        # 4. 迭代求解
        if self.Steps < 5*dm:self.Steps = 5*dm  # 设定最小迭代次数
        for i in arange(self.Steps):
            lrate,r = self.ratecalc(i) # 1) 计算当前迭代次数下的学习率和分类半径
            self.lratrlist.append(lrate);self.rlist.append(r)
            # 2) 随机生成样本索引,并抽取一个样本
            k = np.random.randint(0,dm)
            mySample = normDataset[k,:]
            # 3) 计算最优节点:返回最小距离的索引值
            minIndx = (distM(mySample,self.w)).argmin()
            # 4) 计算领域
            d1 = ceil(minIndx/self.M) # 计算此节点在第二层矩阵中的位置
            d2 = mod(minIndx,self.M)
            distMat = distM(mat([d1,d2]),grid.T)
            #nodelindx = (distMat < r).nonzeor()[1] # 获取领域内的所有节点
            nodelindx = np.nonzero((distMat < r))[1] # 获取领域内的所有节点
            for j in arange(shape(self.w)[1]): # 5) 案列更新权重
                if sum(nodelindx == j):
                    self.w[:,j] = self.w[:,j] + lrate * (mySample[0]-self.w[:,j])
        self.classLabel = list(range(dm)) # 分配和存储聚类后的类别标签
        for i in arange(dm):
            dist=distM(normDataset[i, :], self.w)
            print(type(dist))
            #self.classLabel[i] = argmin(distM(normDataset[i,:],self.w))# np.argmin()求最小值的坐标
            #self.classLabel[i] = distM(normDataset[i,:],self.w).argmin()# np.argmin()求最小值的坐标
            self.classLabel[i] = np.argmin(dist)
        self.classLabel = mat(self.classLabel)

    def showCluster(self,plt): # 绘图  显示聚类结果
        lst = unique(self.classLabel.tolist()[0]) # 去除
        i = 0
        for cindx in lst:
            myclass = nonzero(self.classLabel == cindx)[1]
            xx = self.dataMat[myclass].copy()
            if i == 0:plt.plot(xx[:,0],xx[:,1],'bo')
            if i == 1:plt.plot(xx[:,0],xx[:,1],'rd')
            if i == 2: plt.plot(xx[:, 0], xx[:, 1], 'gD')
            if i == 3: plt.plot(xx[:, 0], xx[:, 1], 'c^')
            i += 1
        plt.show()
if __name__ == "__main__":
    # 加载
    SOMNet =  SOMnet()
    iris = load_iris()
    SOMNet.loadDataSet(iris)
    #SOMNet.file2matrix("test.txt",'/t')
    SOMNet.trainSOM()
    print(SOMNet.w)
SOMNet.showCluster(plt)

数据:sklearn.datasets

参考:

1: http://blog.csdn.net/zdy0_2004/article/details/50858864
2. [http://blog.csdn.net/you_are_my_dream/article/details/53441141]
3. http://blog.csdn.net/zdy0_2004/article/details/50858864
4 (http://blog.csdn.net/richard2357/article/details/16882929)

猜你喜欢

转载自blog.csdn.net/jyh_AI/article/details/82024431