SOM是一类“无监督学习”模型,一般的用法是将高维的input数据在低维的空间表示,因此SOM天然是一种降维方法。除了降维,SOM还可以用于数据可视化,以及聚类等应用中[1]
SOM网络结构:
- 定义
自组织特征映射神经网络(Self-Organizing Feature Map,也称Kohomen映射),简称为SOM网络,主要用于解决模式识别类的问题。SOM网络属于无监督学习算法,与Kmeans算法相似。所不同的是,SOM网络不需要预先提供聚类数量,类别的数据由网络自动识别出来。它的基本思想是:将距离小的个体集合划分为同一类别,而将距离大的个体集合划分为不同的类别。 - 相似性测量
神经网络的输入模式向量的相似性测量可用向量之间的距离来衡量。常用的方法有欧氏距离法和余弦法两种。 - 网络框架
SOM特点:只有两层,即输入层和输出层。输出层与其他神经网络不同的是,它与同层的神经元之间建立侧向连接,并可以通过权值的学习形成特定的模式。如一维线阵、二维平面阵和三维栅格阵等。对于二维的训练数据,排列一般是二维的平面阵。
Kohonen认为,一个神经网络接受外界输入模式时,将会分为不同的对应区域,各区域对输入模式有不同的响应特征,而这个过程是自动完成的。SOM网络正是根据这一看法提出的,其特点与人脑的自组织特性相类似 - SOM网络实现步骤
1)输入层网网络
输入层网络节点与数据集同行数,同列数,但数据集需要归一化。
2)输出层网络
一般根据数据集的维度来构建输出层网络。eg:二维情况,希望分为4类,输出层可设计为4*2的矩阵。
3)权重节点
根据输入层的数据集的维度和输出层的的预估分类数,定义权重节点的维度。例如,数据集是二维的,权重的行数就定为2,分4类,权重的列数就选4。权重值一般给定一个0-1之间的随机值。
4)定义学习率
学习率会影响收敛速度,可以定义一个动态的学习函数,随着迭代次数的增加而收敛。
例如: 学 习 函 数 = 最 大 学 习 率 − ( 当 前 迭 代 次 数 + 1.0 ) ∗ ( 最 大 学 习 率 − 最 小 学 习 率 ) 最 大 迭 代 次 数 学习函数=最大学习率 -\dfrac{(当前迭代次数+1.0)* (最大学习率-最小学习率)}{最大迭代次数} 学习函数=最大学习率−最大迭代次数(当前迭代次数+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} Learnrate(i)=maxLrate−MaxIteration(i+1.0)∗(maxLrate−minLrate)
5)定义聚类半径函数
学习半径影聚类效果,可以定义一个动态收缩的半径函数,随着迭代次数的增加而收缩。定义半径函数为:
例如: 半 径 函 数 = 最 大 半 径 − ( 当 前 迭 代 次 数 + 1.0 ) ∗ ( 最 大 半 径 − 最 小 半 径 ) 最 大 迭 代 次 数 半径函数=最大半径 -\dfrac{(当前迭代次数+1.0)* (最大半径-最小半径)}{最大迭代次数} 半径函数=最大半径−最大迭代次数(当前迭代次数+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} Rrate(i)=maxR−MaxIteration(i+1.0)∗(maxR−minR) - 聚类过程
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.youkuaiyun.com/zdy0_2004/article/details/50858864
2. [http://blog.youkuaiyun.com/you_are_my_dream/article/details/53441141]
3. http://blog.youkuaiyun.com/zdy0_2004/article/details/50858864
4 (http://blog.youkuaiyun.com/richard2357/article/details/16882929)