学习感言
前段时间学习了吴恩达机器学习的聚类算法,带着复习一下基础的实现。其中还有可以优化的地方。比如计算距离度量时,除了使用欧式距离,还可以使用曼哈顿距离、余弦相似度函数。在此先欠个账后续再把这些学习一下。
文章目录
- 聚类算法简介
- K-means聚类算法详解
- python实现+代码解释
- 完整可运行代码
数据集链接: 点击获取数据集
一、聚类算法简介
聚类算法是一种无监督学习方法,用于将数据集中的样本划分为若干个不相交的子集,即“簇”。每个簇可能对应与一些潜在的概念或类别,但这些概念或类别在聚类之前都是未知的。聚类算法的目的是将相似的对象聚集在一起,而不相似的对象则分散在不同的簇中。
二、K-means聚类算法详解
k-means聚类算法是一种常用的无监督学习算法,用于将一组数据点划分为k个不同类别。它的目标是将数据点划分到k个簇群中,使得同一簇内的点相互之间的距离最小化(本文采用欧式距离),而不同簇之间的距离最大化。
算法步骤如下:
- 随机选择k个初始聚类质心
- 将每个数据点分配到与其最近的聚类中心点所属的簇中。
- 对于每个簇,重新计算其簇群的质心(把簇群中的所有点取平均值)
- 重复步骤2和步骤3,直到聚类中心(质心)的变化量为0时停止,或者达到预期迭代的次数
距离度量:(在数据点分配过程中计算数据点与质心之间的距离策略)
将对象点分到距离聚类中心最近的那个簇中需要最近邻的度量策略,在欧式空间中采用的是欧式距离,在处理文档中采用的是余弦相似度函数,有时候也采用曼哈顿距离作为度量,不同的情况实用的度量公式是不同的。
二维平面欧式距离计算公式:
多维欧式空间计算公式:
三、python实现+代码详解
1.初始化主函数以及可视化聚类图 其中数据集以及簇群等都是以坐标形式保存 代码案例 k=4
if __name__ == '__main__':
dataSet = createDataSet() # 获取数据集
centroids,cluster = kmeans(dataSet,4) # 参数4代表簇心,获取簇群以及质心
print('质心为: %s'% centroids)
print('集群为: %s'% cluster)
for i in range(len(dataSet)):
plt.scatter(dataSet[i][0],dataSet[i][1],marker = 'x',color = 'blue',s = 50,label='原始点')
for i in range(len(centroids)):
plt.scatter(centroids[j][0],centroids[j][1],marker = 'o',color ='red',s=50,label='质心')
plt.show()
2. 创建数据集 将数据集中的数据以坐标形式保存
def createDataSet():
t = pd.read_csv('data.csv')
df = pd.DataFrame(t)
df = df.values # 获取df的值 以矩阵形式表示
arry = [] # 用于保存坐标
for i in range(0,79):
arr = []
arr.append(df[i,0])
arr.append(df[i,1])
arry.append(arr)
return arry
3.使用k-means分类
def kmeans(dataSet,k):
# 随机取k个样本作为质心
centroids = random.sample(dataSet,k)
# 更新质心 直到变化量为0
changed,newCentroids = classify(dataSet,centroids,k)
while np.any(changed != 0):
changed,newCentroids = classify(dataSet,centroids,k)
centroids = sorted(newCentroids.tolist())
# 根据质心计算每个集群
cluster = []
clalist = calcDis(dataSet,centroids,k) # 调用欧式距离 获得离最后质心距离最近的集群
minDisIndics = np.argmin(clalist,axis=1)
for i in range(k):
cluster.append([])
for i,j in enumerate(minDisIndics):
cluster[j].append(dataSet[i]) # 将数据集各个坐标添加到对应集群中
return centroids,cluster
4.计算质心
def classify(dataSet,centroids,k):
# 计算样本到质心的距离 (欧式距离)根据上述公式
clalist = calcDis(dataSet,centroids,k)
# 分组计算新的质心
minDisIndics = np.argmin(clalist,axis=1) # 求出每行最小值的下标
# DataFrame(dataSet)表按照groupby(min)进行坐标分组 然后计算分类后坐标群的平均值
newCentroids = pd.DataFrame(dataSet).groupby(minDisIndics).mean()
newCentroids = newCentroids.values
# 计算坐标变化量
changed = newCentroids - centroids
return changed,newCentroids
5.计算欧拉距离 根据文章第一部分公式代入坐标
def calcDis(dataSet, centroids, k):
clalist = []
for data in dataSet:
diff = np.tile(data, (k,1)) - centroids # 将坐标复制k份 分别计算到各个质心的距离
squaredDiff = diff**2
squareDist = np.sum(squaredDiff,axis=1)
distance = squareDist**0.5 # 开方
clalist.append(distance)
clalist = np.array(clalist)
return clalist
6.运行结果展示
四、完整可运行代码
import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 计算欧拉距离
def calcDis(dataSet, centroids,k):
clalist = []
for data in dataSet:
diff = np.tile(data,(k,1))-centroids
squaredDiff = diff**2
squaredDist = np.sum(squaredDiff,axis=1)
distance = squaredDist**0.5
clalist.append(distance)
clalist = np.array(clalist)
return clalist
# 计算质心
def classify(dataSet,centroids,k):
# 计算样本到质心的距离
clalist = calcDis(dataSet,centroids,k)
# 分组计算新的质心
minDisIndics = np.argmin(clalist,axis=1) # 求出每行最小值的下标
# DataFramte(dataSet)对DataSet分组,groupby(min)按照min进行统计分类,mean()对分类结果求均值
newCentroids = pd.DataFrame(dataSet).groupby(minDisIndics).mean()
newCentroids =newCentroids.values
# 计算变化量
changed = newCentroids - centroids
return changed,newCentroids
#使用k-means分类
def kmeans(dataSet,k):
# 随机取质心
centroids = random.sample(dataSet,k)
#更新质心 直到变化量为0
changed, newCentroids = classify(dataSet,centroids,k)
while np.any(changed != 0):
changed,newCentroids = classify(dataSet,newCentroids,k)
centroids = sorted(newCentroids.tolist())
#根据质心计算每个集群
cluster = []
clalist = calcDis(dataSet,centroids,k) #调用欧拉距离
minDisIndics = np.argmin(clalist,axis=1)
for i in range(k):
cluster.append([])
for i, j in enumerate(minDisIndics):
cluster[j].append(dataSet[i])
return centroids,cluster
# 创建数据集
def createDataSet():
t = pd.read_csv('data.csv')
df = pd.DataFrame(t)
df = df.values
arry = []
for i in range(0,79):
arr = []
arr.append(df[i,0])
arr.append(df[i,1])
arry.append(arr)
return arry
if __name__ == '__main__':
dataSet = createDataSet()
centroids,cluster = kmeans(dataSet,4)
print('质心为: %s'% centroids)
print('集群为: %s'% cluster)
for i in range(len(dataSet)):
plt.scatter(dataSet[i][0],dataSet[i][1],marker = 'x',color = 'blue',s=50,label='原始点')
for j in range(len(centroids)):
plt.scatter(centroids[j][0], centroids[j][1], marker='o', color='red', s=50, label='质心')
plt.show()