【深度之眼吴恩达机器学习第四期】笔记(九)

目录

  • K均值
    • K均值算法
      • 语言描述
      • 伪代码描述
    • 解决分离不佳的簇
    • K均值的损失函数
    • K均值初始化
    • 如何选择K
  • 主成分分析
    • 用途1:去除冗余特征
    • 用途2:可视化数据
    • 直观来理解主成分分析
    • 主成分分析与线性回归的区别
    • 选择要降到几维(K)
    • 降维用于加速算法
    • 主成分分析的误用
  • 编程
    • K均值
    • 主成分分析

K均值

无监督学习的数据没有标签,希望计算机自行学习其中的知识。比如聚类模型会通过数据的内在性质,把数据划分为不同的关系紧密的子集。而K均值就是一个聚类模型。
【深度之眼吴恩达机器学习第四期】笔记(九)_第1张图片
聚类模型的用途:

  1. 市场分割
    数据库中有各种客户的信息,希望将他们按照市场的不同进行划分,这样就能对不同的市场制定不同的销售策略或根据市场的不同进行服务改进。
  2. 社会网络分析
    关注一些群体和他们的社交网和一些其他信息(如哪些人是你用邮件联系最频繁的人,而这些人用邮件联系最频繁的人又是谁),以此找到一个密切关联的群体。
  3. 组织计算机集群以及更好地组织数据集
    在数据中心中,计算机集群经常协同工作,可以用K均值来重新组织资源,重新布局网络,优化数据中心以及通信数据。
  4. 了解银河系的构成
    然后用这些构成信息来了解一些天文学的知识。

【深度之眼吴恩达机器学习第四期】笔记(九)_第2张图片

K均值算法

语言描述

假设我们有绿色的这些数据点,希望把这些数据点分为两个子集,应该怎么做?

  1. 随机生成两个点,这两点就叫聚类中心。生成两个点是因为想要分为两个聚类;
    【深度之眼吴恩达机器学习第四期】笔记(九)_第3张图片
  2. 遍历数据,计算它们离两个聚类中心的距离,并把它们分配到距离最近的聚类中心。比如,图中红色的圆点离红色的聚类中心(红色的叉)比距离蓝色的聚类中心更近;
    【深度之眼吴恩达机器学习第四期】笔记(九)_第4张图片
  3. 移动聚类中心。分别计算两种颜色的点的均值位置,并把新的聚类中心设置为计算出来的均值位置;
    【深度之眼吴恩达机器学习第四期】笔记(九)_第5张图片
  4. 重复第二第三步,直到聚类中心不再移动,也就是说数据点的颜色不再改变;
    【深度之眼吴恩达机器学习第四期】笔记(九)_第6张图片
    如果在上述过程中出现一个没有点的聚类中心怎么办?最常见的做法是直接移除那个聚类中心
    但有时候的确需要K个聚类而不是K-1个聚类,那么就可以重新初始化这个聚类中心

伪代码描述

算法的输入有两个:K(想要分几类)和训练数据,而且约定不使用x0=1。
【深度之眼吴恩达机器学习第四期】笔记(九)_第7张图片
ci代表xi离第i个聚类中心最近;
μk代表第k个聚类中心。
【深度之眼吴恩达机器学习第四期】笔记(九)_第8张图片

解决分离不佳的簇

有时候,我们遇到的数据并不都像左边的数据点那样各个聚类间有明显的分割,而是像右边的数据点一样看上去不容易分离。但是K均值算法依旧能够取得不错的结果。
【深度之眼吴恩达机器学习第四期】笔记(九)_第9张图片

K均值的损失函数

假设xi和第5个聚类中心最近,那么ci=5,μci5
K均值的优化目标:找到合适的ci和μk,使得xi和它被分到的聚类的中心(μci)的距离最近。
【深度之眼吴恩达机器学习第四期】笔记(九)_第10张图片
可以证明在K均值算法中,第一步把xi分到离它最近的聚类中心,其实就是调整ci使得损失函数最小化;
第二步中重新计算新的聚类中心,其实就是调整μk使得损失函数最小化。
【深度之眼吴恩达机器学习第四期】笔记(九)_第11张图片

K均值初始化

Q:如何初始化K均值?
A:随机选择K个训练数据点作为初始化的聚类中心。
【深度之眼吴恩达机器学习第四期】笔记(九)_第12张图片
Q:K均值在不同的初始值下会有不同的结果,也就是说可能会陷入局部最优。如何避免陷入局部最优?
A:解决这个问题的方法是进行多次初始化。
【深度之眼吴恩达机器学习第四期】笔记(九)_第13张图片
一般来说,可以进行50到1000次随机初始化,然后计算每次的损失J,选择损失最小的模型。
多次随机初始化在K比较小的时候比较有用,比如K在2到10左右时,但是,如果K很大,比如成百上千,那么多次随机初始化可能并不会有太大的改善。
【深度之眼吴恩达机器学习第四期】笔记(九)_第14张图片

如何选择K

并没有一个很好的方法选择K,比如下图中的数据,有的人会把它分成两个聚类,也有人会把它分成四个聚类。
【深度之眼吴恩达机器学习第四期】笔记(九)_第15张图片
肘部法则:画出损失函数J随K的改变而改变的图,选择从急速下降到平缓下降的点(比如左边图中的K=3),但是有时候得到的图是右边的样子,并没有一个明确的点可供选择,这时候肘部法则就没什么用了。
总而言之,肘部法则是一个值得尝试的方法,但是不能期望它能解决所有问题。
【深度之眼吴恩达机器学习第四期】笔记(九)_第16张图片
通过下游目标确定。有时候,人们运用K均值算法是有一个目标的,比如可以考虑:如果把T-shirt分为3个尺码,它会买得怎么样?把它分为5个尺码会得到更高的销售量吗?这样就得到了K的数值。
【深度之眼吴恩达机器学习第四期】笔记(九)_第17张图片

主成分分析

另一种无监督学习是降维,降维不仅能使数据占用更少的内存,还能加速算法。

用途1:去除冗余特征

假设现在有一个二维的数据,两个维度的数据都是代表物体的长度,其中一维用厘米表示,另一个维度用英寸表示。我们可以让它们合并成一个特征。
这个例子有点勉强,但是在实际应用中,如果有成百上千个特征,就不容易知道哪些特征是冗余的。
假设有三个工程小组,第一个工程小组给你200个特征,第二个工程小组给你300个特征,第三个工程小组给你500个特征,总共有1000个特征。这时候就容易产生冗余数据。
【深度之眼吴恩达机器学习第四期】笔记(九)_第18张图片
这是一个三维数据点投影到二维平面的例子。
【深度之眼吴恩达机器学习第四期】笔记(九)_第19张图片

用途2:可视化数据

假设我们有关于各个国家的数据,每个国家有50个特征,我们怎么样才能看出这些国家之间的关联呢?
【深度之眼吴恩达机器学习第四期】笔记(九)_第20张图片
我们不可能画出50维的数据,但是如果我们能够把这50维的数据降到2维,并且保留数据的主要特征,那么我们就可以在二维的平面把它们画出来了。当然,直接看这个二维的数据可能并不知道每个特征表示的是什么。
【深度之眼吴恩达机器学习第四期】笔记(九)_第21张图片
当你把它们都画出来后,有可能就能知道每一维大概代表什么。
【深度之眼吴恩达机器学习第四期】笔记(九)_第22张图片

直观来理解主成分分析

主成分分析想要找到一个低维空间,使得数据点和它们在低维空间上投影的距离最短。
所以算法会选择投影到红色的线上而不是粉红色的线。
【深度之眼吴恩达机器学习第四期】笔记(九)_第23张图片

主成分分析与线性回归的区别

主成分分析看起来和线性回归很像,但是它们实际上是不同的:
线性回归中有一个特殊的分量y,而主成分分析中,每一个分量都是平等的。
而且线性回归中,数据到预测的y的距离是垂直于x轴的;而主成分分析中数据到投影点的距离是垂直于低维平面的。
【深度之眼吴恩达机器学习第四期】笔记(九)_第24张图片
在进行主成分分析之前,要对数据进行特征缩放(房子的面积和房间的数量相差较大)和归一化处理
在这里插入图片描述
主成分分析想求的数据有两个:低维空间的坐标轴数据点投影到低维空间后的坐标
【深度之眼吴恩达机器学习第四期】笔记(九)_第25张图片
假设我们要把数据从n维降到k维,首先要求数据X间的协方差矩阵,然后对这个协方差矩阵进行奇异值分解,分解后能得到三个矩阵U,S,V,然后把U的前k个列向量取出来,记为Ureduce
【深度之眼吴恩达机器学习第四期】笔记(九)_第26张图片
Ureduce就是降维后的空间坐标轴,降维后的数据坐标Z=UreduceTX
【深度之眼吴恩达机器学习第四期】笔记(九)_第27张图片
如何从降维后的数据重现原数据
X≈Xapprox=UreduceZ,可以看到重现的数据完全是在一条直线上的。
【深度之眼吴恩达机器学习第四期】笔记(九)_第28张图片

选择要降到几维(K)

分别计算投影误差平方的平均值和数据的方差的平均值,我们会选择一个使得下图中的式子成立的k。也就是说,希望降维后的数据依旧保持原数据99%以上的方差
【深度之眼吴恩达机器学习第四期】笔记(九)_第29张图片
一个直接的想法就是,从小到大选择k,计算Ureduce,Z,Xapprox等,然后计算上面的等式是否成立,直到找到使等式成立的最小的k。
但是这个方法比较麻烦,有一个更简便的方法是计算下图右边的这个式子是否成立。比如说k=3时,计算奇异值分解得到的S的对角线上前3个元素的和比上对角线上所有元素的和,看看它是否大于等于99%,如果满足,k=3就是我们所要求的k。
【深度之眼吴恩达机器学习第四期】笔记(九)_第30张图片

降维用于加速算法

假设一个分类问题的输入X有10000维,我们可以把X拿出来,降维到1000维,然后用这个1000维的数据去进行训练。
注意,降维所需的矩阵Ureduce应该是在训练集里学到的,不应该使用验证集和测试集去学习Ureduce。当然,训练完的Ureduce验证集和测试集都是可以用的。
【深度之眼吴恩达机器学习第四期】笔记(九)_第31张图片

主成分分析的误用

主成分分析的一个误用是用于防止过拟合,这并不是正确的用法,并不是说这样做的结果不好,而是说主成分分析不会考虑y的取值,所以有可能丢失一些重要的信息。
一个正确防止过拟合的方法是使用正则化项,这种方法会考虑y的取值,而且效果也比较好。
【深度之眼吴恩达机器学习第四期】笔记(九)_第32张图片
另一个主成分分析的误用就是,人们在刚开始构造模型的时候就把主成分分析考虑进去,但是建议直接使用原数据进行训练。如果没有必要的理由(运行过慢或者占用内存过大等),就不应该使用主成分分析。
【深度之眼吴恩达机器学习第四期】笔记(九)_第33张图片

主成分分析应该被用在加速算法或可视化数据上。

编程

K均值

导包

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from skimage import io
from scipy.io import loadmat

找到离数据点最近的聚类中心

def find_closest_centroids(X, centroids):
# INPUT:数据X,初始聚类中心centroids
# OUTPUT:数据点应该被分到的类
    m = X.shape[0]
    k = centroids.shape[0]
    idx = np.zeros(m)    
    for i in range(m):
        min_dist = 1000000
        # 求离Xi最近的聚类中心,并保存在idx[i]
        for j in range(k):
            dist = np.sum((X[i]-centroids[j])**2)
            if dist < min_dist:
                min_dist = dist
                # 数据点Xi应该被分到第j类
                idx[i] = j
    return idx

# 测试一下上面的函数
data = loadmat('data/ex7data2.mat')
X = data['X']
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]])
idx = find_closest_centroids(X, initial_centroids)
# array([0., 2., 1.])
idx[0:3]

展示原始数据

data2 = pd.DataFrame(data.get('X'), columns=['X1', 'X2'])
# 展示前五行数据
data2.head()

# 画出散点图
sb.set(context="notebook", style="white")
sb.lmplot('X1', 'X2', data=data2, fit_reg=False)
plt.show()
X1 X2
0 1.842080 4.607572
1 5.658583 4.799964
2 6.352579 3.290854
3 2.904017 4.612204
4 3.231979 4.939894

在这里插入图片描述
计算新的聚类中心

def compute_centroids(X, idx, k):
# INPUT:数据X,聚类中心idx,簇的个数k
# OUTPUT:当前簇的聚类中心
    m, n = X.shape
    centroids = np.zeros((k, n))    

    for i in range(k):
        # 找到被分到第i个类的数据点的下标
        indices = np.argwhere(idx==i)
        centroids[i,:] = (np.sum(X[indices],axis=0))/len(indices)    
    return centroids

# array([[2.42830111, 3.15792418],
#       [5.81350331, 2.63365645],
#       [7.11938687, 3.6166844 ]])
compute_centroids(X, idx, 3)

实现K均值

def run_k_means(X, initial_centroids, max_iters):
# INPUT:数据X,初始化的聚类中心,最大迭代次数
# OUTPUT:当前簇的聚类中心
    # 初始化
    m, n = X.shape
    k = initial_centroids.shape[0]
    idx = np.zeros(m)
    centroids = initial_centroids
    
    # 迭代计算聚类中心和分配点到聚类中心
    for i in range(max_iters):
        idx = find_closest_centroids(X, centroids)
        centroids = compute_centroids(X, idx, k)    
    return idx, centroids

idx, centroids = run_k_means(X, initial_centroids, 10)

展示模型结果

# 划分三个聚类
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(cluster1[:,0], cluster1[:,1], s=30, color='y', 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.scatter(centroids[:,0],centroids[:,1], s=80, color = 'r', label='center')
# 显示数据点的含义
ax.legend()
plt.show()

【深度之眼吴恩达机器学习第四期】笔记(九)_第34张图片
在原始数据中随机选择K个作为初始化的聚类中心

def init_centroids(X, k):
    m, n = X.shape
    centroids = np.zeros((k, n))
    # m个样本点中任取k个
    idx = np.random.randint(0, m, k)    
    for i in range(k):
        centroids[i,:] = X[idx[i],:]    
    return centroids

# array([[3.81422865, 4.73526796],
#       [5.74036233, 3.10391306],
#       [2.68499376, 0.35344943]])
init_centroids(X, 3)

使用K均值压缩图片

from IPython.display import Image
Image(filename='data/bird_small.png')

image_data = loadmat('data/bird_small.mat')
image_data

A = image_data['A']
# (128, 128, 3)
A.shape

# 归一化数据
A = A / 255.
# 重置矩阵大小
X = np.reshape(A, (A.shape[0] * A.shape[1], A.shape[2]))
# (16384, 3)
X.shape

【深度之眼吴恩达机器学习第四期】笔记(九)_第35张图片

# 随机初始化聚类中心(16,3),16个像素点,每个点RGB三原色
initial_centroids = init_centroids(X, 16)
# 运行之前写好的聚类算法,迭代10次
idx, centroids = run_k_means(X, initial_centroids, 10)
# 得到最终的聚类中心
idx = find_closest_centroids(X, centroids)
# 把每一个像素值分到各个聚类中心
X_recovered = centroids[idx.astype(int),:]
# (16384, 3)
X_recovered.shape

# 为了方便展示,转化回原始大小
X_recovered = np.reshape(X_recovered, (A.shape[0], A.shape[1], A.shape[2]))
# (128, 128, 3)
X_recovered.shape

pic = io.imread('data/bird_small.png') / 255.
fig, ax = plt.subplots(1, 2)
# 原图像
ax[0].imshow(pic)
# 压缩后的图像
ax[1].imshow(X_recovered)
plt.show()

看得出来,还是保留大量信息的。
【深度之眼吴恩达机器学习第四期】笔记(九)_第36张图片
使用sklearn来实现K均值

# 导入图像和初始化
pic = io.imread('data/bird_small.png') / 255.
io.imshow(pic)
plt.show()
# (128, 128, 3)
pic.shape
# 重置图像大小
data = pic.reshape(128*128, 3)
# (16384, 3)
data.shape
#导入k-means库
from sklearn.cluster import KMeans
model = KMeans(n_clusters=16, n_init=100, n_jobs=-1)
# Out[25]:KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
#       n_clusters=16, n_init=100, n_jobs=-1, precompute_distances='auto',
#       random_state=None, tol=0.0001, verbose=0)
model.fit(data)

centroids = model.cluster_centers_
# (16, 3)
print(centroids.shape)
C = model.predict(data)
# (16384,)
print(C.shape)
# (16384,3)
centroids[C].shape

compressed_pic = centroids[C].reshape((128,128,3))

fig, ax = plt.subplots(1, 2)
ax[0].imshow(pic)
ax[1].imshow(compressed_pic)
plt.show()

和上面自编程的比较,可以看到鸟嘴的颜色更丰富,而黑色羽毛的层次减少了。
【深度之眼吴恩达机器学习第四期】笔记(九)_第37张图片

主成分分析

加载并展示数据

data = loadmat('data/ex7data1.mat')
data
X = data['X']
fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(X[:, 0], X[:, 1])
plt.show()

在这里插入图片描述
实现主成分分析

# 实现奇异值分解
def pca(X):
# INPUT:数据X
# OUTPUT:矩阵U,S,V

    # 归一化数据
    X = (X-X.mean())/X.std()    
    # 计算协方差矩阵
    X = np.matrix(X)
    cov = X.T@X    
    # 进行奇异值分解
    U, S, V = np.linalg.svd(cov)    
    return U, S, V

U, S, V = pca(X)
# (matrix([[-0.79241747, -0.60997914],
#         [-0.60997914,  0.79241747]]),
# array([71.79226819, 28.20773181]),
# matrix([[-0.79241747, -0.60997914],
#         [-0.60997914,  0.79241747]]))
U, S, V

# 使数据投影到低维空间
def project_data(X, U, k):
    # 取前k个列向量,因为低维空间的维数是k
    U_reduced = U[:,:k]
    return np.dot(X, U_reduced)

Z = project_data(X, U, 1)
Z

# 降维后的数据还原回高维空间
def recover_data(Z, U, k):
    U_reduced = U[:,:k]
    return np.dot(Z, U_reduced.T)

X_recovered = recover_data(Z, U, 1)
X_recovered

fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(list(X_recovered[:, 0]), list(X_recovered[:, 1]))
plt.show()

可以看到,还原回高维空间后,数据都在一条直线上了,什么这个压缩是有损压缩(也就是说不能完全还原回原来的样子)。
【深度之眼吴恩达机器学习第四期】笔记(九)_第38张图片
使用主成分分析压缩图像

faces = loadmat('data/ex7faces.mat')
X = faces['X']
# (5000, 1024)
X.shape

face = np.reshape(X[3,:], (32, 32))
plt.imshow(face)
plt.show()

【深度之眼吴恩达机器学习第四期】笔记(九)_第39张图片
从1024维降到100维

U, S, V = pca(X)
Z = project_data(X, U, 100)

X_recovered = recover_data(Z, U, 100)
face_pca = np.reshape(X_recovered[3,:], (32, 32))
fig, ax = plt.subplots(1, 2)
ax[0].imshow(face)
ax[1].imshow(face_pca)
plt.show()

左边是原图像,右边是降维后再还原到高维的图像。
【深度之眼吴恩达机器学习第四期】笔记(九)_第40张图片

你可能感兴趣的:(吴恩达机器学习)