一、实验目的
1.理解聚类的过程
2.理解并掌握K-均值算法的过程
3.理解PCA算法进行降维的原理和步骤
二、实验内容及要求:
1.实验数据:iris数据,一共150个数据,每个数据包含4个特征,假设样本类别未知,但已知类别数为3。
2.实验要求
1)采用PCA的方式将原始特征进行降维,要求降维后的特征能够保留原始特征80%以上的信息;
2)将降维后的新特征在新的特征空间画出样本点;
3)采用K-均值算法对降维后的特征进行分类,并画出分类后的样本点(以不同的颜色进行表示);要求分别采用两种不同的初始代表点的确定方法,比较分类结果的不同;并与样本的真实类别进行比较,计算错误率。
4)对实验结果进行分析,分析初始代表点的不同对分类结果的影响。
5)使用python实现。
三、实验代码
# coding:utf-8
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
def pplt(df, test_point=[0, 0], flag=0):
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.scatter(df[:45, 0], df[:45, 1], df[:45, 2], c='r', label="points 1")
ax.scatter(df[45:90, 0], df[45:90, 1], df[45:90, 2], c='g', label="points 2")
ax.scatter(df[90:135, 0], df[90:135, 1], df[90:135, 2], c='b', label="points 3")
if flag == 1:
ax.scatter(test_point[0], test_point[1], test_point[2], c='black', label='test_point')
plt.legend()
plt.show()
def pca(data, n_components):
'''
pca is O(D^3)
:param data: (n_samples, n_features(D)) 135*3
:param n_dim: target dimensions
:return: (n_samples, n_components)
'''
# 减去均值,也可以进行标准化处理(除以方差)
data = data - np.mean(data, axis=0, keepdims=True)
# print(data.shape)
# 计算协方差矩阵
# cov_matrix = 1 / m * np.matmul(data.T, data)
cov_matrix = np.cov(data, rowvar = False) # or
# 计算协方差矩阵特征值及对于的特征向量
eig_values, eig_vector = np.linalg.eig(cov_matrix) # 1*3 3*3
# print(eig_values)
# 对特征值进行排序,并取前n_components组
indexs_ = np.argsort(-eig_values)[:n_components] # 将矩阵a按照axis(0列1行)排序,并返回排序后的下标 - 降序排
picked_eig_values = eig_values[indexs_]
picked_eig_vector = eig_vector[:, indexs_] # 3*2
# print(picked_eig_vector)
data_ndim = np.matmul(data, picked_eig_vector)
# print(data_ndim.shape)
return data_ndim
# data 降维的矩阵(n_samples, n_features)
# n_dim 目标维度
# fit n_features >> n_samples, reduce cal
# 寻址每个样本其最近的中心点
def find_closest_centroids(X, centroids):
m = X.shape[0]
k = centroids.shape[0]
idx = np.zeros(m)
for i in range(m):
min_dist = 1000000
for j in range(k):
# 计算每个训练样本和中心点的距离
dist = np.sum((X[i, :] - centroids[j, :]) ** 2)
if dist < min_dist:
# 记录当前最短距离和其中心的索引值
min_dist = dist
idx[i] = j
return idx
# 计算聚类中心
def compute_centroids(X, idx, k):
m, n = X.shape
centroids = np.zeros((k, n))
for i in range(k):
indices = np.where(idx == i) # X中归类到0 1 2 代表点的下标存入indices
# print('indices',i,indices)
# 计算下一个聚类中心,这里简单的将该类中心的所有数值求平均值作为新的类中心
centroids[i, :] = (np.sum(X[indices, :], axis=1) / len(indices[0])) #.ravel() # 只返回原始数组的引用/视图
# print(centroids.shape)
return centroids
# 初始化聚类中心
def init_centroids(X, k):
m, n = X.shape
print('initial m,n,k',m,n,k)
centroids = np.zeros((k, n))
'''
1)随机选择代表点 k个
'''
# 随机初始化 k 个 [0,m]的整数
idx = np.random.randint(0, m, k) # 0 - 150 步长k
# print(centroids.shape)
for i in range(k):
centroids[i, :] = X[idx[i], :]
# print(idx[i], i, centroids[i, :])
'''
2)用前c个样本点作为代表点
'''
# idx = np.random.randint(0, 50, 1)
# centroids[0, :] = X[idx, :]
# centroids[1, :] = X[idx+50, :]
# centroids[2, :] = X[idx+100, :]
print('centroids',centroids)
return centroids
'''
首先选择K个随机的点,称其为聚类中心
对于数据集中的每一个数据,按照距离K个中心点的距离,将其与距离最近的中心点关联起来,与同一个中心点关联的所有点聚成一个类
计算每一个组的平均值,将该组所关联的中心点移动到平均值的位置
重复步骤2-3,直到中心点不再变化
'''
# 实现 kmeans 算法
def run_k_means(X, initial_centroids, max_iters):
'''
:param X: 样本
:param initial_centroids:聚类中心
:param max_iters: 迭代次数
:return:
'''
m, n = X.shape
# 聚类中心的数目
k = initial_centroids.shape[0]
print('聚类中心的数目',k)
idx = np.zeros(m)
centroids = initial_centroids
# print('centroids',centroids)
for i in range(max_iters):
idx = find_closest_centroids(X, centroids)
# 聚类中心更新
centroids = compute_centroids(X, idx, k)
return idx, centroids
def defalt(real,pre,X):
m= X.shape[0]
right = 0
for i in range(m):
if real[i] == pre[i]+1:
# print(real[i],pre[i])
right += 1
return right / m
if __name__ == "__main__":
f_train1 = np.loadtxt("iris训练数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3, 4]) # 使用第123个特征
f_train2 = np.loadtxt("iris测试数据.txt", dtype=np.double, delimiter='\t', usecols=[0, 1, 2, 3, 4])
data = (np.r_[f_train1[0:25], f_train2[0:25], f_train1[25:50], f_train2[25:50], f_train1[50:75], f_train2[
50:75]]) # 135* 4 里面np.r 是元组 转置后是矩阵
lable = data[:, 0]
# # print(test[0, :])
# data = load_iris()
# X = data.data
# Y = data.target
data_pca = pca(data[:, 1:5], 2)
# data_2d1 = pca(X, 2)
plt.figure(figsize=(8, 4))
# plt.subplot(121)
plt.title("after_PCA")
plt.scatter(data_pca[:, 0], data_pca[:, 1], c=data[:, 0])
# plt.scatter(data_2d1[:, 0], data_2d1[:, 1], c=Y)
# sklearn_pca = PCA(n_components=2)
# data_2d2 = sklearn_pca.fit_transform(train[:, 1:4])
# data_2d2 = sklearn_pca.fit_transform(X)
# plt.subplot(122)
# plt.title("sklearn_PCA")
# plt.scatter(data_2d2[:, 0], data_2d2[:, 1], c=train[:, 0])
# plt.scatter(data_2d2[:, 0], data_2d2[:, 1], c=Y)
# plt.show()
X = data_pca
initial_centroids = init_centroids(X, 3)
# print(initial_centroids)
# idx = find_closest_centroids(X, initial_centroids)
# print(idx)
# print(compute_centroids(X, idx, 3))
idx, centroids = run_k_means(X, initial_centroids, 10)
# print('idx',idx)
right = defalt(lable,idx,X)
print('正确率',right)
# 可视化聚类结果
cluster1 = X[np.where(idx == 0)[0], :]
cluster2 = X[np.where(idx == 1)[0], :]
cluster3 = X[np.where(idx == 2)[0], :]
fig, ax = plt.subplots(figsize=(12, 8))
ax.scatter(centroids[:, 0], centroids[:, 1], s=60, color='yellow', label='Point of Representation')
ax.scatter(cluster1[:, 0], cluster1[:, 1], s=30, color='r', label='Cluster 1')
ax.scatter(cluster2[:, 0], cluster2[:, 1], s=30, color='g', label='Cluster 2')
ax.scatter(cluster3[:, 0], cluster3[:, 1], s=30, color='b', label='Cluster 3')
ax.legend()
plt.show()