西瓜书课后题9.4(K均值)

题目

试编程实现k均值算法,设置三组不同的k值、三组不同初始中心点,在西瓜数据集4.0上进行试验比较,并讨论什么样的初始中心有利于取得好的结果。

代码

import numpy as np
import matplotlib.pyplot as plt


def createDataSet():
    """
    创建测试的数据集,里面的数值中具有连续值
    :return:
    """
    dataSet = [
        [0.697, 0.460],
        [0.774, 0.376],
        [0.634, 0.264],
        [0.608, 0.318],
        [0.556, 0.215],
        [0.403, 0.237],
        [0.481, 0.149],
        [0.437, 0.211],
        [0.666, 0.091],
        [0.243, 0.267],
        [0.245, 0.057],
        [0.343, 0.099],
        [0.639, 0.161],
        [0.657, 0.198],
        [0.360, 0.370],
        [0.593, 0.042],
        [0.719, 0.103],
        [0.359, 0.188],
        [0.339, 0.241],
        [0.282, 0.257],
        [0.748, 0.232],
        [0.714, 0.346],
        [0.483, 0.312],
        [0.478, 0.437],
        [0.525, 0.369],
        [0.751, 0.489],
        [0.532, 0.472],
        [0.473, 0.376],
        [0.725, 0.445],
        [0.446, 0.459],
    ]

    # 特征值列表
    labels = ['密度', '含糖率']

    for i in range(len(dataSet)):
        if 9 <= i <= 21:
            dataSet[i].append(-1)
        else:
            dataSet[i].append(1)

    return np.array(dataSet), labels


# dataSet, labels = createDataSet()
# print(dataSet)
# print(labels)


def kMeans(dataSet, k):
    """
    K均值算法
    :param dataSet:
    :param k:       k个中心
    :return:
    """
    dataArr = dataSet[:, :-1]
    # 初始k个均值向量
    index = np.random.randint(0, len(dataSet), k)
    mu = dataArr[index]

    # 划分簇
    run = True              # run为false时停止循环
    retCluster = {}
    while run:
        cluster = {}
        for i in range(len(dataSet)):
            minDist = np.inf
            minIndex = -1
            for j in range(len(mu)):
                curDist = np.sqrt(((dataArr[i] - mu[j]) ** 2).sum())
                if curDist < minDist:
                    minDist = curDist
                    minIndex = j
            # 把第i个元素划入第j个簇中
            if minIndex not in cluster.keys():
                cluster[minIndex] = []
            cluster[minIndex].append(i)

        # 更新均值向量
        cnt = 0  # 计算均值向量更新的数
        for i in range(len(mu)):
            data = np.array(dataArr[cluster[i]])
            muHat = data.sum(axis=0) / len(data)
            vecDist = np.sqrt(((mu[i] - muHat) ** 2).sum())
            if vecDist != 0:
                mu[i] = muHat
                cnt += 1

        if cnt == 0:
            run = False
            retCluster = cluster

    return retCluster, mu


def main():
    dataSet, labels = createDataSet()
    cluster, mu = kMeans(dataSet, 3)
    print(cluster)
    print(mu)
    for key in cluster.keys():
        data = np.array(dataSet[cluster[key]])
        plt.scatter(data[:, 0], data[:, 1], label=key)
    plt.scatter(mu[:, 0], mu[:, 1], s=80, c='r', marker="+")
    plt.legend()
    plt.show()


if __name__ == '__main__':
    main()

输出结果

在这里插入图片描述

  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是一个简单的 Python 实现 k 均值算法的代码: ```python import numpy as np class KMeans: def __init__(self, n_clusters=8, max_iter=300): self.n_clusters = n_clusters self.max_iter = max_iter def fit(self, X): # 初始化聚类中心 self.centroids = X[np.random.choice(X.shape[0], self.n_clusters, replace=False)] # 开始迭代 for i in range(self.max_iter): # 分配样本到聚类中心 clusters = [[] for _ in range(self.n_clusters)] for x in X: distances = [np.linalg.norm(x - c) for c in self.centroids] cluster_idx = np.argmin(distances) clusters[cluster_idx].append(x) # 更新聚类中心 prev_centroids = self.centroids self.centroids = np.array([np.mean(cluster, axis=0) for cluster in clusters if cluster]) # 如果聚类中心没有变化,则退出循环 if np.allclose(self.centroids, prev_centroids): break def predict(self, X): distances = np.array([np.linalg.norm(X - c, axis=1) for c in self.centroids]) return np.argmin(distances, axis=0) ``` 这段代码实现了 KMeans 类,通过构造函数可以设置聚类数和最大迭代次数,fit 方法用于训练模型,predict 方法用于预测样本所属的聚类。 具体实现中,首先在样本中随机选择 k 个点作为聚类中心,然后进行迭代。每次迭代,首先将样本分配到最近的聚类中心所在的簇中,然后更新聚类中心,直到聚类中心不再变化或达到最大迭代次数。最后,predict 方法根据已经训练好的聚类中心,预测样本所属的聚类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值