机器学习实战笔记4——主成分分析

任务安排

1、机器学习导论       8、核方法
2、KNN及其实现       9、稀疏表示
3、K-means聚类      10、高斯混合模型
4、主成分分析          11、嵌入学习
5、线性判别分析      12、强化学习
6、贝叶斯方法          13、PageRank
7、逻辑回归              14、深度学习

主成分分析(PCA)

Ⅰ 算法背景:维数灾难

      维数灾难最早是由理查德·贝尔曼(Richard E. Bellman)在考虑优化问题时提出来的 ,它用来描述当(数学)空间维度增加时,分析和组织高维空间(通常有成百上千维)中的数据,因体积指数增加而遇到各种问题场景。
      维数灾难这个概念具有的共同特点是:当维度增加时,空间的体积增加得很快,使得可用的数据变得稀疏。

      生活中多维数据比较的例子很多,比如人的三围及身高体重、游戏角色的六维属性等等。我们拿大家最熟悉的成绩来说,小学时,我们可能只有语数英三科(三维),想要和小伙伴比较成绩,关键看到底是哪一个科目某一特征值)具体影响了我们之间的差距,因为科目不多,还比较容易,但到了中学,我们可能要学八科、九科、十科…,身边小伙伴也变多了,想要比较起来就没有之前那么容易了,而当分析某一数学问题时,可能有成百上千维的数据,样本个数也不在少数,那么总体分析就显得举步维艰。因此,我们就想让数据变得简单一些,就有了维数约简思想。

Ⅱ 维数约简

      维数约简又称降维,是机器学习的一种必要手段。若数据 X = X= X={ x i x_i xi} 是属于 n n n 维空间的,通过特征提取或者特征选择的方法,将原空间的维数降至 k k k 维,要求 k k k 远小于 n n n,并满足: k k k 维空间的特性能反映原空间数据的特征,这个过程称之为维数约简
      维数约简即通过某种数学变换,将原始高维属性空间转变为一个低维子空间,在这个子空间中样本密度大幅度提高,距离计算也变得容易起来
在这里插入图片描述
      由线性代数的知识我们知道,空间维度的改变依赖于变换矩阵,如 X X X 是一个 n n n 维列向量 X = [ 1 , 2 , . . . , n ] T X=[1,2,...,n]^T X=[1,2,...,n]T,我们想要把它变成 Y = [ 1 , 2 , . . . , m ] T Y=[1,2,...,m]^T Y=[1,2,...,m]T,即在 X X X 前面乘上一个 m × n m×n m×n变换矩阵 A A A
      而主成分分析,就是降维里的一种重要方法。

      既然要对已有的特征值进行降维变换,那么首先,我们要先得到原样本集的特征值,回顾一下线性代数的知识。
      有一个 n n n 阶矩阵 A A A,若存在数 λ λ λ 和非零 n n n 维列向量 X X X,满足 A X = λ X AX=λX AX=λX,则称 λ λ λ A A A 的一个特征值, X X X A A A 的对应于 λ λ λ 的一个特征向量

Ⅲ 核心思想

      主成分分析(Principal Component Analysis) 的出发点是从一组特征 ( n n n 维)中计算出一组按重要性从大到小排列的新特征( k k k 维, k ≤ n k≤n kn,通常取远小于 n n n),它们是原有特征的线性组合,并且相互之间不相关。(比如你和小伙伴的理科成绩非常接近,那么决定你们之间差距的主要科目 (新特征值PC) 就是文科类的了,只关注这几科,即降维了)

①主成分特点

      1. 源于质心的矢量
      2. 主成分 ① 指向最大方差的方向
      3. 各后续主成分与前一主成分正交,且指向残差(剩余)子空间最大方差的方向

②举例(二维)

为了便于分析说明,我们举二维样本集的例子:
      如下图所示,红色的两向量表示“蓝色椭圆”的长轴短轴,很明显可以看出,假如我们把样本集的点投影到长轴上更能反映出样本集整体的分布,故在这个例子里我们把长轴记为主成分#1与长轴正交(互不相关)的短轴记为主成分#2,理想情况下,短轴的模(高维情况下称范数)为 0,即仅通过长轴就可以完全分析出样本集的分布,这就实现了完美的降维,因而我们容易知道,长短轴的模(范数)相差越大,即降维的效果越好,所以我们的目标就是,找出尽量长的长轴(标号靠前的主成分)
在这里插入图片描述

③最大方差理论

      通常,我们认为信号具有较大的方差,噪声具有较小的方差,信噪比就是信号与噪声的功率之差( 10 l g ( P s P n ) 10lg(\frac{P_s}{P_n}) 10lgPnPs),越大越好。如下图所示,我们把紫色线上的数据认为是信号,而蓝色线上的数据认为是噪声,因此我们的目的就是最大化投影数据的方差(样本点在紫线上最分散)最小化数据点与投影之间的均方距离(蓝线和越小)
在这里插入图片描述

④目的

      PCA 的目的就是“降噪”和“去冗余”。
      “降噪”即使保留下来的维度间的相关性尽可能小
      “去冗余”即使保留下来的维度含有的方差(能量)尽可能大

★Ⅳ 算法剖析

输入:样本集 { x i xi xi} i = 1 n ^n_{i=1} i=1n,低维空间维数 k k k(即所要保留的新特征值个数)
输出:投影矩阵 W = [ w 1 , w 2 , . . . , w k ] W=[w_1,w_2,...,w_k] W=[w1,w2,...,wk]
下面介绍两种 PCA 的实现方法:

①顺序排列

      1.对所有样本进行中心化(和期望作差) x i ← x i − 1 n ∑ i = 1 n x i x_i←x_i-\frac{1}{n}∑^n_{i=1}x_i xixin1i=1nxi
      2.对中心化的数据 { x 1 , x 2 , . . . , x n x_1,x_2,...,x_n x1,x2,...,xn},计算主成分#1:(即目标函数)
w 1 = arg ⁡ m a x ∣ ∣ w 1 ∣ ∣ = 1 1 n ∑ i = 1 n ( w 1 T x i ) 2 w_1=\arg \underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}(w^T_1x_i)^2 w1=argw1=1maxn1i=1n(w1Txi)2
       w 1 T x i w^T_1x_i w1Txi 即内积运算( w 1 w_1 w1 为单位向量),求的是 x i x_i xi w 1 w_1 w1 上的投影,平方是为了省去求绝对值
利用拉格朗日乘数法求解最优 λ λ λ,约束条件为 ∣ ∣ w ∣ ∣ = 1 ||w||=1 w=1(即 w T w = 1 w^Tw=1 wTw=1
L ( w , λ ) = 1 n ( w T x i ) 2 − λ ( w T w − 1 ) L(w,λ)=\frac{1}{n}(w^Tx_i)^2-λ(w^Tw-1) L(w,λ)=n1(wTxi)2λ(wTw1)
(矩阵求导)对 w w w求导
∂ L ∂ w = ( 1 n ∑ i = 1 n x i x i T ) w − λ w \frac{\partial L}{\partial w}=(\frac{1}{n}∑^n_{i=1}x_ix_i^T)w-λw wL=(n1i=1nxixiT)wλw
实际上,令 X = [ x 1 , x 2 , . . . , x n ] X=[x_1,x_2,...,x_n] X=[x1,x2,...,xn],则 X X T = 1 n ∑ i = 1 n x i x i T XX^T=\frac{1}{n}∑^n_{i=1}x_ix_i^T XXT=n1i=1nxixiT
      3.最大化投影方差
w k = arg ⁡ m a x ∣ ∣ w 1 ∣ ∣ = 1 1 n ∑ i = 1 n [ w k T ( x i − ∑ j = 1 k − 1 w j w j T x i ⏟ x i ′ ) ] 2 w_k=\arg \underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}[w^T_k(\underbrace{x_i-∑^{k-1}_{j=1}w_jw_j^Tx_i}_{\text{$x_i'$}})]^2 wk=argw1=1maxn1i=1n[wkT(xi xij=1k1wjwjTxi)]2
后面一串 x i − ∑ j = 1 k − 1 w j w j T x i x_i-∑^{k-1}_{j=1}w_jw_j^Tx_i xij=1k1wjwjTxi 可以简单点理解为,扣掉前面那个主成分的方向,在剩下的残差子空间里求新的主成分在这里插入图片描述

②协方差矩阵法

      1.对所有样本进行去中心化(和期望作差) x i ← x i − 1 n ∑ i = 1 n x i x_i←x_i-\frac{1}{n}∑^n_{i=1}x_i xixin1i=1nxi
      2.计算样本的协方差矩阵 C C C
C = ( c i j ) n × n = [ c 11 c 12 . . . c 1 n c 21 c 22 . . . c 2 n . . . . . . . . . . . . c n 1 c n 2 . . . c n n ] C=(c_{ij})_{n×n}=\left[ \begin{matrix} c_{11} & c_{12} & ... & c_{1n}\\ c_{21} & c_{22} & ... & c_{2n} \\ ... & ... & ... & ... \\ c_{n1} & c_{n2} & ... & c_{nn} \end{matrix} \right] C=(cij)n×n=c11c21...cn1c12c22...cn2............c1nc2n...cnn
                          c i j = C o v ( X i , Y j ) c_{ij}=Cov(X_i,Y_j) cij=Cov(Xi,Yj)      i , j = 1 , 2 , . . . , n i,j=1,2,...,n i,j=1,2,...,n
      (对角线元素为某一维度的方差)
      3.对协方差矩阵C做特征值分解(即求所有满足的特征值和特征向量) C W ′ = λ W ′ CW'=λW' CW=λW(也可以用拉格朗日乘数法只求所需的最大的 k k k 个)
      4.取最大的 k k k 个特征值所对应的特征向量 w 1 , w 2 , . . . , w k w_1,w_2,...,w_k w1,w2,...,wk

比较详细的 PCA 数学推导过程 主成分分析(PCA)原理详解

——————————这节课的理论理解是真的费劲啊!————————

今日任务

1.给定的图像数据集,可视化并输出聚类性能(上节课还想偷懒,没想到该来的这么快就来了)
在这里插入图片描述

2.给定的图像数据集,计算相应的特征脸(Eigenfaces)
注:不是每一组 20 张算一个特征脸,是 200 张取前十个特征脸(这特征脸有点恐怖,不是说好提取完是张伟吗)
在这里插入图片描述

3.给定图像数据集,探讨 PCA 降维后特征个数与聚类性能的关系
在这里插入图片描述

任务解决

1、今天要用到 python 的库 cv2(版本更新被合并到 opencv_python 里了),提前装一下

pip install opencv_python -i https://pypi.tuna.tsinghua.edu.cn/simple

在这里插入图片描述

import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.cluster import KMeans
from PIL import Image
from ML_clustering_performance import clusteringMetrics

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20  # 列
IMAGE_ROW = 10  # 行
to_image = Image.new('RGB', (IMAGE_COLUMN * w, IMAGE_ROW * h))


def createDatabase(path):
    # 查看路径下所有文件
    TrainFiles = os.listdir(path)  # 遍历每个子文件夹
    # 计算有几个文件(图片命名都是以 序号.jpg方式)
    Train_Number = len(TrainFiles)  # 子文件夹个数
    train = []
    y_sample = []
    # 把所有图片转为1维并存入T中
    for k in range(0, Train_Number):
        Trainneed = os.listdir(path + '/' + TrainFiles[k])  # 遍历每个子文件夹里的每张图片
        Trainneednumber = len(Trainneed)  # 每个子文件里的图片个数
        for i in range(0, Trainneednumber):
            img = Image.open(path + '/' + TrainFiles[k] + '/' + Trainneed[i])
            to_image.paste(img, (i * w, k * h))  # 把读出来的图贴到figure上
            image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)  # 数据类型转换
            image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)  # RGB变成灰度图
            train.append(image)
            y_sample.append(k)
    train = np.array(train)
    y_sample = np.array(y_sample)
    return train, y_sample


# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
# print(X.shape)
X_ = X.reshape(X.shape[0], h*w)

kms = KMeans(n_clusters=10)
y_sample = kms.fit_predict(X_, y)
print(clusteringMetrics(y, y_sample))

plt.imshow(to_image)
plt.show()

↓ ↓ 别人家的代码系列)

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import matplotlib.image as imgplt
import os
import pandas as pd
from ML_clustering_performance import clusteringMetrics

name = []
target = []


def getimage():
    # 获取文件并构成向量
    # 预测值为1维,把一张图片的三维(RGB)压成1维,那么n张图片就是二维
    global total_photo
    file = os.listdir('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images')  # 遍历face_images里每个子文件夹
    i = 0
    for subfile in file:
        photo = os.listdir('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images\\' + subfile)  # 遍历每个子文件夹里的照片
        for name in photo:
            photo_name.append('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images\\' + subfile+'\\'+name)
            target.append(i)
        i += 1
    print(photo_name)
    for path in photo_name:
        photo = imgplt.imread(path)
        # photo = cv.imread(path)
        photo = photo.reshape(1, -1)
        photo = pd.DataFrame(photo)
        total_photo = total_photo.append(photo, ignore_index=True)
    total_photo = total_photo.values


def kmeans():
    clf = KMeans(n_clusters=10)
    clf.fit(total_photo)
    y_predict = clf.predict(total_photo)
    centers = clf.cluster_centers_
    result = centers[y_predict]
    result = result.astype("int64")
    result = result.reshape(200, 200, 180, 3)  # 图像的矩阵大小为200,180,3
    return result, y_predict


def draw():
    fig, ax = plt.subplots(nrows=10, ncols=20, sharex=True, sharey=True, figsize=[15, 8], dpi=80)
    plt.subplots_adjust(wspace=0, hspace=0)
    count = 0
    for i in range(10):
        for j in range(20):
            ax[i, j].imshow(result[count])
            count += 1
    plt.show()


def score():
    print(clusteringMetrics(target, y_predict))


total_photo = pd.DataFrame()
getimage()
result, y_predict = kmeans()
draw()
score()

效果图(就这,也跑了十几秒T∩T)
在这里插入图片描述
在这里插入图片描述

2、直接放代码吧,PCA 理论分析比较难,但用起来挺简单的,学着别人的例子用改改参数就行了(Python 真香)
参考了 Scikit-learn实例之Pca+Svm人脸识别(AT&T数据集)

import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.decomposition import PCA

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180

def createDatabase(path):
    TrainFiles = os.listdir(path)
    Train_Number = len(TrainFiles)
    train = []
    y_sample = []
    for k in range(0, Train_Number):
        Trainneed = os.listdir(path + '/' + TrainFiles[k])
        Trainneednumber = len(Trainneed)
        for i in range(0, Trainneednumber):
            image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)
            image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
            train.append(image)
            y_sample.append(k)
    train = np.array(train)
    y_sample = np.array(y_sample)
    return train, y_sample


# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
X_ = X.reshape(X.shape[0], h*w)

# 从200张图里挑出特征值前10的特征脸
n_components = 10
pca = PCA(n_components).fit(X_)  # svd_solver='randomized', whiten=True
eigenfaces = pca.components_.reshape((n_components, h, w))

# 将输入数据投影到特征面正交基上
X_train_pca = pca.transform(X_)


def plot_gallery(images, titles, h, w, n_row=1, n_col=10):
    """Helper function to plot a gallery of portraits"""
    plt.figure(figsize=(1.8 * n_col, 2 * n_row))
    plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)  # 图片位置布局
    for i in range(10):
        plt.subplot(n_row, n_col, i + 1)
        plt.imshow(images[i].reshape((h, w)))
        # plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
        plt.title(titles[i], size=12)
        # 把坐标去了
        plt.xticks(())
        plt.yticks(())


eigenface_titles = ["eigenface %d" % (i+1) for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()

效果图
在这里插入图片描述
不需要用到 opencv,直接用 matplotlib 的相关函数求特征脸

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import matplotlib.image as imgplt
import os
import pandas as pd

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
n_row, n_col = 1, 10
n_components = n_row * n_col
image_shape = (200, 540)
photo_name = []
target = []
total_photo = pd.DataFrame()


def getinfo(path):
    # 获取文件并构成向量
    # 预测值为1维,把一张图片的三维压成1维,那么n张图片就是二维
    global total_photo
    file = os.listdir(path)
    # 遍历每个图片
    for subfile in file:
        photo = os.listdir(path + subfile)
        for name in photo:
            photo = imgplt.imread(path + subfile + '/' + name)
            photo = photo.reshape(1, -1)
            photo = pd.DataFrame(photo)
            total_photo = total_photo.append(photo, ignore_index=True)
    total_photo = total_photo.values


getinfo(path)
faces = total_photo


def plot_gallery(images, title, n_col=n_col, n_row=n_row):
    plt.figure(figsize=(1.8 * n_col, 2 * n_row))
    plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
    plt.suptitle(title, size=16)

    for i, comp in enumerate(images):
        plt.subplot(n_row, n_col, i + 1)
        # vmax = max(comp.max(), -comp.min())
        plt.imshow(comp.reshape(image_shape))  # cmap=plt.cm.gray interpolation='nearest', vmin=-vmax, vmax=vmax
        plt.xticks(())
        plt.yticks(())


estimators = [("", PCA(n_components=10, whiten=True))]

for name, estimator in estimators:
    # print("Extracting the top %d %s..." % (n_components, name))
    # print(faces.shape)
    estimator.fit(faces)
    components_ = estimator.components_
    plot_gallery(components_[:n_components], name)

plt.show()

效果图(跑出来效果差一点,应该是有地方修改的,改半天没搞定,先放着了)
在这里插入图片描述
3、循环聚类下画个图就OK了

import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from PIL import Image
from ML_clustering_performance import clusteringMetrics

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20
IMAGE_ROW = 10


def createDatabase(path):
    TrainFiles = os.listdir(path)
    Train_Number = len(TrainFiles)
    train = []
    y_sample = []
    for k in range(0, Train_Number):
        Trainneed = os.listdir(path + '/' + TrainFiles[k])
        Trainneednumber = len(Trainneed)
        for i in range(0, Trainneednumber):
            img = Image.open(path + '/' + TrainFiles[k] + '/' + Trainneed[i])
            image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)
            image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
            train.append(image)
            y_sample.append(k)
    train = np.array(train)
    y_sample = np.array(y_sample)
    return train, y_sample


# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
X_ = X.reshape(X.shape[0], h*w)

n_components = 10

ACCS = []
NMIS = []
ARIS = []

for i in range(1, 9):
    n_components = i
    pca = PCA(n_components=n_components).fit(X_)  # svd_solver='randomized', whiten=True
    eigenfaces = pca.components_.reshape((n_components, h, w))
    # 将输入数据投影到特征面正交基上
    X_train_pca = pca.transform(X_)
    # 聚类
    kms = KMeans(n_clusters=10)
    y_sample = kms.fit_predict(X_train_pca, y)
    ACC, NMI, ARI = clusteringMetrics(y, y_sample)
    ACCS.append(ACC)
    NMIS.append(NMI)
    ARIS.append(ARI)

fig, ax = plt.subplots()
bar_width = 0.35
opacity = 0.4  # 不透明度
index = np.arange(8)
# error_config = {'ecolor': '0.3'}

rects1 = ax.bar(index, ACCS, bar_width, alpha=opacity, color='r', label='ACC')  # error_kw=error_config
rects2 = ax.bar(index + bar_width, NMIS, bar_width, alpha=opacity, color='g', label='NMI')
rects3 = ax.bar(index + 2*bar_width, ARIS, bar_width, alpha=opacity, color='b', label='ARI')

ax.set_xticks(index + bar_width / 2)
ax.set_xticklabels(('1', '2', '3', '4', '5', '6', '7', '8'))
ax.legend()
plt.show()

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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值