【机器学习】吴恩达 7.x K-means与PCA

7.0 k-means聚类

使用k-means聚类算法并且将其应用于压缩图像。在第二部分中你将使用主成分分析来找到脸部图像的一个低维表示。
1.导入数据并绘制出原始数据的图案

在这里插入图片描述

data=sio.loadmat('ex7data2.mat')
print(data.keys())dict_keys#(['__header__', '__version__', '__globals__', 'X'])

X=data['X']
print(X.shape)#(300, 2)


def plot_data(x):
    plt.scatter(X[:,0],X[:,1],label='train',marker='o',c='y',edgecolors='g')
    plt.show

plot_data(X)

2.执行kmeans过程
#簇分类
def find_centroids(X,centros):
    idx=[]
    for i in range(len(X)):
        dist=np.linalg.norm((X[i]-centros),axis=1)#一范数
        id_i=np.argmin(dist)#返回最小值的索引
        idx.append(id_i)
    return np.array(idx)

centros=np.array([[3,3],[6,2],[8,5]])#初始聚类中心
idx=find_centroids(X,centros)
print(idx[:3])#[0 2 1] 距离

#计算聚类中心
def compute_centros(X,idx,k):
    centros=[]
    for i in range(k):
        centros_=np.mean(X[idx==i],axis=0)
        centros.append(centros_)
    return centros

 print(compute_centros(X,idx,k=3))
#[array([2.42830111, 3.15792418]),
# array([5.81350331, 2.63365645]),
# array([7.11938687, 3.6166844 ])]

#执行k-means
def run_kmeans(X,centros,iters):
    k=len(centros)
    centros_all=[]
    centros_all.append(centros)
    centros_i=centros
    for i in range(iters):
        idx=find_centroids(X,centros_i)
        centros_i=compute_centros(X,idx,k)
        centros_all.append(centros_i)
    return idx,np.array(centros_all)

3.绘制聚类中心点的移动轨迹

在这里插入图片描述

#绘制过程,聚类中心的移动轨迹
def plot_data1(X,centros_all,idx):
    plt.figure()
    plt.scatter(X[:,0],X[:,1],c=idx,cmap='rainbow')#rainbow数据集颜色
    plt.plot(centros_all[:,:,0],centros_all[:,:,1],'kx--')
    plt.show()

idx,centros_all=run_kmeans(X,centros,iters=100)
plot_data1(X,centros_all,idx)

完整代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.io as sio
from scipy.optimize import minimize
from sklearn.svm import SVC

data=sio.loadmat('ex7data2.mat')
#print(data.keys())dict_keys(['__header__', '__version__', '__globals__', 'X'])

X=data['X']
#print(X.shape)(300, 2)


def plot_data(x):
    plt.scatter(X[:,0],X[:,1],label='train',marker='o',c='y',edgecolors='g')
    plt.show

#plot_data(X)

#簇分类
def find_centroids(X,centros):
    idx=[]
    for i in range(len(X)):
        dist=np.linalg.norm((X[i]-centros),axis=1)#一范数 每个点的绝对值之和
        id_i=np.argmin(dist)#返回最小值的索引,并将其归属到距离最小的簇类中心所对应的类中;
        idx.append(id_i)
    return np.array(idx)

centros=np.array([[3,3],[6,2],[8,5]])#初始聚类中心
idx=find_centroids(X,centros)
#print(idx[:3])[0 2 1] 距离

#重新计算聚类中心
def compute_centros(X,idx,k):
    centros=[]
    for i in range(k):
        centros_=np.mean(X[idx==i],axis=0)
        centros.append(centros_)
    return centros#新的三个聚类中心

# print(compute_centros(X,idx,k=3))
#[array([2.42830111, 3.15792418]),
# array([5.81350331, 2.63365645]),
# array([7.11938687, 3.6166844 ])]

#执行k-means
def run_kmeans(X,centros,iters):
    k=len(centros)#聚类中心的个数
    centros_all=[]
    centros_all.append(centros)
    centros_i=centros
    for i in range(iters):#迭代100次,计算聚类中心
        idx=find_centroids(X,centros_i)
        centros_i=compute_centros(X,idx,k)
        centros_all.append(centros_i)
    return idx,np.array(centros_all)


#绘制过程,聚类中心的移动轨迹
def plot_data1(X,centros_all,idx):
    plt.figure()
    plt.scatter(X[:,0],X[:,1],c=idx,cmap='rainbow')#rainbow数据集颜色 绘制散点图,并依据idx将不同的类标记为不同的颜色
    plt.plot(centros_all[:,:,0],centros_all[:,:,1],'yx--')#绘制折线图 y黄色 ×号x 虚线--
    plt.show()

idx,centros_all=run_kmeans(X,centros,iters=100)
plot_data1(X,centros_all,idx)


在这里插入图片描述
在这里插入图片描述

完整代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.io as sio
from skimage import io
import pylab



#簇分类
def find_centroids(X,centros):
    idx=[]
    for i in range(len(X)):
        dist=np.linalg.norm((X[i]-centros),axis=1)#一范数 每个点的绝对值之和
        id_i=np.argmin(dist)#返回最小值的索引,并将其归属到距离最小的簇类中心所对应的类中;
        idx.append(id_i)
    return np.array(idx)

centros=np.array([[3,3],[6,2],[8,5]])#初始聚类中心


#重新计算聚类中心
def compute_centros(X,idx,k):
    centros=[]
    for i in range(k):
        centros_=np.mean(X[idx==i],axis=0)
        centros.append(centros_)
    return centros#新的三个聚类中心


#执行k-means
def run_kmeans(X,centros,iters):
    k=len(centros)#聚类中心的个数
    centros_all=[]
    centros_all.append(centros)
    centros_i=centros
    for i in range(iters):#迭代100次,计算聚类中心
        idx=find_centroids(X,centros_i)
        centros_i=compute_centros(X,idx,k)
        centros_all.append(centros_i)
    return idx,np.array(centros_all)



data=sio.loadmat('bird_small.mat')
#print(data.keys())(['__header__', '__version__', '__globals__', 'A'])
A=data['A']
#print(A.shape)(128, 128, 3)

#初始化聚类中心
def KMeansInitCentroids(x,K):
    randidx=np.random.permutation(x)#随机排列 不在原数组上进行,返回新的数组,不改变自身数组。
    centroids=randidx[:K,:]#前k行
    return centroids

image=io.imread('bird_small.png')
# plt.imshow(image)
# plt.axis('off')#去掉坐标轴
# plt.show()

A=A/255 #标准化
A=A.reshape(-1,3)#3列
#print(A.shape)(16384, 3)

k=16#16种颜色
centroids=KMeansInitCentroids(A,k)
#print(centroids.shape)(16, 3)

idx,centros_all=run_kmeans(A,centroids,iters=20)
centros=centros_all[-1]#取迭代完的最后一个
im=np.zeros(A.shape)
for i in range(k):#将一个聚类的颜色变成聚类中心的颜色
    im[idx==i]=centros[i]
im=im.reshape(128,128,3)
plt.imshow(im)
plt.show()

降维,可视化自己的图片

原图

在这里插入图片描述

处理后的

在这里插入图片描述

import matplotlib.pyplot as plt
import numpy as np
import scipy.io as sio
import matplotlib.image as mpimg
from sklearn.cluster import  MiniBatchKMeans


pic=mpimg.imread('./stray_kids.jpg')
# print(pic)
data=pic/255#不是0-1需要除以255
# print(data.shape[0])1152
#print(data.shape[1])2048
data=data.reshape(data.shape[0]*data.shape[1],3)

k=16
# MiniBatchKMeans聚类
kmeans = MiniBatchKMeans(k,n_init= 'auto')#因为版本变更,需要加上n_init= 'auto'
kmeans.fit(data)  # 先fit
picture_recolored = kmeans.cluster_centers_[kmeans.predict(data)]  # 再predict,然后再分配标记的聚类中心的RGB编码
picture_recolored = picture_recolored.reshape(pic.shape)

# 画图
fig, axes = plt.subplots(1, 2, figsize=(10, 10))
axes[0].imshow(pic)
axes[0].set_title('Original')
axes[1].imshow(picture_recolored)
axes[1].set_title('Compressed, with %d colors' % k)  # .set_title可以给子图加标题。

# 保存,观察文件大小是否变化
mpimg.imsave('recoverd.jpeg', picture_recolored)

PCA主成分分析

首先用一个二维的样本集来实验,对PCA如何运行的有一个直观的感受,然后再在一个更大的由5000个人脸图像组成的数据集上实现PCA。

1.导入数据并可视化

data=sio.loadmat('ex7data1.mat')
X=data['X']
print(X.shape)

plt.scatter(X[:,0],X[:,1])
plt.show()
2.标准化数据

在这里插入图片描述

#对数据标准化
def demean(X):
    mean=X.mean(axis=0)#每列均值 mu
    std=X.std(axis=0,ddof=1)#计算的是样本的标准差 sigma
    X=(X-mean)/std #x_norm
    return X,mean,std

X_demean,X_mean,X_std=demean(X)
plt.scatter(X_demean[:,0],X_demean[:,1])
plt.show()

3.计算协方差与特征向量

在这里插入图片描述

def pca(x):
    m=len(X)
    C=(x.T@x)/m#计算协方差 主对角线是x的方差,副对角线是X的协方差
    U,S,V=np.linalg.svd(C)#SVD奇异值分解计算特征向量U
    return U,S
U,S=pca(X_demean)
#比较两个不同的特征向量(第1列和第2列)哪个投影误差更小,画出以数据均值为中心的特征向量,取U矩阵中第1列得到矩阵
print(U)

plt.figure(figsize=(6,6))
plt.scatter(X[:,0],X[:,1],marker='o',facecolors='none',edgecolors='b')
plt.plot([X_mean[0],X_mean[0]+1.5*S[0]*U[0,0]], [X_mean[1], X_mean[1]+1.5*S[0]*U[1,0]],c='r', label='First')#两个点的连线
plt.plot([X_mean[0],X_mean[0]+1.5*S[1]*U[0,1]], [X_mean[1], X_mean[1]+1.5*S[1]*U[1,1]] ,c='g',label='Second')#1.5和s表示特征向量的长度
plt.title('Computed eigenvectors of the dataset')
plt.grid()
plt.show()

4.将均值化后的数据投影到特征向量上,实现降维,并重构数据得到数据的近似值

在这里插入图片描述

#pca降维
#将数据投影在主成分上
def projectData(X,U,K):
    Z=X@U[:,:K]
    return Z
Z=projectData(X_demean,U,1)

#重构数据
def recoverData(Z,U,K):
    X_rec=Z@U[:,:K].T
    return X_rec
X_rec=recoverData(Z,U,1)
plt.figure()
plt.scatter(X_rec[:,0],X_rec[:,1],facecolors='none',edgecolors='b')
plt.show()
5.可视化投影

在这里插入图片描述

#直观地看降维过程
plt.figure()
plt.axis('equal')
plot=plt.scatter(X_demean[:,0],X_demean[:,1],s=30,facecolors='none',edgecolors='b',label='Original Data Points')
plot=plt.scatter(X_rec[:,0],X_rec[:,1],s=30,facecolors='none',edgecolors='r',label='PCA Data Points')
plt.grid(True)
for x in range(X_demean.shape[0]):
    plt.plot([X_demean[x,0],X_rec[x,0]],[X_demean[x,1],X_rec[x,1]],'k--')
plt.legend()
plt.show()


完整代码

import matplotlib.pyplot as plt
import numpy as np
import scipy.io as sio
import matplotlib.image as mpimg
from sklearn.cluster import  MiniBatchKMeans


data=sio.loadmat('ex7data1.mat')
X=data['X']
#print(X.shape)(50, 2)

# plt.scatter(X[:,0],X[:,1])
# plt.show

#对数据标准化
def demean(X):
    mean=X.mean(axis=0)#每列均值 mu
    std=X.std(axis=0,ddof=1)#计算的是样本的标准差 sigma
    X=(X-mean)/std #x_norm
    return X,mean,std

X_demean,X_mean,X_std=demean(X)
plt.scatter(X_demean[:,0],X_demean[:,1])
plt.show

def pca(x):
    m=len(X)
    C=(x.T@x)/m#计算协方差
    U,S,V=np.linalg.svd(C)#SVD奇异值分解计算特征向量U
    return U,S
U,S=pca(X_demean)

plt.figure(figsize=(6,6))
plt.scatter(X[:,0],X[:,1],marker='o',facecolors='none',edgecolors='b')
plt.plot([X_mean[0],X_mean[0]+1.5*S[0]*U[0,0]], [X_mean[1], X_mean[1]+1.5*S[0]*U[1,0]],c='r', label='First')#两个点的连线
plt.plot([X_mean[0],X_mean[0]+1.5*S[1]*U[0,1]], [X_mean[1], X_mean[1]+1.5*S[1]*U[1,1]] ,c='g',label='Second')#1.5和s表示特征向量的长度
plt.title('Computed eigenvectors of the dataset')
plt.grid()
plt.show

#pca降维
#将数据投影在主成分上
def projectData(X,U,K):
    Z=X@U[:,:K]
    return Z
Z=projectData(X_demean,U,1)

#重构数据
def recoverData(Z,U,K):
    X_rec=Z@U[:,:K].T
    return X_rec
X_rec=recoverData(Z,U,1)
plt.figure()
plt.scatter(X_rec[:,0],X_rec[:,1],facecolors='none',edgecolors='b')
plt.show

#直观地看降维过程
plt.figure()
plt.axis('equal')
plot=plt.scatter(X_demean[:,0],X_demean[:,1],s=30,facecolors='none',edgecolors='b',label='Original Data Points')
plot=plt.scatter(X_rec[:,0],X_rec[:,1],s=30,facecolors='none',edgecolors='r',label='PCA Data Points')
plt.grid(True)
for x in range(X_demean.shape[0]):
    plt.plot([X_demean[x,0],X_rec[x,0]],[X_demean[x,1],X_rec[x,1]],'k--')
plt.legend()
plt.show()

#查看降维后的数据保留了原始数据多少差异性
def retained_variance(S,K):
    rv=np.sum(S[:K])/np.sum(S)
    return print('{:.2f}%'.format(rv*100))

# print(retained_variance(S,1))86.78%

实际应用

在这里插入图片描述

在这里插入图片描述

完整代码

import matplotlib.pyplot as plt
import numpy as np
import scipy.io as sio
import matplotlib.image as mpimg
from sklearn.cluster import  MiniBatchKMeans

mat=sio.loadmat('ex7faces.mat')
#print(mat.keys())dict_keys(['__header__', '__version__', '__globals__', 'X'])
A=mat['X']
# print(A.shape)(5000, 1024)
def plot_100_images(A):
    fig,axs=plt.subplots(ncols=10,nrows=10,figsize=(10,10))
    #在每个子画布里画一个图像
    for c in range(10):
        for r in range(10):
            axs[c,r].imshow(A[10*c+r].reshape(32,32).T,cmap='Greys_r')#显示单通道的灰图
            axs[c,r].set_xticks([])
            axs[c,r].set_yticks([])


A_demean=A-np.mean(A,axis=0)#A去均值化
C=A_demean.T@A_demean/len(A)#协方差
U,S,V=np.linalg.svd(C)#特征值 特征向量
U1=U[:,:36]
# print(U.shape)(1024, 1024)
# print(U1.shape)(1024, 36)
A_reduction=A_demean@U1#降维
# print(A_reduction.shape)(5000, 36)
A_recover=A_reduction@U1.T+np.mean(A,axis=0)#重构
plot_100_images(A_recover)
plot_100_images(A)#前后对比
plt.show()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值