1、题目
给出一个数据集data_multivar.txt,里面有200个点坐标,在平面坐标系下可以画出它的散点图,如图11-12所示。
data_multivar.txt
图11-12 数据集 data_multivar.txt 散点图
用K均值聚类算法来训练模型,将该数据集的200个点分成4类。注意:运行之前,首先将给出的数据集data_multivar.txt 拷贝到相应的文件夹中。读者可以在程序中设置k值为2、3、5等,运行代码进行比较。
2、代码
在11.2代码基础上改这一点即可?我也不知道,哎
# K取值2
print("step2.1:聚类")
k=2
centroids,clusterAssment=kmeans(dataSetKNN1,k)
print('数据类型:',dataSetKNN1.dtype)
print("step3.1:结果输出:见'图2.png'")
showCluster(dataSetKNN1,k,centroids,clusterAssment)
# K取值3
print("step2.2:聚类")
k=3
centroids,clusterAssment=kmeans(dataSetKNN1,k)
print('数据类型:',dataSetKNN1.dtype)
print("step3.2:结果输出:见'图3.pag'")
showCluster(dataSetKNN1,k,centroids,clusterAssment)
# K取值5
print("step2.3:聚类")
k=5
centroids,clusterAssment=kmeans(dataSetKNN1,k)
print('数据类型:',dataSetKNN1.dtype)
print("step3.3:结果输出:见'图5.png'")
showCluster(dataSetKNN1,k,centroids,clusterAssment)
3、结果图
1、
2、
3、
4、
4、
4、标准答案
(1)函数
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
# 计算欧式距离,即两点间的直线距离
#参数:vector1-List列表,n维属性坐标值构成的向量
# vector2-List列表,n维属性坐标值构成的向量
#返回值:浮点数,欧式距离
def euclDistance(vector1, vector2):
return np.sqrt(np.sum(np.power(vector2 - vector1, 2)))
# 创建一个数据集,包含2个类别共8个样本
def createDataSet():
# 生成一个矩阵,每行表示一个样本
group = np.array([[1.0,0.9], [1.0,1.0], [0.8,0.9], [0.6,0.65],
[0.1, 0.2], [0.3,0.4], [0.2,0.3], [0.0, 0.1]])
# 监督学习,手工设置8个样本所属的类别标签
labels = ['A', 'A','A', 'A', 'B', 'B','B', 'B']
return group, labels
# KNN分类算法函数实现
#参数:newInput-List列表,待分类的数据点
# dataSet-List列表,已分类点坐标
# lables-List列表,分类标签
# k-整数,近邻数量
#返回值:maxIndex-字符,分类结果
def kNNClassify(newInput, dataSet, labels, k):
numSamples = dataSet.shape[0] # shape[0]表示行数
distance = []
#计算newInput与dataSet中个点的距离,放入distance列表内
for vec in dataSet:
distance.append(euclDistance(newInput,vec))
#对距离排序
sortedDistIndices = np.argsort(distance)
classCount = {}
#选择k个最近邻
for i in range(k):
voteLabel = labels[sortedDistIndices[i]]
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key
return maxIndex
#随机生成K个候选聚类中心点
#参数:dataSet-List列表,已分类点坐标
# k-整数,近邻数量
#返回值:centroids-2维列表,k个随机候选中心点坐标
def initCentroids(dataSet, k):
numSamples, dim = dataSet.shape
centroids = np.zeros((k, dim))
# 循环遍历每一列,在每一列(也就是每一维)的最小值和最大值之间产生K个随机数,作为候选中心点这一维的坐标
for j in range(dim):
# 计算每一列的最小值
minJ = min(dataSet[:, j])
# 计算每一列的范围值
rangeJ = float(max(dataSet[:, j]) - minJ)
# 计算每一列的质心,并将值赋给centroids
centroids[:, j] = minJ + rangeJ * np.random.rand(k)
return centroids
#在已有数据点中随机挑选K个作为聚类中心点
#这实际上是K中心点聚类算法的初始化方法
#参数:dataSet-List列表,已分类点坐标
# k-整数,近邻数量
#返回值:centroids-2维列表,k个随机候选中心点坐标
def initCentroids1(dataSet, k):
numSamples, dim = dataSet.shape
centroids = np.zeros((k, dim))
for i in range(k):
index = int(np.random.uniform(0, numSamples))
centroids[i, :] = dataSet[index, :]
return centroids
# K均值聚类
#参数:dataSet-List列表,待聚类样本集
# k-整数,近邻数量
#返回值:centroids-2维列表,k个随机中心点坐标
# clusterAssment -列表,各个样本点的聚类结果
def kmeans(dataSet, k):
numSamples = dataSet.shape[0]
#第一列数据存放归属的点
#第二列存放样本与候选聚类中心点之间的误差
clusterAssment = np.mat(np.zeros((numSamples, 2)))
clusterChanged = True
centroids = initCentroids(dataSet, k)
while clusterChanged:
clusterChanged = False
for i in range(numSamples):
minDist = 100000.0
minIndex = 0
#依次找出最近候选聚类中心点
for j in range(k):
distance = euclDistance(centroids[j, :], dataSet[i, :])
if distance < minDist:
minDist = distance
minIndex = j
#更新归属结果
if clusterAssment[i, 0] != minIndex:
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist**2
#更新候选聚类中心点坐标
for j in range(k):
pointsInCluster = dataSet[np.nonzero(clusterAssment[:, 0].A == j)[0]]
centroids[j, :] = np.mean(pointsInCluster, axis = 0)
print('KMN聚类完成!')
return centroids, clusterAssment
# 2维平面显示聚类结果
#参数:dataSet-List列表,样本集
# k-整数,近邻数量
# centroids-List列表,聚类中心点坐标
# clusterAssment-List列表,聚类结果
#返回值:无
def showCluster(dataSet, k, centroids, clusterAssment):
fig_2d_clustered=plt.figure()
ax2d_clustered=fig_2d_clustered.add_subplot(111)
numSamples, dim = dataSet.shape
if dim != 2:
print("只能绘制2维图形")
return 1
#创建数据点标记格式控制列表,实现数据点区别输出
mark = ['.r', '+b', '*g', '1k', '^r', 'vr', 'sr', 'dr', '<r', 'pr']
if k > len(mark):
print("K值过大!")
return 1
#绘制所有样本点
for i in range(numSamples):
markIndex = int(clusterAssment[i, 0])
ax2d_clustered.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])
#绘制聚类中心点
for i in range(k):
ax2d_clustered.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 20)
fig_2d_clustered.savefig('clusterRes.png', dpi=300, bbox_inches='tight')
fig_2d_clustered.show()
#计算代价TC
#参数:dataSet-List列表,样本集
# k-整数,近邻数量
# medoids_idx-List列表,候选中心点
# clusterAssment-List列表,聚类结果
#返回值:total_cost-浮点数,TC代价
# medoids-List2维列表,本次归属到各中心点的样本点
def totalcost(dataSet, medoids_idx) :
distances_cache = {}
size = len(dataSet)
total_cost = 0.0
medoids = {}
for idx in medoids_idx :
medoids[idx] = []
for i in range(size) :
choice = None
min_cost = 100000
#计算各样本数据点到medoids_idx的距离,将其归属到距离最近的那个中心点
for m in medoids :
tmp = distances_cache.get((m,i),None)
if tmp == None :
tmp = euclDistance(dataSet[m],dataSet[i])
distances_cache[(m,i)] = tmp
if tmp < min_cost :
choice = m
min_cost = tmp
medoids[choice].append(i)
total_cost += min_cost
return total_cost, medoids
# K中心点聚类
#参数:dataSet-List列表,待聚类样本集
# k-整数,近邻数量
#返回值:centroids-2维列表,k个中心点坐标
# clusterAssment -列表,各个样本点的聚类结果
import random
def kmedoids(dataSet, k) :
size ,dim= dataSet.shape
centroids = np.zeros((k,dim))
clusterAssment = np.mat(np.zeros((size, 2)))
medoids_idx = random.sample([i for i in range(size)], k)
pre_cost, medoids = totalcost(dataSet,medoids_idx)
current_cost = 100000
best_choice = []
best_res = {}
iter_count = 0
#反复计算TC,进行聚类
while 1 :
for m in medoids :
for item in medoids[m] :
if item != m :
idx = medoids_idx.index(m)
swap_temp = medoids_idx[idx]
medoids_idx[idx] = item
tmp,medoids_ = totalcost(dataSet,medoids_idx)
if tmp < current_cost :
best_choice = list(medoids_idx)
best_res = dict(medoids_)
current_cost = tmp
medoids_idx[idx] = swap_temp
iter_count += 1
if best_choice == medoids_idx : break
if current_cost <= pre_cost :
pre_cost = current_cost
medoids = best_res
medoids_idx = best_choice
centNum=0;
for index in best_choice:
centroids[centNum,:]=dataSet[index,:]
centNum += 1
classNumber = 0
for key in best_res:
for index in best_res[key]:
clusterAssment[index,0]=classNumber
classNumber += 1
print('KMed聚类完成!')
return centroids, clusterAssment
(2)运用
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
origData = pd.read_csv("data_multivar.txt",header=None)
dataSetKMNSize = len(origData)
dataSetKMN = np.mat(origData)
print("step1: 原始数据分布:")
for i in range(dataSetKMNSize):
plt.plot(dataSetKMN[i, 0], dataSetKMN[i, 1],'b*')
print("step 2: 聚类")
k = 4
centroids, clusterAssment = kmeans(dataSetKMN, k)
print("step 3: 结果输出:")
showCluster(dataSetKMN, k, centroids, clusterAssment)