Skip to content

无监督学习:寻求数据的表示形式

聚类:对观察数据进行分组

聚类解决的问题

对于鸢尾属植物数据集来说,我们知道鸢尾属植物有3种不同的类型,但是并不知道每一个样本是那种类型:我们可以尝试 聚类任务:将样本数据分为不同的组,不同组之间是有明显差距的。这样的算法称为clusters(聚类)。

K-均值(K-means)聚类

请注意,存在许多不同的聚类标准和相关算法。最简单的聚类算法是 K-means

https://scikit-learn.org/stable/_images/sphx_glr_plot_cluster_iris_002.png

>>> from sklearn import cluster, datasets
>>> X_iris, y_iris = datasets.load_iris(return_X_y=True)

>>> k_means = cluster.KMeans(n_clusters=3)
>>> k_means.fit(X_iris)
KMeans(n_clusters=3)
>>> print(k_means.labels_[::10])
[1 1 1 1 1 0 0 0 0 0 2 2 2 2 2]
>>> print(y_iris[::10])
[0 0 0 0 0 1 1 1 1 1 2 2 2 2 2]

警告

k_means 算法不能保证运行结果跟真实情况相同。首先,很难选择聚类的个数。其次,由于该算法对初始化很敏感,并且可能会有局部最优解,尽管scikit-learn使用了几种技巧来减少以上问题的发生。

不好的初始化

k_means_iris_bad_init

8个聚类

k_means_iris_8

真实情况

cluster_iris_truth

不要过度解释聚类结果

应用示例:矢量量化(vector quantization)

一般对于聚类来说,尤其是KMeans,可以看作是选择少量样本来压缩信息的一种方式。这个问题有时被称为 矢量量化(vector quantization)。例如,这可以用于分离一张图像的色调:

>>> import scipy as sp
>>> try:
...    face = sp.face(gray=True)
... except AttributeError:
...    from scipy import misc
...    face = misc.face(gray=True)
>>> X = face.reshape((-1, 1)) # 我们需要一个形状为(n_sample, n_feature)的数组
>>> k_means = cluster.KMeans(n_clusters=5, n_init=1)
>>> k_means.fit(X)
KMeans(n_clusters=5, n_init=1)
>>> values = k_means.cluster_centers_.squeeze()
>>> labels = k_means.labels_
>>> face_compressed = np.choose(labels, values)
>>> face_compressed.shape = face.shape

原始图像

face

K均值量化

face_compressed

等宽度

face_regular

图像直方图

face_histogram

分层聚合聚类: Ward

分层聚类方法是一种聚类分析的类型,其目的是建立聚类的分层结构。一般来说,实现该算法的大多数方法有以下两种:

  • 聚合(Agglomerative) -自下而上的方法:每个观察数据都从单独一个聚类开始,并且以最小化距离标准的方式进行迭代地合并。当仅由少量观察数据组成时,此方法会引起人们的注意。当聚类个数很大时,它的计算效率比k均值高效地多。
  • 分裂(Divisive) - 自上而下的方法:所有的观察数据都开始于同一个聚类,当一个聚类向下一层移动时,它会被迭代地拆分。当对大量的数据进行估计时,此方法不仅速度慢(由于所有观察都是从同一个聚类开始,然后递归拆分),而且从统计学的角度来讲也是不合适的。

连接约束聚类(Connectivity-constrained clustering)

对于逐次聚合聚类(agglomerative clustering),通过连接图可以指定哪些样本可以被聚合在一个聚类中。在 scikit-learn 中,图由邻接矩阵来表示, 通常该矩阵是一个稀疏矩阵。这种表示方法是非常有用的,例如在聚类图像时检索连接区域(有时也被称为连接要素):

from scipy.ndimage.filters import gaussian_filter

import matplotlib.pyplot as plt

import skimage
from skimage.data import coins
from skimage.transform import rescale

from sklearn.feature_extraction.image import grid_to_graph
from sklearn.cluster import AgglomerativeClustering

# 这些是在skimage-0.14版本以上引入的
if LooseVersion(skimage.__version__) >= '0.14':
    rescale_params = {'anti_aliasing': False, 'multichannel': False}
else:
    rescale_params = {}

# #############################################################################
# 生成数据
orig_coins = coins()

# 把它的大小调为原来的20%,以加快处理速度
# 在缩小规模之前使用高斯过滤器进行平滑
# 减少混淆现象
smoothened_coins = gaussian_filter(orig_coins, sigma=2)

https://scikit-learn.org/stable/_images/sphx_glr_plot_coin_ward_segmentation_001.png

特征聚集(Feature agglomeration)

我们已经知道,稀疏性可以缓解特征维度带来的问题,与特征数量相比,样本数量不足。另一个解决该问题的方式是合并相似的维度:feature agglomeration(特征聚集)。 该方法可以通过特征聚类来实现。换句话说,就是对样本数据转置后进行聚类。

>>> digits = datasets.load_digits()
>>> images = digits.images
>>> X = np.reshape(images, (len(images), -1))
>>> connectivity = grid_to_graph(*images[0].shape)

>>> agglo = cluster.FeatureAgglomeration(connectivity=connectivity,
...                                      n_clusters=32)
>>> agglo.fit(X)
FeatureAgglomeration(connectivity=..., n_clusters=32)
>>> X_reduced = agglo.transform(X)

>>> X_approx = agglo.inverse_transform(X_reduced)
>>> images_approx = np.reshape(X_approx, images.shape)

https://scikit-learn.org/stable/_images/sphx_glr_plot_digits_agglomeration_001.png

transforminverse_transform方法

一些估计器会提供一个transform方法,例如减少数据集的维度。

分解: 从整个信号到其各个分量与负载

分量和负载

如果X是多维数据的话,那么我们要解决的问题是在不同的观察基础上对它进行重写:我们想学习负载L和一组分量C,使得X = LC。提取分量 C 有多种不同的方法。

主成分分析: PCA

主成分分析(PCA)能够把信号中的数据信息最大方差的连续成分提取出来。

pca_3d_axis

pca_3d_aligned

上图中样本点的分布在一个方向上是非常平坦的:即三个单变量特征中的任何一个都可以有另外两个特征来表示。 主成分分析法(PCA)可以找到使得数据分布不平坦(flat)的矢量方向(可以反映数据主要信息的特征方向)。

当用PCA来转换(transform)数据时,它可以通过在主子空间(principal subspace)上的投影来降低数据的维数。

>>> # 创建只有2个维度有用的信号
>>> x1 = np.random.normal(size=100)
>>> x2 = np.random.normal(size=100)
>>> x3 = x1 + x2
>>> X = np.c_[x1, x2, x3]

>>> from sklearn import decomposition
>>> pca = decomposition.PCA()
>>> pca.fit(X)
PCA()
>>> print(pca.explained_variance_)  
[  2.18565811e+00   1.19346747e+00   8.43026679e-32]

>>> #如我们所见,只有前两个分量才有用
>>> pca.n_components = 2
>>> X_reduced = pca.fit_transform(X)
>>> X_reduced.shape
(100, 2)

独立分量分析: ICA

独立分量分析(ICA)可以提取数据信息中的独立成分,这些成分的负载分布包含了最多的独立信息。它能够恢复 非高斯独立信号:

https://scikit-learn.org/stable/_images/sphx_glr_plot_ica_blind_source_separation_001.png

>>> # 生成样本数据
>>> import numpy as np
>>> from scipy import signal
>>> time = np.linspace(0, 10, 2000)
>>> s1 = np.sin(2 * time)  # 信号1:正弦信号
>>> s2 = np.sign(np.sin(3 * time))  # 信号2:方波信号
>>> s3 = signal.sawtooth(2 * np.pi * time)  # 信号3:锯齿信号
>>> S = np.c_[s1, s2, s3]
>>> S += 0.2 * np.random.normal(size=S.shape)  # 添加噪音
>>> S /= S.std(axis=0)  # 标准化数据
>>> # 混合数据
>>> A = np.array([[1, 1, 1], [0.5, 2, 1], [1.5, 1, 2]])  # 混合矩阵
>>> X = np.dot(S, A.T)  # 生成观测数据

>>> # 计算 ICA
>>> ica = decomposition.FastICA()
>>> S_ = ica.fit_transform(X)  # 获取估计的来源
>>> A_ = ica.mixing_.T
>>> np.allclose(X,  np.dot(S_, A_) + ica.mean_)
True

©2007-2019,scikit-learn开发人员(BSD许可证)。 显示此页面源码