《机器学习》西瓜书课后习题9.4——python实现K-means算法

《机器学习》西瓜书课后习题9.4——python实现K-means算法

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

本文主要适用python语言编程实现了K-means算法的过程,并使用了西瓜数据集4.0作为测试数据,在初始化均值向量时使用随机选择的方法,因此相同参数的情况下代码每次运行的结果可能会有所不同。最后,为了验证聚类效果,可视化了最终的结果集,可以发现的是,随着迭代的此时的增多,聚类的效果更好,直至趋于稳定。

具体的算法伪代码和原理部分参见《机器学习》周志华 P203。

西瓜数据集4.0内容:

编号,密度,含糖率
1,0.697,0.460
2,0.774,0.376
3,0.634,0.264
4,0.608,0.318
5,0.556,0.215
6,0.403,0.237
7,0.481,0.149
8,0.437,0.211
9,0.666,0.091
10,0.243,0.267
11,0.245,0.057
12,0.343,0.099
13,0.639,0.161
14,0.657,0.198
15,0.360,0.370
16,0.593,0.042
17,0.719,0.103
18,0.359,0.188
19,0.339,0.241
20,0.282,0.257
21,0.748,0.232
22,0.714,0.346
23,0.483,0.312
24,0.478,0.437
25,0.525,0.369
26,0.751,0.489
27,0.532,0.472
28,0.473,0.376
29,0.725,0.445
30,0.446,0.459

下面我将对代码逐段解释……

一、数据预处理

先将数据集下载并加载进来!代码如下:

def loadData(filename):
    data = open(filename, 'r', encoding='GBK')
    reader = csv.reader(data)
    headers = next(reader)
    dataset = []
    for row in reader:
        row[1] = float(row[1])
        row[2] = float(row[2])
        dataset.append([row[1],row[2]])

    return dataset

二、k-means算法

1、创建一个Kmeans类,所有的操作均封装

Kmeans类中以下的参数是必不可少的:

  • k:聚类的个数
  • train_data:数据集
  • epoch:迭代次数

在该类中,首先是对均值向量进行初始化,随机选择k个数据作为均值向量。其次,我们需要计算数据和均值向量之间的距离,并按最近距离进行划分类。然后,我们需要更新均值向量,具体做法是取每个类中的均值作为新的均值向量。如此,直到达到要求的迭代次数。

class Kmeans:
    k = 0
    train_data = []
    category_k = {}
    vector_k = []
    epoch = 0
    def __init__(self,k,train_data,epoch):
        self.train_data = np.array(train_data, dtype=float)
        self.epoch = epoch
        #  初始化均值向量
        for i in range(0,k):
           self.vector_k.append(self.train_data[random.randint(0,len(train_data)-1)])
        self.vector_k = np.array(self.vector_k, dtype=float)

        #  第i轮迭代
        for epoch_i in range(0,epoch):
            self.category_k = {}
            #  计算距离并分类
            for data_i in self.train_data:
                category_i = self.dist(data_i)
                if category_i not in self.category_k:
                    self.category_k[category_i] = [data_i]
                else:
                    self.category_k[category_i].append(data_i)

            #  更新均值向量
            self.update_category()

2、计算距离并分类

    #  计算第i个数据和所有均值向量的距离,并
    def dist(self,data_i):
        dist = (self.vector_k-data_i)**2
        mean_dist = dist.mean(axis=1)
        return mean_dist.argmin()

3、更新均值向量

    #  计算每个类别的均值并更新均值向量
    def update_category(self):
        for i in range(0,len(self.vector_k)):
            self.vector_k[i] = np.array(self.category_k[i]).mean(axis=0)

4、绘制图像

    #  绘制散点图
    def draw_scatter(self):
        for i in self.category_k:
            x = np.array(self.category_k[i])[:,0]
            y = np.array(self.category_k[i])[:,1]
            plt.scatter(x,y)
        #  绘制均值向量点的位置
        print(self.vector_k)
        x_mean = self.vector_k[:,0]
        y_mean = self.vector_k[:,1]

        plt.title("epoch = "+str(self.epoch))
        plt.xlabel('密度')
        plt.ylabel('含糖率')
        plt.scatter(x_mean,y_mean,marker='+')
        plt.show()

三、完整的程序源代码

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

import random
import numpy as np
import csv
import matplotlib.pyplot as plt

class Kmeans:
    k = 0
    train_data = []
    category_k = {}
    vector_k = []
    epoch = 0
    def __init__(self,k,train_data,epoch):
        self.train_data = np.array(train_data, dtype=float)
        self.epoch = epoch
        #  初始化均值向量
        for i in range(0,k):
           self.vector_k.append(self.train_data[random.randint(0,len(train_data)-1)])
        self.vector_k = np.array(self.vector_k, dtype=float)

        #  第i轮迭代
        for epoch_i in range(0,epoch):
            self.category_k = {}
            #  计算距离并分类
            for data_i in self.train_data:
                category_i = self.dist(data_i)
                if category_i not in self.category_k:
                    self.category_k[category_i] = [data_i]
                else:
                    self.category_k[category_i].append(data_i)

            #  更新均值向量
            self.update_category()

    def get_category(self):
        return self.category_k


    #  计算第i个数据和所有均值向量的距离,并
    def dist(self,data_i):
        dist = (self.vector_k-data_i)**2
        mean_dist = dist.mean(axis=1)
        return mean_dist.argmin()
        # print(mean_dist.argmin())

    #  计算每个类别的均值并更新均值向量
    def update_category(self):
        for i in range(0,len(self.vector_k)):
            self.vector_k[i] = np.array(self.category_k[i]).mean(axis=0)

    #  绘制散点图
    def draw_scatter(self):
        for i in self.category_k:
            x = np.array(self.category_k[i])[:,0]
            y = np.array(self.category_k[i])[:,1]
            plt.scatter(x,y)
        #  绘制均值向量点的位置
        print(self.vector_k)
        x_mean = self.vector_k[:,0]
        y_mean = self.vector_k[:,1]

        plt.title("epoch = "+str(self.epoch))
        plt.xlabel('密度')
        plt.ylabel('含糖率')
        plt.scatter(x_mean,y_mean,marker='+')
        plt.show()




def loadData(filename):
    data = open(filename, 'r', encoding='GBK')
    reader = csv.reader(data)
    headers = next(reader)
    dataset = []
    for row in reader:
        row[1] = float(row[1])
        row[2] = float(row[2])
        dataset.append([row[1],row[2]])

    return dataset

filename = '西瓜数据集4.0.csv'
traindata = loadData(filename)
kmeans = Kmeans(3,traindata,100)
print(kmeans.get_category())
kmeans.draw_scatter()

四、结果分析

在这里我们令k=3,迭代次数依次为100,500,1000次,然后根据图像来观察聚类效果,如图所示:

图中相同颜色的点表示划分为同一个簇,红色的“+”号代表最终的均值向量,标题上标注了迭代的次数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
K-means算法是一种简单有效的聚类算法,在数据挖掘和机器学习领域得到广泛应用。对于西瓜品类分析,在进行K-means算法之前,需要先对数据进行处理和数据预处理。以下是基于python语言的代码实现: 首先,安装所需库 ``` pip install pandas numpy matplotlib seaborn sklearn ``` 接着,导入所需库并读入数据 ``` import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.cluster import KMeans # 读入数据 data=pd.read_csv('watermelon.csv') ``` 数据的预处理包括去掉无用数据、数据类型转换等。该数据中无无用数据,故只需数据类型转换: ``` # 数据类型转换 data.iloc[:,2:]=data.iloc[:,2:].astype('float64') ``` 接着,按照品种名称对数据进行分组,并分别绘制出密度图和散点图以观察数据分布情况: ``` # 分组 data1=data.groupby('品种') # 绘制密度图 for i in data1: sns.distplot(i[1]['密度'],hist=False,rug=True,label=i[0]) # 绘制散点图 plt.scatter(data['密度'],data['含糖率'],c=data['品种'].astype('category').cat.codes) plt.show() ``` 绘制的结果如下图所示: ![image-20210318161715841](https://cdn.jsdelivr.net/gh/107-world/img_cdn/img_a/image-20210318161715841.png) 通过观察数据分布情况,可以考虑对密度和含糖率进行聚类分析,代码如下: ``` # 聚类 data2=data.iloc[:,2:] kmeans=KMeans(n_clusters=3,random_state=0).fit(data2) # 将聚类结果存储在dataframe中 result=pd.concat([data,pd.Series(kmeans.labels_,index=data.index)],axis=1) result.rename(columns={0:'聚类结果'},inplace=True) # 绘制聚类后的分布情况 plt.scatter(result['密度'],result['含糖率'],c=result['聚类结果'].astype('category').cat.codes) plt.show() ``` 通过绘制聚类后的分布情况,可以更直观地观察聚类结果,代码如下: ![image-20210318162328962](https://cdn.jsdelivr.net/gh/107-world/img_cdn/img_a/image-20210318162328962.png) 在本次西瓜品类分析中,我们使用K-means算法西瓜的密度和含糖率进行聚类分析,将西瓜分为三个品类,并可视化显示各品类的分布情况。K-means算法的优点是简单易懂、计算速度快,适合处理大规模的数据,但由于需要事先指定聚类数量,对初始的选择比较敏感,因此还需要对数据进行比较准确的预处理和选择合适的初始方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yozu_Roo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值