大数据-213 数据挖掘 机器学习理论 - KMeans Python 实现 距离计算函数 质心函数 聚类函数

点一下关注吧!!!非常感谢!!持续更新!!!

目前已经更新到了:

  • Hadoop(已更完)
  • HDFS(已更完)
  • MapReduce(已更完)
  • Hive(已更完)
  • Flume(已更完)
  • Sqoop(已更完)
  • Zookeeper(已更完)
  • HBase(已更完)
  • Redis (已更完)
  • Kafka(已更完)
  • Spark(已更完)
  • Flink(已更完)
  • ClickHouse(已更完)
  • Kudu(已更完)
  • Druid(已更完)
  • Kylin(已更完)
  • Elasticsearch(已更完)
  • DataX(已更完)
  • Tez(已更完)
  • 数据挖掘(正在更新...)

章节内容

上节我们完成了如下的内容:

  • 无监督学习算法
  • KMeans 基本原理
  • KMeans 簇内误差平方和

Python实现

导入依赖

python 复制代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
# 解决坐标轴刻度负号乱码
plt.rcParams['axes.unicode_minus'] = False
# 解决中文乱码问题
plt.rcParams['font.sans-serif'] = ['Simhei']

导入数据集

此处使用鸢尾花数据集为例:

python 复制代码
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
#导入数据集
iris = pd.read_csv("iris.txt",header = None)
iris.head()
iris.shape

执行结果如下图所示:

编写距离计算函数

我们需要定义一个两个长度相等的数组之间欧式距离计算函数,在不直接应用计算结果,只比较距离远近的情况下,我们可以用距离平方和代替距离进行比较,化简开平方运算,从而减少函数计算量。此外需要说明的是,涉及到距离计算的,一定要注意量纲的统一。

如果量纲不统一的话,模型极易偏向量纲大的那一方。

  • 函数功能:计算两个数据集之间的欧式距离
  • 输入:两个 array 数据集
  • 返回:两个数据集之间的欧式距离(此处用距离平方和代替距离)
python 复制代码
def distEclud(arrA, arrB):
    d = arrA - arrB
    dist = np.sum(np.power(d, 2), axis=1)
    return dist

编写随机函数生成质心函数

在定义随机质心生成函数时,首先需要计算每列数值的范围,然后从该范围中随机生成指定个数的质心。

  • 函数功能:随机生成 k 个质心
  • 参数说明:dataSet 包含标签的数据集,k 是簇的个数,返回 data_cent 是 k 个质心
python 复制代码
def randCent(dataSet, k):
    # n为列数,假设dataSet是一个DataFrame
    n = dataSet.shape[1]  # 获取数据集的列数(例如 iris 数据集有 5 列)
    
    # 获取每一列的最小值和最大值(仅使用前 n-1 列,最后一列是标签或类别)
    data_min = dataSet.iloc[:, :n-1].min()  # 前4列的最小值
    data_max = dataSet.iloc[:, :n-1].max()  # 前4列的最大值
    
    # 在最小值和最大值之间生成 k 个随机中心点,形状为 (k, n-1)
    data_cent = np.random.uniform(data_min, data_max, (k, n-1))
    
    return data_cent

经过上述定义,在 iris 中随机生成了三个质心:

执行对应的代码:

python 复制代码
iris_cent = randCent(iris, 3)
iris_cent

执行结果如下图所示:

编写 K-Means 聚类函数

在执行 K-Means 的时候,需要不断的迭代质心,因此我们需要两个可迭代的容器来完成该目标:

  • 第一个容器用于存放和更新质心,该容器可考虑使用 list 来执行,list 不仅是可迭代对象,同时 list 内不同元素索引位置也可以用于标记和区分各质心,即各簇的编号:即代码中的 centroids。
  • 第二个容器则需要记录,保存和更新到各点到质心之间的距离,并能够方便对其进行比较,该容器考虑使用一个三列的数组来执行。

第二个容器中:

  • 第一列用于存放最近一次计算完成后某点到各质心的最短距离
  • 第二列用于记录最近一次计算完成后根据最短距离得到的代表对应质心的数值索引,即所述簇,即质心编号。
  • 第三列用于存放上一次某点对应质心编号(某点所属簇),后两列用于比较质心发生变化后某点所属簇的情况是否发生变化。

函数功能:K-均值聚类算法

参数说明:

  • dataSet 带标签数据集
  • k 簇的个数
  • distMeas 距离计算函数
  • createCent 随机质心生成函数

返回:

  • centroids 质心
  • result_set 所有数据划分结果
python 复制代码
# 假设 distEclud 和 randCent 是你定义的距离测量函数和随机生成质心函数
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    # 获取数据集的维度,m 是行数,n 是列数
    m, n = dataSet.shape  # m是行数(数据量),n是列数(例如 iris 为 150*5)

    # 初始化质心 centroids,生成 k 个随机质心
    centroids = createCent(dataSet, k)  # centroids 为 k*n 的矩阵(随机生成)

    # 初始化 clusterAssment 矩阵,用来存储每个点的簇分配结果
    # clusterAssment: [该行到最近质心的距离, 本次迭代中最近质心编号, 上次迭代中最近质心编号]
    clusterAssment = np.zeros((m, 3))  # 初始化为 m*3 的矩阵
    clusterAssment[:, 0] = np.inf  # 设置初始距离为无穷大
    clusterAssment[:, 1:3] = -1  # 质心编号初始化为 -1

    # 将数据集和 clusterAssment 合并,形成 result_set
    result_set = pd.concat([dataSet, pd.DataFrame(clusterAssment)], axis=1, ignore_index=True)

    # 标记簇是否发生变化
    clusterChanged = True

    while clusterChanged:
        clusterChanged = False
        # 遍历每个样本点,计算它与每个质心的距离,并更新簇分配信息
        for i in range(m):
            # 计算当前数据点到所有质心的距离
            dist = distMeas(dataSet.iloc[i, :n-1].values, centroids)  # 计算距离,dist 是 k*1 的矩阵
            # 记录最小距离和对应质心的索引
            result_set.iloc[i, n] = dist.min()  # 记录最小距离
            result_set.iloc[i, n+1] = np.where(dist == dist.min())[0][0]  # 记录最近质心的索引

        # 检查当前簇分配与上次是否完全一致
        clusterChanged = not (result_set.iloc[:, -1] == result_set.iloc[:, -2]).all()

        # 如果簇分配发生变化,则更新质心和 result_set
        if clusterChanged:
            # 根据新的簇分配,计算新的质心位置
            cent_df = result_set.groupby(n+1).mean()  # 根据最新簇分配,分组计算新的质心
            centroids = cent_df.iloc[:, :n-1].values  # 更新质心,使用新的均值作为质心

            # 更新簇分配编码,将当前簇分配替换为上次的簇分配
            result_set.iloc[:, -1] = result_set.iloc[:, -2]

    return centroids, result_set

将鸢尾花数据带进去,查看模型的效果:

python 复制代码
iris_cent,iris_result = kMeans(iris, 3)
iris_cent
iris_result.head()

执行结果若下所示:

有几点需要特别注意:

  • 设置统一的操作对象 result_set,为了调用和使用的方便,这里将 clusterAssment 转换为了 DataFrame 并与输入 DataFrame 合并,组成的对象作为后续调用的统一对象,该对象内即保存了原始数据,也保存了迭代运算的中间结果,包括数据所属簇标记和数据质心距离等,该对象同时也作为最终函数的返回结果
  • 判断质心是否发生改变条件,在K-Means 中判断质心是否发生改变,即判断是否继续进行下一步迭代的依据并不是某点距离新的质心距离变短,而是某点新的距离向量(到各质心的距离)中最短的分量位置是否发生变化,即质心变化后某点是否应归属另外的簇,在质心变化导致各点所属簇发生变化的过程中,点到质心的距离不一定会变短,即判断条件不能用下述语句表示
  • 质心和类别一一对应,在最后生成的结果中,centroids的行标为 result_set 中各点所属类别
相关推荐
阿斯卡码1 小时前
jupyter添加、删除、查看内核
ide·python·jupyter
小于小于大橙子2 小时前
视觉SLAM数学基础
人工智能·数码相机·自动化·自动驾驶·几何学
埃菲尔铁塔_CV算法4 小时前
图像算法之 OCR 识别算法:原理与应用场景
图像处理·python·计算机视觉
封步宇AIGC4 小时前
量化交易系统开发-实时行情自动化交易-3.4.2.Okex行情交易数据
人工智能·python·机器学习·数据挖掘
封步宇AIGC4 小时前
量化交易系统开发-实时行情自动化交易-2.技术栈
人工智能·python·机器学习·数据挖掘
景鹤4 小时前
【算法】递归+回溯+剪枝:78.子集
算法·机器学习·剪枝
Natural_yz4 小时前
大数据学习09之Hive基础
大数据·hive·学习
陌上阳光4 小时前
动手学深度学习68 Transformer
人工智能·深度学习·transformer
Natural_yz4 小时前
大数据学习10之Hive高级
大数据·hive·学习
OpenI启智社区4 小时前
共筑开源技术新篇章 | 2024 CCF中国开源大会盛大开幕
人工智能·开源·ccf中国开源大会·大湾区