机器学习之自组织特征映射神经网络(SOM)python实现

下面为两种SOM的运行代码,用来分类同样的数据,第一种学习率和聚类半径随着迭代次数的变化而变化,参考机器学习之自组织特征映射神经网络(SOM),同时运行博客点这里的代码,比较运行时间,都设置迭代次数为1000次,分4类,运行时间分为为0(即小于1s)和17s。
两种方式的归一化方法不一样。一个是维度归一化,一个是一般的归一化(行向量)

代码1

from numpy import *
import matplotlib.pyplot as plt
import string

class Kohonen(object):
    def __init__(self):
        self.lratemax=0.8   #最大学习率-欧式距离
        self.lratemin=0.05  #最小学习率-欧式距离
        self.rmax=5         #最大聚类半径--根据数据集
        self.rmin=0.5       #最小聚类半径--根据数据集
        self.Steps=1000     #迭代次数
        self.lratelist=[]   #学习率收敛曲线
        self.rlist=[]       #学习率半径曲线
        self.w=[]           #权重向量组
        self.M=2            # M*N表示聚类总数
        self.N=2            #M、N表示邻域的参数
        self.dataMat=[]     #外部导入数据集
        self.classLabel=[]  #聚类后的类别标签

    def loadDate(self,fileName):  #加载数据文件
        fr=open(fileName)
        for line in fr.readlines():
            curLine=line.strip().split("\t")
            lineArr=[]
            lineArr.append(float(curLine[0]))
            lineArr.append(float(curLine[1]))
            self.dataMat.append(lineArr)
        self.dataMat=mat(self.dataMat)

    def file2matrix(self,path, delimiter):
        recordlist = []
        fp = open(path)
        content = fp.read()
        fp.close()
        rowlist = content.splitlines()  # 按行转换为一维表
        # 逐行遍历      # 结果按分隔符分割为行向量
        recordlist = [map(eval, row.split(delimiter)) for row in rowlist if row.strip()]
        # 返回转换后的矩阵形式
        self.dataMat = mat(recordlist)

    def normalize(self,dataMat):
        [m,n]=shape(dataMat)
        for i in xrange(n):
           dataMat[:,i] =(dataMat[:,i]-mean(dataMat[:,]))/std(dataMat[:,])
        return dataMat

    def distEclud(self,matA,matB):
        ma, na = shape(matA);
        mb, nb = shape(matB);
        rtnmat = zeros((ma, nb))
        for i in xrange(ma):
            for j in xrange(nb):
                rtnmat[i, j] = linalg.norm(matA[i, :] - matB[:, j].T)
        return rtnmat

    def init_grid(self): #初始化第二层网格
        [m, n] = shape(self.dataMat)
        k=0 #构建低二层网络模型
        #数据集的维度即网格的维度,分类的个数即网格的行数
        grid=mat(zeros((self.M*self.N,n)))
        for i in xrange(self.M):
            for j in xrange(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 train(self):
        #1.构建输入层网络
        dm,dn=shape(self.dataMat)
        #归一化数据
        normDataSet=self.normalize(self.dataMat)
        #2.初始化第二层分类网络
        grid=self.init_grid()
        #3.随机初始化两层之间的权重向量
        self.w=random.rand(dn,self.M*self.N)
        distM=self.distEclud  #确定距离公式
        #4.迭代求解
        if self.Steps<5*dm:self.Steps=5*dm  #设定最小迭代次数
        for i in xrange(self.Steps):
            lrate,r=self.ratecalc(i) #1.计算当前迭代次数下的学习率和学习聚类半径
            self.lratelist.append(lrate);self.rlist.append(r)
            #2.随机生成样本索引,并抽取一个样本
            k=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).nonzero()[1] #获取领域内的所有点
            for j in xrange(shape(self.w)[1]):
                if sum(nodelindx==j):
                    self.w[:,j]=self.w[:,j]+lrate*(mySample[0]-self.w[:,j])
        #主循环结束

        self.classLabel=range(dm) #分配和存储聚类后的类别标签
        for i in xrange(dm):
            self.classLabel[i]=distM(normDataSet[i,:],self.w).argmin()
        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')
            elif i==1:plt.plot(xx[:,0],xx[:,1],'rd')
            elif i==2:plt.plot(xx[:,0],xx[:,1],'gD')
            elif i==3:plt.plot(xx[:,0],xx[:,1],'c^')
            i+=1
        plt.show()

if __name__=="__main__":

    SOMNet=Kohonen()
    SOMNet.loadDate('dataset2.txt')
    SOMNet.train()
    SOMNet.showCluster(plt)

这里写代码片

代码2

参考:http://blog.csdn.net/chenge_j/article/details/72537568

from numpy import *
import matplotlib.pyplot as plt
from  numpy import linalg

#初始化输入层与竞争层神经元的连接权值矩阵
def initCompetition(n , m , d):
    #随机产生0-1之间的数作为权值
    array = random.random(size=n * m *d)
    com_weight = array.reshape(n,m,d)
    return com_weight

#计算向量的二范数
def cal2NF(X):
    res = 0
   # return linalg.norm(X)
    for x in X:
        res += x*x
    return res ** 0.5

#对数据集进行归一化处理
def normalize(dataSet):
    old_dataSet = copy(dataSet)
    for data in dataSet:
        two_NF = cal2NF(data)
        for i in range(len(data)):
            data[i] = data[i] / two_NF
    return dataSet , old_dataSet
#对权值矩阵进行归一化处理
def normalize_weight(com_weight):
    for x in com_weight:
        for data in x:
            two_NF = cal2NF(data)
            for i in range(len(data)):
                data[i] = data[i] / two_NF
    return com_weight

#得到获胜神经元的索引值
def getWinner(data , com_weight):
    max_sim = 0
    n,m,d = shape(com_weight)
    mark_n = 0
    mark_m = 0
    for i in range(n):
        for j in range(m):
            if sum(data * com_weight[i,j]) > max_sim:
                max_sim = sum(data * com_weight[i,j])
                mark_n = i
                mark_m = j
    return mark_n , mark_m

#得到神经元的N邻域
def getNeibor(n , m , N_neibor , com_weight):
    res = []
    nn,mm , _ = shape(com_weight)
    for i in range(nn):
        for j in range(mm):
            N = int(((i-n)**2+(j-m)**2)**0.5)
            if N<=N_neibor:
                res.append((i,j,N))
    return res

#学习率函数
def eta(t,N):
    return (0.3/(t+1))* (math.e ** -N)

#SOM算法的实现

'''
T:最大迭代次数
N_neibor:初始近邻数
'''
def do_som(dataSet , com_weight, T , N_neibor):
    for t in range(T-1):
        com_weight = normalize_weight(com_weight)
        for data in dataSet:
            n , m = getWinner(data , com_weight)
            neibor = getNeibor(n , m , N_neibor , com_weight)
            for x in neibor:
                j_n=x[0];j_m=x[1];N=x[2]
                #权值调整
                com_weight[j_n][j_m] = com_weight[j_n][j_m] + eta(t,N)*(data - com_weight[j_n][j_m])
            N_neibor = N_neibor+1-(t+1)/200
    res = {}
    N , M , _ =shape(com_weight)
    for i in range(len(dataSet)):
        n, m = getWinner(dataSet[i], com_weight)
        key = n*M + m
        if res.has_key(key):
            res[key].append(i)
        else:
            res[key] = []
            res[key].append(i)
    return res

def draw(C , dataSet):
    color = ['r', 'y', 'g', 'b', 'c', 'k', 'm' , 'd']
    count = 0
    for i in C.keys():
        X = []
        Y = []
        datas = C[i]
        for j in range(len(datas)):
            X.append(dataSet[datas[j]][0])
            Y.append(dataSet[datas[j]][1])
        plt.scatter(X, Y, marker='o', color=color[count % len(color)], label=i)
        count += 1
    plt.legend(loc='upper right')
    plt.show()

def loadDataSet(fileName):  # 加载数据文件
    fr = open(fileName)
    dataMat=[]
    for line in fr.readlines():
        curLine = line.strip().split(",")
        lineArr = []
        lineArr.append(float(curLine[0]))
        lineArr.append(float(curLine[1]))
        dataMat.append(lineArr)
    dataMat = mat(dataMat)
    return dataMat

def file2matrix(path, delimiter):
    recordlist = []
    fp = open(path, "rb")  # 读取文件内容
    content = fp.read()
    fp.close()
    rowlist = content.splitlines()  # 按行转换为一维表
     # 逐行遍历         # 结果按分隔符分割为行向量
    recordlist = [map(eval, row.split(delimiter)) for row in rowlist if row.strip()]
        # 返回转换后的矩阵形式
    return recordlist
 # SOM算法主方法
def SOM(dataSet,com_n,com_m,T,N_neibor):
    dataSet, old_dataSet = normalize(dataSet)
    com_weight = initCompetition(com_n,com_m,shape(dataSet)[1])
    C_res = do_som(dataSet, com_weight, T, N_neibor)
    draw(C_res, dataSet)
    draw(C_res, old_dataSet)


starttime = datetime.datetime.now()
dataSet = file2matrix("dataset2.txt",'\t')
SOM(dataSet,2,2,1000,2)
endtime = datetime.datetime.now()
print (endtime - starttime).seconds

这里写图片描述

参考:http://blog.csdn.net/chenge_j/article/details/72537568

som神经网络,即自组织映射(Self-Organizing Map),是一种无监督学习的神经网络算法,用于聚类和数据降维。下面是一个基于Python的简单som神经网络的代码示例: ```python import numpy as np class SOM: def __init__(self, input_dim, output_dim, learning_rate=0.2, num_iterations=100): self.input_dim = input_dim self.output_dim = output_dim self.learning_rate = learning_rate self.num_iterations = num_iterations self.weights = np.random.rand(output_dim[0], output_dim[1], input_dim) def train(self, input_data): for iteration in range(self.num_iterations): for data_point in input_data: bmu_idx = self.find_best_matching_unit(data_point) self.update_weights(data_point, bmu_idx, iteration) def find_best_matching_unit(self, data_point): min_dist = np.inf bmu_idx = (0, 0) for i in range(self.output_dim[0]): for j in range(self.output_dim[1]): dist = np.linalg.norm(data_point - self.weights[i, j]) if dist < min_dist: min_dist = dist bmu_idx = (i, j) return bmu_idx def update_weights(self, data_point, bmu_idx, iteration): for i in range(self.output_dim[0]): for j in range(self.output_dim[1]): dist_to_bmu = np.linalg.norm(np.array(bmu_idx) - np.array([i, j])) lr = self.learning_rate * (1 - iteration / self.num_iterations) influence = np.exp(-dist_to_bmu / (lr * iteration)) self.weights[i, j] += lr * influence * (data_point - self.weights[i, j]) def predict(self, input_data): output = np.zeros(input_data.shape[0]) for i, data_point in enumerate(input_data): bmu_idx = self.find_best_matching_unit(data_point) output[i] = bmu_idx[0] * self.output_dim[1] + bmu_idx[1] return output # 示例用法 input_data = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) som = SOM(input_dim=2, output_dim=(10, 10)) som.train(input_data) test_data = np.array([[2.0, 3.0], [4.0, 5.0]]) predicted = som.predict(test_data) print(predicted) ``` 这里的SOM类有几个关键的方法和属性: - `__init__`:初始化方法,定义了输入维度、输出维度、学习率和迭代次数,并初始化权重矩阵。 - `train`:训练方法,通过迭代更新权重矩阵。 - `find_best_matching_unit`:寻找最佳匹配单元方法,在输出层中寻找与输入数据点最相似的神经元。 - `update_weights`:更新权重方法,根据输入数据点和最佳匹配单元更新权重矩阵。 - `predict`:预测方法,根据输入数据点,返回最佳匹配单元的位置。 示例中使用一个简单的二维数据集进行训练,并通过`predict`方法预测测试数据点的最佳匹配单元位置。 这是一个简单的som神经网络python源代码示例,可以根据需要进行修改和扩展。
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值