机器学习折腾记(3-2):不同视角的分类——聚类

根据学习过程中的不同经验,机器学习算法可以大致分类为无监督 (unsupervised)算法和监督 (supervised)算法。

监督学习算法 (supervised learning algorithm)训练含有很多特征的数据集,不过数据集中的样本都有一个标签 (label)或目标 (target)。例如,Iris数据集注明了每个鸢尾花卉样本属于什么品种。监督学习算法通过研究Iris数据集,学习如何根据测量结果将样本划分为3个不同品种。

无监督学习算法 (unsupervised learning algorithm)训练含有很多特征的数据集,然后学习出这个数据集上有用的结构性质。在深度学习中,我们通常要学习生成成数据集的整个概率分布,显式地,比如密度估计,或是隐式地,比如合成或去噪。还有一些其他类型的无监督学习任务,例如聚类,将数据集分成相似样本的集合。

今天我们来说下聚类,上一节我们通过NLTK的工具包得到了关于帖子的特征向量,我们相信它足以捕捉到帖子的特征。有很多方法可以把帖子聚合分组,这并不奇怪。而多数聚类算法都属于下面两个方法之一:扁平和层次聚类。

扁平聚类会将帖子分成一系列相互之间没有关联的簇。它的目标是通过一个划分,使一个簇中的帖子相互之间非常相似,而所有不同簇中的帖子很不相似。很多扁平聚类算法需要预先指定簇的个数。

在层次聚类中,并不需要指定簇的个数。相反,层次聚类可以构造出簇之间的层次关系。在相似帖子类聚到一个簇中的同时,相似的簇将会进一步聚到一个超级簇中。这个步骤递归下去,直到只剩下一个簇,它包含了所有东西。在层次结构中,人们可以选择所需要的簇的个数。但这样会降低效率。

Scikit在sklearn.cluster 包中提供了范围广泛的聚类方法。你可以在http://scikit-learn.org/dev/modules/clustering.html 快速浏览它们的优缺点。

scikit-learn支持的聚类算法介绍

聚类有很多算法,如下图,是Scikit-learn官网的实现的不同聚类算法:
这里写图片描述
Affinity propagation:学术界一般翻译为近邻传播聚类算法。它的思路是通过迭代的方法计算出一个数据点更适合和另外哪一个数据点属于一个簇。

Mean-shift:又称为均值漂移算法,Mean Shift的概念最早是由Fukunage在1975年提出的,在后来由Yizong Cheng对其进行扩充,主要提出了两点的改进:

Spectral clustering:中文叫谱聚类算法,是从图论中演化出来的算法,后来在聚类中得到了广泛的应用。它的主要思想是把所有的数据看做空间中的点,这些点之间可以用边连接起来。距离较远的两个点之间的边权重值较低,而距离较近的两个点之间的边权重值较高,通过对所有数据点组成的图进行切图,让切图后不同的子图间边权重和尽可能的低,而子图内的边权重和尽可能的高,从而达到聚类的目的。

Ward hierarchical clustering:又叫层次聚类,Hierarchical clustering 是一个常用的聚类算法,它通过不断的合并或者分割来构建聚类。 聚类的层次被表示成树(或者 dendrogram(树形图))。树根是拥有所有样本的唯一聚类,叶子是仅有一个样本的聚类。 Agglomerative clustering也是一种层次聚类算法。

DBSCAN:英文全写为Density-based spatial clustering of applications with noise ,是在 1996 年由Martin Ester, Hans-Peter Kriegel, Jörg Sander 及 Xiaowei Xu 提出的聚类分析算法, 这个算法是以密度为本的:给定某空间里的一个点集合,这算法能把附近的点分成一组(有很多相邻点的点),并标记出位于低密度区域的局外点(最接近它的点也十分远),DBSCAN 是其中一个最常用的聚类分析算法,也是其中一个科学文章中最常引用的。(WIKI)

Gaussian mixtures:高斯混合模型是一个假设所有的数据点都是生成于一个混合的有限数量的并且未知参数的高斯分布的概率模型。 我们可以将混合模型看作是 k-means 聚类算法的推广,它利用了关于数据的协方差结构以及潜在高斯中心的信息。对应不同的估算策略,Scikit-learn 实现了不同的类来估算高斯混合模型。

Birch:Birch 是一种能够高效处理大数据聚类的基于树的层次聚类算法。Birch 为提供的数据构建一颗 Characteristic Feature Tree (CFT,聚类特征树)。 数据实质上是被有损压缩成一组 Characteristic Feature nodes (CF Nodes,聚类特征节点)。 CF Nodes 中有一部分子聚类被称为 Characteristic Feature subclusters (CF Subclusters), 并且这些位于非终端位置的CF Subclusters 可以拥有 CF Nodes 作为孩子节点。

对帖子聚类

你肯定已经注意到了一件事——真实数据含有很多噪声。新闻组数据也不例外。它甚至包含了不合法的字符,这会导致UnicodeDecodeError 。我们需要在进行向量化处理时忽略它。

对于无监督学习来说,很容易造成数据的过拟合,因为它不像有监督学习那样,会先经过人工的筛选处理,去除掉多余数据噪声数据。

当然适当的噪声数据也是必要的,它能帮助我们测试模型的预测准确性。

解决我们最初的难题

到这里,其实你可能已经能通过把代码拷贝到学习环境,运行代码查看到模型的效果了。我们能运行起一个机器学习算法的目标已经达到。

同时我们也明白,里面包含的太多东西都还是不够清晰,因为概念和公式实在太多了。

当然,我们还是要继续问自己一个问题,为什么要使用聚类算法?和我们的相关业务场景到底又有多大关联?

如果答案是没有关联,那其实,这个解决方案其实一点作用都没有,对吧?

所以说,搞清楚我们到底为什么要看一个晦涩难懂的机器学习算法,比拿起一本机器学习算法更重要。

小结

从聚类上的预处理,到把有噪文本转化为有意义的简洁向量表示的解决方案,这是一个艰难的过程。回头看一下我们为最终能够聚类所做的工作,它其实值不够占了整个任务的一半多一点而已。但是在这个过程中,我们学习到了很多关于文本处理的知识(包括NLP),以及聚类的相关知识。

由于Scikit有极其强大的程序包,这个过程已经相当平缓。不过仍有很多东西可以探索。本章中我们只抓住了它的表面功能。在下一节里我们将会看到聚类更大的作用。

实现代码

import os
import scipy as sp
from scipy.stats import norm
from matplotlib import pylab
from sklearn.cluster import KMeans

seed = 2
sp.random.seed(seed)  # to reproduce the data later on

num_clusters = 3


def plot_clustering(x, y, title, mx=None, ymax=None, xmin=None, km=None):
    pylab.figure(num=None, figsize=(8, 6))
    if km:
        pylab.scatter(x, y, s=50, c=km.predict(list(zip(x, y))))
    else:
        pylab.scatter(x, y, s=50)

    pylab.title(title)
    pylab.xlabel("Occurrence word 1")
    pylab.ylabel("Occurrence word 2")
    # pylab.xticks([w*7*24 for w in range(10)], ['week %i'%w for w in range(10)])

    pylab.autoscale(tight=True)
    pylab.ylim(ymin=0, ymax=1)
    pylab.xlim(xmin=0, xmax=1)
    pylab.grid(True, linestyle='-', color='0.75')
    pylab.show()

    return pylab


xw1 = norm(loc=0.3, scale=.15).rvs(20)
yw1 = norm(loc=0.3, scale=.15).rvs(20)

xw2 = norm(loc=0.7, scale=.15).rvs(20)
yw2 = norm(loc=0.7, scale=.15).rvs(20)

xw3 = norm(loc=0.2, scale=.15).rvs(20)
yw3 = norm(loc=0.8, scale=.15).rvs(20)

x = sp.append(sp.append(xw1, xw2), xw3)
y = sp.append(sp.append(yw1, yw2), yw3)

i = 1
plot_clustering(x, y, "Vectors")
# pylab.savefig(os.path.join("..", "1400_03_0%i.png" % i))
pylab.clf()

i += 1

#################### 1 iteration ####################

mx, my = sp.meshgrid(sp.arange(0, 1, 0.001), sp.arange(0, 1, 0.001))

km = KMeans(init='random', n_clusters=num_clusters, verbose=1,
            n_init=1, max_iter=1,
            random_state=seed)
km.fit(sp.array(list(zip(x, y))))

Z = km.predict(sp.c_[mx.ravel(), my.ravel()]).reshape(mx.shape)

plot_clustering(x, y, "Clustering iteration 1", km=km)
pylab.imshow(Z, interpolation='nearest',
           extent=(mx.min(), mx.max(), my.min(), my.max()),
           cmap=pylab.cm.Blues,
           aspect='auto', origin='lower')

c1a, c1b, c1c = km.cluster_centers_
pylab.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[:, 1],
            marker='x', linewidth=2, s=100, color='black')
# pylab.savefig(os.path.join("..", "1400_03_0%i.png" % i))
pylab.clf()

i += 1

#################### 2 iterations ####################
km = KMeans(init='random', n_clusters=num_clusters, verbose=1,
            n_init=1, max_iter=2,
            random_state=seed)
km.fit(sp.array(list(zip(x, y))))

Z = km.predict(sp.c_[mx.ravel(), my.ravel()]).reshape(mx.shape)

plot_clustering(x, y, "Clustering iteration 2", km=km)
pylab.imshow(Z, interpolation='nearest',
           extent=(mx.min(), mx.max(), my.min(), my.max()),
           cmap=pylab.cm.Blues,
           aspect='auto', origin='lower')

c2a, c2b, c2c = km.cluster_centers_
pylab.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[:, 1],
            marker='x', linewidth=2, s=100, color='black')
# import pdb;pdb.set_trace()
pylab.gca().add_patch(
    pylab.Arrow(c1a[0], c1a[1], c2a[0] - c1a[0], c2a[1] - c1a[1], width=0.1))
pylab.gca().add_patch(
    pylab.Arrow(c1b[0], c1b[1], c2b[0] - c1b[0], c2b[1] - c1b[1], width=0.1))
pylab.gca().add_patch(
    pylab.Arrow(c1c[0], c1c[1], c2c[0] - c1c[0], c2c[1] - c1c[1], width=0.1))

# pylab.savefig(os.path.join("..", "1400_03_0%i.png" % i))
pylab.clf()

i += 1

#################### 3 iterations ####################
km = KMeans(init='random', n_clusters=num_clusters, verbose=1,
            n_init=1, max_iter=10,
            random_state=seed)
km.fit(sp.array(list(zip(x, y))))

Z = km.predict(sp.c_[mx.ravel(), my.ravel()]).reshape(mx.shape)

plot_clustering(x, y, "Clustering iteration 10", km=km)
pylab.imshow(Z, interpolation='nearest',
           extent=(mx.min(), mx.max(), my.min(), my.max()),
           cmap=pylab.cm.Blues,
           aspect='auto', origin='lower')

pylab.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[:, 1],
            marker='x', linewidth=2, s=100, color='black')
# pylab.savefig(os.path.join("..", "1400_03_0%i.png" % i))
pylab.clf()

i += 1

参考资源

1、《机器学习系统设计》
2、《深度学习》
3、http://sklearn.apachecn.org/cn/0.19.0/modules/clustering.html#hierarchical-clustering

猜你喜欢

转载自blog.csdn.net/mickjoust/article/details/80079401