聚类算法学习 — K-means

目录

  • 1 算法
    • 1.1 算法简介
    • 1.2 算法步骤
    • 1.3 伪代码与时间复杂度
    • 1.4 优缺点
      • 1.4.1 优点
      • 1.4.2 缺点
  • 2 具体实施
    • 2.1 不使用Python Kmeans库
    • 2.2 使用Python Kmeans库
      • 2.2.1 库准备
      • 2.2.2 sklearn.cluster.KMeans 参数介绍
      • 2.2.3 t-SNE降维算法
      • 2.2.4 代码

1 算法

1.1 算法简介

K-means是基于欧氏距离的基础聚类算法,一般作为聚类算法入门选手,其主要思想是初始任选k个基本点,计算各点离初始点的欧式距离,选择距离最近的初始点,将其归为一类;一轮结束后,重新计算每类的聚类中心,循环上述过程直至 max_iter

1.2 算法步骤

  1. 随机选择k个样本作为初始聚类中心 c = c 1 , c 2 , c 3 . . . c=c_1, c_2, c_3... c=c1,c2,c3...
  2. 对每个样本 n i n_i ni 计算其到这k个初始聚类中心的欧氏距离,并将其归类到距离最小的聚类中心所对应的类中
  3. 完成一轮后,对于每个类重新计算其聚类中心 a j = 1 ∣ c i ∣ ∑ x ∈ c i x a_j=\frac{1}{|c_i|}\sum_{x\in c_i}x aj=ci1xcix (属于某类的所有点的质心)
  4. 通过设置 max_iter (最大迭代次数)来进行m轮迭代,最终完成聚类

1.3 伪代码与时间复杂度

#n个m维样本点,选取k个初始聚类中心,进行max次迭代
while(max):
    for i in range(k):
        for j in range(n):
            #计算每个样本点j到聚类中心i的距离,并将距离小的归为一类
    for i in range(k):
        #计算并修改每类新的聚类中心坐标
  1. 时间复杂度: O ( n ∗ m ∗ k ∗ m a x ) O(n*m*k*max) O(nmkmax)
  2. 空间复杂度: O ( m ( n + k ) ) O(m(n+k)) O(m(n+k))

1.4 优缺点

1.4.1 优点

  1. 最简单的聚类方法,容易理解且容易实施,指定k即可获得不同的聚类结果
  2. 算法复杂度较低,时间与空间性能较强
  3. 对于数据较规整的题目,往往使用局部最优即可获得最佳答案
  4. 在处理大数据集时,该算法可保持较好伸缩性与高效性

1.4.2 缺点

  1. 只能处理较规整的数据(少异常值)且呈圆形分布的数据,对于线性或样本类不平衡的分类不适用
  2. k值为人工选择,与就是说处理前需人工判断分为几类,极大受初始k值的选择,k的不同选择或产生不同结果
  3. 若数据量非常大,算法的时间开销将巨大,只适用于处理小数据两样本

2 具体实施

2.1 不使用Python Kmeans库

基本思想

  1. 初始化聚类中心:随机选取样本库中一个样本点 c 1 c_1 c1 作为第一个聚类中心放入容器;取样本库中离其最远的点作为下一个聚类中心点,以此类推找到k个点(为优化可选择距离开方作为标准)
  2. 初始归类:计算样本点中每个点离初始聚类中心的距离,选择距离短的将其放入相同容器(类)
  3. 迭代归类:在每个容器(类)中,计算其均值并更新新的聚类中心点坐标,再次进行聚类操作,迭代 m a x max max 次得到理想结果
  4. 利用Python第三方库中 matplotlib.pyplot 用散点图对聚类后的结果可视化

引用代码如下

import numpy as np
import matplotlib.pyplot as plt

# 两点距离
def distance(e1, e2):
    return np.sqrt((e1[0]-e2[0])**2+(e1[1]-e2[1])**2)

# 集合中心
def means(arr):
    return np.array([np.mean([e[0] for e in arr]), np.mean([e[1] for e in arr])])

# arr中距离a最远的元素,用于初始化聚类中心
def farthest(k_arr, arr):
    f = [0, 0]
    max_d = 0
    for e in arr:
        d = 0
        for i in range(k_arr.__len__()):
            d = d + np.sqrt(distance(k_arr[i], e))
        if d > max_d:
            max_d = d
            f = e
    return f

# arr中距离a最近的元素,用于聚类
def closest(a, arr):
    c = arr[1]
    min_d = distance(a, arr[1])
    arr = arr[1:]
    for e in arr:
        d = distance(a, e)
        if d < min_d:
            min_d = d
            c = e
    return c


if __name__=="__main__":
    ## 生成二维随机坐标,手上有数据集的朋友注意,理解arr改起来就很容易了
    ## arr是一个数组,每个元素都是一个二元组,代表着一个坐标
    ## arr形如:[ (x1, y1), (x2, y2), (x3, y3) ... ]
    arr = np.random.randint(100, size=(100, 1, 2))[:, 0, :]

    ## 初始化聚类中心和聚类容器
    m = 5
    r = np.random.randint(arr.__len__() - 1)
    k_arr = np.array([arr[r]])
    cla_arr = [[]]
    for i in range(m-1):
        k = farthest(k_arr, arr)
        k_arr = np.concatenate([k_arr, np.array([k])])
        cla_arr.append([])

    ## 迭代聚类
    n = 20
    cla_temp = cla_arr
    for i in range(n):    # 迭代n次
        for e in arr:    # 把集合里每一个元素聚到最近的类
            ki = 0        # 假定距离第一个中心最近
            min_d = distance(e, k_arr[ki])
            for j in range(1, k_arr.__len__()):
                if distance(e, k_arr[j]) < min_d:    # 找到更近的聚类中心
                    min_d = distance(e, k_arr[j])
                    ki = j
            cla_temp[ki].append(e)
        # 迭代更新聚类中心
        for k in range(k_arr.__len__()):
            if n - 1 == i:
                break
            k_arr[k] = means(cla_temp[k])
            cla_temp[k] = []

    ## 可视化展示
    col = ['HotPink', 'Aqua', 'Chartreuse', 'yellow', 'LightSalmon']
    for i in range(m):
        plt.scatter(k_arr[i][0], k_arr[i][1], linewidth=10, color=col[i])
        plt.scatter([e[0] for e in cla_temp[i]], [e[1] for e in cla_temp[i]], color=col[i])
    plt.show()

2.2 使用Python Kmeans库

2.2.1 库准备

本篇需用到的库:numpy、pandas、matplotlib、scikit-learn
库的安装可参考我的上篇文章进行安装 如何解决Python下载包问题

2.2.2 sklearn.cluster.KMeans 参数介绍

sklearn.cluster.KMeans(n_cluster=8,init=‘k-means++’,n_init=10,max_iter=300,tol=0.0001,
precompute_distances=‘auto’,verbose=0,random_state=None,copy_x=True,n_jobs=1,algorithm=‘auto’)

  • n_cluster: 类中心的个数,默认为8
  • init: 参数为’k-means++',‘random’或一个numpy的矩阵,默认为’k-means++’
    ‘k-means++’:启发式选择一个初始聚类中心
    ‘random’:随机选择数据中的k行作为类中心,每一行代表一个数据的属性集合传入ndarray需要是(n_clusters*n_features)维,并给定初始化中心
  • n_init: 默认为10.k-means算法会选择不同的质心运行的次数,最终结果是n_init次中最好的模型.
  • max_iter: 默认为30,每一次k-means算法迭代的最大次数
  • tol: 默认为1e-4,相对于惯性收敛的容错率,小于该值停止迭代,认为达到收敛
  • precompute_distances: 参数为’auto’,True,False。预计算,会得到更高的收敛速度但会占用更多内存
    ‘auto’:n_samples*n_clusters>12时不进行预计算
    True:始终预计算
    False:永远不进行预计算
  • verbose: 默认为0,冗余模式?文档也没有提供详细的解释,不过通常不对默认值进行修改,如果有大神知道请评论告知QAQ
  • random_state: 参数为int,RandomState instance or None.用来设置生成随机数的方式
    int:作为随机数生成器的种子
    RandomState instance:作为随机数生成器
    None:随机数生成器采用np.random
  • copy_x: 默认为True,是个boolean变量
    True:对输入训练数据x所做的任何操作都是对x.copy()进行的,不改变x的原值。
    False:对x的操作会同步到x上,即传引用调用
  • n_jobs: int型变量,并行运行的个数。
    -1:使用所有CPU. n_jobs<-1时,使用(n_cpus+1+n_jobs)个CPU.
  • algorithm: ‘auto’,‘full’ or ‘elkan’.默认为’auto’
    full:采用经典的EM算法
    elkan:通过使用三角不等式从而更有效,但不支持稀疏数据
    auto:数据稀疏选择full模式,数据稠密选择elkan模式
    属性:
  • cluster_centers_: 一个n-clusters*n_features的矩阵,表示聚类中心的坐标
  • labels_: 每个点的标签
  • inertia: 每个点到所属的聚类中心的平方和

2.2.3 t-SNE降维算法

t-SNE的主要用途是可视化和探索高维数据,主要目标是将多维数据集转换为低维数据集。
主要原理:

  1. 首先,它将通过选择一个随机数据点并计算与其他数据点(|xᵢ—xⱼ|)的欧几里得距离来创建概率分布。 从所选数据点附近的数据点将获得更多的相似度值,而距离与所选数据点较远的数据点将获得较少的相似度值。 使用相似度值,它将为每个数据点创建相似度矩阵(S1)。
  2. 其次,它将根据正态分布将计算出的相似距离转换为联合概率。
  3. 再次,对于较低维的数据点,还将创建一个相似度矩阵(S2)。然后该算法将S1与S2进行比较,并通过处理一些复杂的数学运算来使S1与S2之间有所不同。包括使用两个分布之间的Kullback Leibler散度(KL散度)作为损失函数运行梯度下降算法。使用KL散度通过将两个分布之间相对于数据点位置的值最小化,帮助t-SNE保留数据的局部结构。
  4. 最后,该算法能够得到与原始高维数据相对相似度较好的低维数据点。我们可以使用sklearn.manifold.TSNE()实现t-SNE算法。
    目前我们只需要知道它是用来将降维数据可视化的算法即可

2.2.4 代码

import pandas as pd
import numpy as np
from pandas import DataFrame, Series
from sklearn.cluster import KMeans
from sklearn.cluster import Birch
import matplotlib.pyplot as plt

# 读取文件
datafile = 'E:/programming/data analysis/exp_c/cluster.xlsx'  # 文件所在位置,u为防止路径中有中文名称,此处没有,可以省略
outfile = 'E:/programming/data analysis/exp_c/cluster1.xlsx'  # 设置输出文件的位置
data = pd.read_excel(datafile)  # datafile是excel文件,所以用read_excel,如果是csv文件则用read_csv
d = DataFrame(data)
d.head()

# 聚类
mod = KMeans(n_clusters=3, max_iter=1500,random_state=1234,algorithm='auto')  # 聚成3类数据,并发数为4,最大循环次数为500
mod.fit_predict(d)  # y_pred表示聚类的结果

# 聚成3类数据,统计每个聚类下的数据量,并且求出他们的中心
r1 = pd.Series(mod.labels_).value_counts()
r2 = pd.DataFrame(mod.cluster_centers_)
r = pd.concat([r2, r1], axis=1)
r.columns = list(d.columns) + [u'类别数目']
print(r)

# 给每一条数据标注上被分为哪一类
r = pd.concat([d, pd.Series(mod.labels_, index=d.index)], axis=1)
r.columns = list(d.columns) + [u'聚类类别']
print(r.head())
r.to_excel(outfile)  # 如果需要保存到本地,就写上这一# 列

# 可视化过程
from sklearn.manifold import TSNE

ts = TSNE(n_components=2, init='random')
ts.fit_transform(r)
ts = pd.DataFrame(ts.embedding_)

a = ts[r[u'聚类类别'] == 0]
plt.plot(a[0], a[1], 'r.')
a = ts[r[u'聚类类别'] == 1]
plt.plot(a[0], a[1], 'go')
a = ts[r[u'聚类类别'] == 2]
plt.plot(a[0], a[1], 'b*')
plt.show()

*注:sklearn在不断升级,如若运行中出现 *FutureWarning: The default learning rate in TSNE will change from 200.0 to ‘auto’ in 1.2.
warnings.warn(等类似警告,可通过此篇文章如何修复scikit-learn中的Future Warning解决。

参考文献
1.https://blog.csdn.net/weixin_41724761/article/details/89786414
2.https://blog.csdn.net/qq_37509235/article/details/82925781
3.https://zhuanlan.zhihu.com/p/78798251
4.https://blog.csdn.net/weixin_40683253/article/details/81288900
5. t-SNE:可视化效果最好的降维算法

你可能感兴趣的:(聚类,算法,python,k-means,kmeans)