机器学习算法复习---聚类算法之KMeans

         了解基础的机器学习知识即了解基础的机器学习的一些名词但没有实现过机器学习算法的人观看且对python不了解的也可以看,每一处具有注释。本文使用的python3编译环境,与python2编译环境有一些差别,不过不影响大体。本文的理论部分以西瓜书和统计学习方法为参考,代码实现以机器学习实战为参考。

         好!开始上代码!主要介绍聚类算法中的KMeans算法,其他的陆续更新

         一、手写KMeans

        理论部分

              1、聚类算法:聚类试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个"簇" (cluster). 通过这样的划分,每个簇可能对应于一些潜在的概念(类别) ,如"浅色瓜" "深色瓜","有籽瓜" "无籽瓜",甚至"本地瓜""外地瓜"等;需说明的是,这些概念对聚类算法而言事先是未知的,聚类过程仅能自动形成簇结构,簇所对应的概念语义需由使用者来把握和命名. 

              

               人话版本:当思考聚类算法的时候,我第一次想到的是人以群分,物以类聚。举个例子面对一个班级的学生我们可以根据数学考试的分数90-100分为一等,80-90分为二等。。面对我们不知道怎么分类的事物我们怎么实现物以类聚,(哈哈本专业来帮忙了),在植物学中我们怎么分类各种植物呢?动物学中我们怎么分类各种动物呢?全国的草地如何进行分类呢?拿全国的草地如何进行分类来说,我们要搜集各个草地所在地的降水量、温度、适度、主要的建群种等属性然后将其量化。为叙述简单仅取一个属性降水量来分析。输入不同地区的降水量,计算不同地区之间的差距,比如分为两类,从中随机选择两地,其他的地区以这俩地方为标准计算与这两地的距离,并选择最小的进行投靠,这样就能将其分类。那么问题来了?如何计算他们之间的差距?

           2、距离的计算------距离算法的灵魂

              介绍距离计算之前先介绍属性

                     连续属性:在定义域上有无穷多个可能的取值

                     离散属性:在定义域上是有限个取值

                    有序属性:能直接在属性值上计算距离 "1" 与 "2" 比较接近、与 "3" 比较远,这样属性称为"有序属性" (ordinal attribute),数据具有一定的等级顺序; 而定义域为{飞机,火车,轮船}这样的离散属性则不能直接在属性值上计算距离,称为"无序属性" (non-ordinal
attribute) .  。

               

闵可夫斯基距离

 

 

闵可夫斯基距离可用于有序属性

p=2 时,闵可夫斯基距离即欧氏距离 (Euclidean distance) --即两点之间距离公式

p=l 时,闵可夫斯基距离即曼哈顿距离 (Manhattan distance)

街区距离" (city block distance)

 

 

VDM(Value Difference Metric)

与本文无关省略

思想

公式

 

例子

 

others

 

       代码部分

            k-means clustering
                  Pros: Easy to implement
                  Cons: Can converge at local minima; slow on very large datasets
                  Works with: Numeric values

         伪代码

创建k个点作为起始质心(经常是随机选择)
当任意一个点的簇分配结果发生改变时 
    对养据集中的每个数据点 
        对每个质心
            计算质心与数据点之间的距离 
        将数据点分配到距其最近的簇 
    对每一个簇,计算簇中所有点的均值并将均值作为质心

           python3

              

# -*- coding: utf-8 -*-
"""
k-means clustering
    Pros: Easy to implement 
    Cons: Can converge at local minima; slow on very large datasets 
    Works with: Numeric values
 
@author: 
"""

from numpy import *
import numpy as np
#加载数据
def loadDataSet(fileName):
    datMat =[] 
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        ##这里与原文不一样。
        datMat.append(curLine)
        dataMat = np.array(datMat)
        ##astype 将numpy数组类型转换为float形式
        dataMat = dataMat.astype(float)
        
    return dataMat

#计算欧式距离
def distEclud(vecA, vecB):
     return sqrt(sum(power(vecA - vecB, 2)))
 

##获得初始蔟质心
##centroids:中心点
def randCent(dataSet, k):
    ##获得列数
    n = shape(dataSet)[1]
    ##创建k行n列的0矩阵
    centroids = mat(zeros((k,n)))
    for j in range(n):                     
        minJ = min(dataSet[:,j]) 
        rangeJ = float(max(dataSet[:,j]) - minJ)
        centroids[:,j] = minJ + rangeJ * random.rand(k,1)
    return centroids


def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    ##获得行数
    m = shape(dataSet)[0]
    """
    clusterAssment:蔟分配结果矩阵
        第一列:记录蔟索引值
        第二列:误差---当前点到簇质心的距离
    """
    clusterAssment = mat(zeros((m,2))) 
    #获得初始质心
    centroids = createCent(dataSet, k)
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        
        for i in range(m):
            #minDist初始值设置为无穷大  inf:无穷大
            minDist = inf; minIndex = -1
            ##选出第i个元素距离那一个蔟最小
            for j in range(k):
                ##计算每一个元素与质心J的欧氏距离                                
                distJI = distMeas(centroids[j,:],dataSet[i,:])  
                if distJI < minDist:                          
                    minDist = distJI; minIndex = j
            
            ##只要当前第i个元素所属于的蔟与之前不想等就继续循环
            if clusterAssment[i,0] != minIndex: clusterChanged = True
            
            ##将当前的第i个元素距离第j个蔟最小记录下来
            clusterAssment[i,:] = minIndex,minDist**2
            
        for cent in range(k):         
            ##clusterAssment[:,0]第一列元素 list
            ##属于第cent个质心的所有元素赋值给ptsInClust                                
            ptsInClust = dataSet[nonzero(clusterAssment[:,0]==cent)[0]]
            ##axis = 0表示矩阵的列方向按均值计算
            ##计算每一蔟的均值
            centroids[cent,:] = mean(ptsInClust, axis=0)      
            
    return centroids, clusterAssment

          调用SKlearn中的算法

          

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 25 10:36:56 2019

@author: 
"""

import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc

# 读取数据,绘制图像
#x = np.loadtxt('testSet.txt', unpack=False, dtype='f8', delimiter=',')
datMat =[] 
fr = open('testSet.txt')
for line in fr.readlines():
    curLine = line.strip().split('\t')
    fltLine = curLine
    datMat.append(fltLine)
    dataMat = np.array(datMat)

dataMat = dataMat.astype(float)

print(dataMat.shape)
#print(dataMat)
# 基于Kmeans完成聚类
model = sc.KMeans(n_clusters=4)
model.fit(dataMat)  # 完成聚类
pred_y = model.predict(dataMat)  # 预测点在哪个聚类中
print(pred_y)  # 输出每个样本的聚类标签
#获取聚类中心
centers = model.cluster_centers_
print("聚类中心",centers)

# 绘制分类边界线
l, r = dataMat[:, 0].min() - 1, dataMat[:, 0].max() + 1
b, t = dataMat[:, 1].min() - 1, dataMat[:, 1].max() + 1
n = 500
grid_x, grid_y = np.meshgrid(np.linspace(l, r, n), np.linspace(b, t, n))
bg_x = np.column_stack((grid_x.ravel(), grid_y.ravel()))
bg_y = model.predict(bg_x)
grid_z = bg_y.reshape(grid_x.shape)



# 画图显示样本数据
mp.figure('Kmeans', facecolor='lightgray')
mp.title('Kmeans', fontsize=16)

mp.xlabel('X', fontsize=14)
mp.ylabel('Y', fontsize=14)

mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x, grid_y, grid_z, cmap='gray')
mp.scatter(dataMat[:, 0], dataMat[:, 1], s=80, c=pred_y, cmap='brg', label='Samples')
mp.scatter(centers[:, 0], centers[:, 1], s=300, color='red', marker='+', label='cluster center')

mp.legend()

mp.show()

发布了26 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_41926640/article/details/103244221