首先介绍一下(yuan)鸢尾花数据集,该数据集测量了所有150个样本的4个特征单位都是cm,分别是:
1.sepal length(花萼长度)
2.sepal width(花萼宽度)
3.petal length(花瓣长度)
4.petal width(花瓣宽度)
对应一个150行4列的矩阵,本文思路是通过PCA压缩数据将其从150行四列变成150行3列,4维变3维(每个特征对应一个维度)
在网上看了很多,k-means和PCA的结果都是二维的,我想用三维图来展示分类的的效果图就自己将代码改了一下。发个博客记录一下代码,思想大概就是将鸢尾花4维的数据转为三维后再使用k-means分类,因为提前知道了这些数据是来自三类的花,所以提前给出K-means要分类的个数为3,算法会提前随机给3个类似于重心的东西,然后离重心近的会被分到该簇。之后每个簇的重心会随着其簇内样本的增加不断改变。重心大概就是结果图中X所在的位置。
#coding=utf-8
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
from mpl_toolkits.mplot3d import Axes3D
from sklearn.cluster import KMeans
import numpy as np
##计算欧式距离
def distEuclid(x, y):
return np.sqrt(np.sum((x - y) ** 2))
##随机产生n个dim维度的数据 (这里为了展示结果 dim取2或者3)
def genDataset(n, dim):
data = []
while len(data) < n:
p = np.around(np.random.rand(dim) * size, decimals=2)
data.append(p)
return data
## 初始化簇中心点 一开始随机从样本中选择k个 当做各类簇的中心
def initCentroid(data, k):
num, dim = data.shape
centpoint = np.zeros((k, dim))
l = [x for x in range(num)]
np.random.shuffle(l)
for i in range(k):
index = int(l[i])
centpoint[i] = data[index]
return centpoint
##进行KMeans分类
def KMeans(data, k):
##样本个数
num = np.shape(data)[0]
##记录各样本 簇信息 0:属于哪个簇 1:距离该簇中心点距离
cluster = np.zeros((num, 2))
cluster[:, 0] = -1
##记录是否有样本改变簇分类
change = True
##初始化各簇中心点
cp = initCentroid(data, k)
while change:
change = False
##遍历每一个样本
for i in range(num):
minDist = 9999.9
minIndex = -1
##计算该样本距离每一个簇中心点的距离 找到距离最近的中心点
for j in range(k):
dis = distEuclid(cp[j], data[i])
if dis < minDist:
minDist = dis
minIndex = j
##如果找到的簇中心点非当前簇 则改变该样本的簇分类
if cluster[i, 0] != minIndex:
change = True
cluster[i, :] = minIndex, minDist
## 根据样本重新分类 计算新的簇中心点
for j in range(k):
pointincluster = data[[x for x in range(num) if cluster[x, 0] == j]]
cp[j] = np.mean(pointincluster, axis=0)
print("finish!")
return cp, cluster
##展示结果 各类簇使用不同的颜色 中心点使用X表示
def Show(data, k, cp, cluster):
num, dim = data.shape
color = ['b', 'r', 'g', 'c', 'y', 'm', 'k']
##二维图
if dim == 2:
for i in range(num):
mark = int(cluster[i, 0])
plt.plot(data[i, 0], data[i, 1], color[mark] + 'o')
for i in range(k):
plt.plot(cp[i, 0], cp[i, 1], color[i] + 'x')
##三维图
elif dim == 3:
ax = plt.subplot(122, projection='3d')
for i in range(num):
mark = int(cluster[i, 0])
ax.scatter(data[i, 0], data[i, 1], data[i, 2], c=color[mark])
ax.set_title('k-means result')
for i in range(k):
ax.scatter(cp[i, 0], cp[i, 1], cp[i, 2], c=color[i], marker='x')
plt.show()
if __name__ == "__main__":
data = load_iris()#以字典形式加载鸢尾花数据集
y = data.target #使用y表示数据集中的标签
x = data.data #使用x表示数据集中的属性数据
#使用PCA 算法,设置降维后主成分数目为 2
#print(x,'\n', y)
#print(x)
#print(type(x))
size = 20 ##取值范围
pca = PCA(n_components=3)
#对原始数据进行降维,保存在 reduced_X 中
reduced_X = pca.fit_transform(x)
print('降维后的数据为:\n',reduced_X)#降维后的数据
print('各主成分方差解释度为:',pca.explained_variance_ratio_)#方差解释度
print('主成分对应的载荷矩阵为',pca.components_)
red_x, red_y , red_z = [], [],[]
blue_x, blue_y , blue_z= [], [],[]
green_x, green_y, green_z=[],[],[]
for i in range(len(reduced_X)):
#标签为0时,3维标签数据保存到列表red_x,red_y,redz中
if y[i] == 0:
red_x.append(reduced_X[i][0])
red_y.append(reduced_X[i][1])
red_z.append(reduced_X[i][2])#
elif y[i] == 1:
blue_x.append(reduced_X[i][0])
blue_y.append(reduced_X[i][1])
blue_z.append(reduced_X[i][2])#
else:
green_x.append(reduced_X[i][0])
green_y.append(reduced_X[i][1])
green_z.append(reduced_X[i][2])#
X = reduced_X[:, :3] # #表示我们取特征空间中的3个维度
#print(X.shape)
#print(X)
#print(type(X))
num = 50 ##点个数
k=3 ##分类个数
data = X
cp,cluster = KMeans(data,k)
ax=plt.figure().add_subplot(121,projection='3d')
ax.scatter(red_x, red_y,red_z,c='r', marker='o')
ax.scatter(blue_x, blue_y,blue_z,c='b', marker='o')
ax.scatter(green_x, green_y,green_z,c='g', marker='o')#散点图中用s,其余图用markersize可调节散点的大小
ax.set_title('PCA result')
Show(data,k,cp,cluster)