k-means聚类简单代码实现

聚类算法是一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中

在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法

简单的聚类代码实现:

# coding:utf-8
from math import *
from random import random

import numpy as np
from numpy import *
from numpy.ma import power,mean,nonzero
import matplotlib.pyplot as plt

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
class myOwn_k_means2(object):
    """
    k-means整体包含内容:
    1.fit:训练函数传入x,超参数k,同时取随机中心点centroids
    2.choose_centroid: 在边界范围内随机选择k个质心
    3.distance:求两点间距离
    4.key_k_means:核心部分,聚类并重新调整中心,返回取得的中心
    5.predict: 预测部分,得到最终的簇分类结果
    """
    def fit(self,x,k):
        # 根据训练数据得到中心点
        self.centroids = self.choose_centroid(x,k)
        self.new_centroids = self.key_k_means(x,k)

    def choose_centroid(self,x,k):
        """
        随机选择质心,在最大边界内选择质心的值
        利用一个0-1的随机生成器
        :return:随机选择的质心点
        """

        # 取其列数,即特征数2
        num = np.shape(x)[1]
        # 建立一个中心点矩阵
        centroids = np.mat(np.zeros((k,num)))
        # 在最大及最小边界内随机取k个中心
        for j in range(num):
            minJ = min(x[:,j])
            # print(f'我是minJ:\n{minJ}')
            maxJ = max(x[:,j])
            # print(f'我是maxJ:\n{maxJ}')
            rangeJ = float(maxJ-minJ)
            # 在0-1之间取k个
            centroids[:,j] = minJ + rangeJ*random.rand(k,1)
        # print(f'我是centroids:\n{centroids}')
        return centroids

    def distance(self,disA,disB):
        """
        求两点间距离,disA,disB分别为两点矩阵
        :return: 两点间欧式距离
        """
        # print(f'我是距离distance:\n{sqrt(sum(power((disA-disB),2)))}')
        return sqrt(sum(power((disA-disB),2)))

    def key_k_means(self,x,k):
        print(f'开始计算质心位置')
        """
        k-means 的核心部分,聚类并重新调整中心
        :return: 最终的中心点及分类列表
        """
        # 取其行数,所有点的个数1500
        m = np.shape(x)[0]
        # 设置一个簇分配结果矩阵,两列,一列记录簇索引值,一列记录到质心的距离
        cluster = np.mat(np.zeros((m,2)))
        # 1.调用函数choose_centroid(),并初始化centroids
        # centroids = self.choose_centroid(x,k)
        clusterChange = True
        while clusterChange:
            clusterChange = False
            # 遍历所有数据找到距离每个点最近的质心
            # 具体做法:对每个点遍历所有质心,并计算点到每个质心的距离。
            for i in range(m):
                minDist = 1000.0;
                minIndex = -1
                for j in range(k):
                    # 计算该点到质心的欧式距离
                    distJI = self.distance(self.centroids[j,:],x[i,:])
                    if distJI < minDist:
                        minDist = distJI
                        minIndex = j
                # 更新每一行样本所属的簇
                if cluster[i,0] != minIndex:
                    clusterChange = True
                    cluster[i,:] = minIndex,minDist ** 2
            # print(f'我是质心:\n{centroids}')
            # 遍历所有质心,并更新它们的取值
            for cent in range(k):
                # 获取簇类所有的点,函数nonzero()
                ptsInClust = x[nonzero(cluster[:,0].A == cent)[0]]
                # print(f'我是ptsInClust:\n{ptsInClust}')
                # 对矩阵的行求平均值
                self.centroids[cent,:] = mean(ptsInClust,axis=0)
                # 用一个值来承接new_centroids
                new_centroids = self.centroids
        # print(f'我是centroids:\n{centroids}')
        # print(f'我是cluster.A[:,0]:\n{cluster.A[:,0]}')
        # 我是cluster.A[:,0]:[0. 0. 1. ... 2. 2. 2.]
        # return centroids,cluster.A[:,0]
        return new_centroids

    def predict(self,X):
        """
        k-means 的核心部分,聚类并重新调整中心
        :return:
        """
        # 读入待预测数据
        # self.X = X
        # 训练好的中心点

        # print(f'我是predict中的centriods:\n{centriods}')
        # 定义一个新的列表存储距离
        list_distance = []
        list_result = []
        for i in range(len(self.centroids)):
            for j in range(len(X)):
                pre_distance = self.distance(self.centroids[i],X[j])
                list_distance.append(pre_distance)
            # print(f'我是list_distance:\n{np.array(list_distance).shape}')
            list_result.append(list_distance)
            # print(f'我是list_result:\n{np.array(list_result).shape}')
            list_distance = []
        list_result = np.array(list_result)
        # print(f'我是list_result:\n{list_result}')
        # 取每列最小的列索引
        result = np.argmin(list_result,axis=0)
        # print(f'我是result:\n{result}')
        return result




plt.figure(figsize=(12,12))

n_samples = 1500
random_state = 170
X,y = make_blobs(n_samples=n_samples,random_state=random_state)
# print(f'我是X:\n{X}')
my_kmeans = myOwn_k_means2()
my_kmeans.fit(X,3)
y_pred = my_kmeans.predict(X)

plt.subplot(221)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.title("我是聚类")
plt.show()

此处用到了一个新的函数:nonzero()

你可能感兴趣的:(机器学习,kmeans算法,机器学习,数据挖掘,自然语言处理)