《机器学习系统设计》之应用scikit-learn做文本分类(下)

14 篇文章 12 订阅
5 篇文章 0 订阅

前言:

    本系列是在作者学习《机器学习系统设计》([美] WilliRichert)过程中的思考与实践,全书通过Python从数据处理,到特征工程,再到模型选择,把机器学习解决问题的过程一一呈现。书中设计的源代码和数据集已上传到我的资源:http://download.csdn.net/detail/solomon1558/8971649

       第3章通过词袋模型+K均值聚类实现相关文本的匹配。本文主要讲解K-均值聚类相关知识以及在20newsgroup数据集上使用K-均值聚类进行测试。

    相关链接:《机器学习系统设计》之应用scikit-learn做文本分类(上)

1. K-均值聚类算法

    K-均值是发现给定数据集的k个簇的算法。簇个数k由用户给定,每一个簇通过其质心(centroid),即簇中所有点的中心来描述。

    K-均值算法的工作流程为:首先随机确定k个初始点作为质心;然后将数据集章的每个点分配到一个簇中,即为每个点找距其最近的质心,并将其分配给该质心对应簇;这一步完成后,每个簇的质心更新为该簇所有点的平均值。经过一定的迭代,当移动量低于一定阈值时,我们就认为聚类已经收敛了。

    上述过程的伪代码表示如下:

创建k个点作为起始质心(一般随机选择)

当任意一个点的簇分配结果发生改变时

   对数据集中每个数据点

      对每个质心

          计算质心与数据点之间的距离

      将数据点分配到距其最近的簇

   对每一个簇,计算簇中所有点的均值并将均值作为中心

    K-均值聚类算法的优缺点:

    优点:算法简单,易于实现

    缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢。

2. K-均值例程

    本小节通过一个简单的例子来验证这个算法,这个例子包含只有两个词语的文档(源代码见附录)

    经过1次K均值迭代后,以任意3个向量作为起始点,经标签赋予余下的样本,然后更新簇的中心,使之成为该簇中所有数据点的中心点,我们得到以下聚类:


    由于簇中心的移动,我们必须重新分配簇的标签,并重新计算簇的中心点。在第二轮迭代之后,得到以下聚类:


    箭头显示了簇中心的移动。程序显示进过5次迭代后,簇中心点不在显著移动。(Scikit默认容许阈值为0.0001)。

    在聚类停止之后,我们只需记录下簇中心及其标识。当每个新文档进来的时候,我们对其向量化,并与所有的簇中心进行比较。我们得到与新文档向量距离最小的簇中心所在的簇,然后把这个簇分配给该新文档。这样新文档的向量只需与同一簇中的向量比较、匹配,大大减少计算量。

3. 在20newsgroup上进行文档匹配

    20newsgroup数据集是机器学习中的一个标准数据集。它包含18828个文档,来自于20个不同的新闻组。如果把每个新闻组看作是一个簇,那么很容易测试出我们寻找相关文档的方法是否有效。

    这个数据集可以从MLComp(http://mlcomp.org/datasets/379)下载,本人已将该数据集资源上传:http://download.csdn.net/detail/solomon1558/9007077

    该资源包含一个原信息文件和3个目录:test、train和raw。测试和训练目录将整个数据集切分为60%的训练和40%的测试文档。

3.1 读取数据

    Scikit已经包含了定制的读取器来读取这个数据集。在读取数据时,可以设置环境变量MLCOMP_DATASETS_HOME,或者通过mlcomp_root参数直接指定路径:

import sklearn.datasets
MLCOMP_DIR = r"E:\py_Space\ML_C3\data"
dataset = sklearn.datasets.load_mlcomp("20news-18828", "train", mlcomp_root=MLCOMP_DIR)
print (dataset.filenames) 
print("Number of posts:", len(dataset.filenames))

['E:\\py_Space\\ML_C3\\data\\379\\train\\talk.politics.misc\\17860-178992'

 'E:\\py_Space\\ML_C3\\data\\379\\train\\sci.med\\12836-58920'

 'E:\\py_Space\\ML_C3\\data\\379\\train\\comp.graphics\\871-38995'...,

 'E:\\py_Space\\ML_C3\\data\\379\\train\\sci.space\\14129-61228'

 'E:\\py_Space\\ML_C3\\data\\379\\train\\soc.religion.christian\\15467-20879'

 'E:\\py_Space\\ML_C3\\data\\379\\train\\comp.sys.mac.hardware\\3919-52046']

('Number of posts:', 13180)

    通过设置函数load_mlcomp的第2个参数”train”、”predict”可以选取训练集或测试集。

    为方便起见,把范围限制在某些新闻组中,使整个实验流程更短。我们可以通过设置categories参数实现这一点:

groups = [
    'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware',
    'comp.sys.ma c.hardware', 'comp.windows.x', 'sci.space']
dataset = sklearn.datasets.load_mlcomp("20news-18828", "train",
                                       mlcomp_root=MLCOMP_DIR,
                                       categories=groups
                                       )

3.2 对帖子聚类

    由于真实的文本数据中存在很多噪声,甚至包含不合法的字符,这会导致UnicodeDecodeError报错,我们必须让向量化处理器忽略它们:

vectorizer = StemmedTfidfVectorizer(min_df=10, max_df=0.5,
                                    # max_features=1000,
                                    stop_words='english',
                                    #charset_error=None
                                    decode_error='replace'
                                    )
vectorized = vectorizer.fit_transform(dataset.data)
num_samples, num_features = vectorized.shape
print("#samples: %d, #features: %d" % (num_samples, num_features))

#samples: 3414, #features: 4330

    注意书中采用参数charset_error,运行过程报错:

    TypeError: __init__() gotan unexpected keyword argument 'charset_error'

    应该换用decode_error=’replace’代替。

    输出结果显示现有一个大小为3414的文档池,每个文档的特征向量的维度是4430,这个矩阵就是K均值算法的输入。本实验中把簇的大小固定在50:

num_clusters = 50  # sp.unique(labels).shape[0] 
from sklearn.cluster import KMeans
km = KMeans(n_clusters=num_clusters, init='k-means++', n_init=1,
            verbose=1)
clustered = km.fit(vectorized)

    在拟合之后,我们可以从km的成员变量中获得聚类信息。针对每个拟合过的向量,km.labels_都给出了一个对应的标签:

[27 22 43 ..., 1 44 21]

3.3 预测标签

    本小节介绍如何通过km.predict给新文档分配一个簇。

    首先将新文本向量化:

new_post = \
    """Disk drive problems. Hi, I have a problem with my hard disk.
After 1 year it is working only sporadically now.
I tried to format it, but now it doesn't boot any more.
Any ideas? Thanks.
"""
new_post_vec = vectorizer.transform([new_post])
new_post_label = km.predict(new_post_vec)[0]

    得到新文档的聚类信息后,我们就不需要用new_post_vec和所有的训练文档的向量进行比较。相反,我们只需专注与同一簇中的帖子。从原始数据集中取出它们的索引:

similar_indices = (km.labels_ == new_post_label).nonzero()[0]

    括号中的比较操作可以得到一个布尔型数组,nonzero将这个数组转化为一个更小的数组,它只包含True元素索引。

    然后用similar_indices构建了一个文档列表,以及它们的相似度分值,并对其按相似度升序排序。

similar = []
for i in similar_indices:
    dist = sp.linalg.norm((new_post_vec - vectorized[i]).toarray())
    similar.append((dist, dataset.data[i])) 
similar = sorted(similar)

    打印出最相似的文档(show_at_1),最不相似的文档(show_at_3),以及它们之间的帖子(show_at_3),它们都来自于同一个簇。

show_at_1 = similar[0]
show_at_2 = similar[len(similar) / 2]
show_at_3 = similar[-1]

print(show_at_1)
print(show_at_2)
print(show_at_3)

4. 总结

    从聚类上的预处理,到把有噪文本转化为有意义的简洁向量表示的解决方案,这是一个艰难的过程。其中,我们为最终能够聚类所做的工作占了整个任务的一大部分。但是在这个过程中,我们学习到了很多关于文本处理的知识,以及简单词频统计在有噪声的真实数据上的有效应用。

附录

K-均值聚类例程:

plot_kmeans_exaple.py

# inspired by http://scikit-
# learn.org/dev/auto_examples/cluster/plot_kmeans_digits.html#example-
# cluster-plot-kmeans-digits-py
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')
    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.show()
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))))
print(len(sp.array(list(zip(x, y)))))
#print(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.show()
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

在20newsgroup上进行文档匹配

rel_post_mlcomp.py

import sklearn.datasets
import scipy as sp

new_post = \
    """Disk drive problems. Hi, I have a problem with my hard disk.
After 1 year it is working only sporadically now.
I tried to format it, but now it doesn't boot any more.
Any ideas? Thanks.
"""

MLCOMP_DIR = r"E:\py_Space\ML_C3\data"
groups = [
    'comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.ibm.pc.hardware',
    'comp.sys.ma c.hardware', 'comp.windows.x', 'sci.space']
dataset = sklearn.datasets.load_mlcomp("20news-18828", "train",
                                       mlcomp_root=MLCOMP_DIR,
                                       categories=groups
                                       )
print (dataset.filenames)
print (len(dataset.filenames))
print("Number of posts:", len(dataset.filenames))

labels = dataset.target
num_clusters = 50  # sp.unique(labels).shape[0]

import nltk.stem
english_stemmer = nltk.stem.SnowballStemmer('english')

from sklearn.feature_extraction.text import TfidfVectorizer


class StemmedTfidfVectorizer(TfidfVectorizer):
    def build_analyzer(self):
        analyzer = super(TfidfVectorizer, self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))

vectorizer = StemmedTfidfVectorizer(min_df=10, max_df=0.5,
                                    # max_features=1000,
                                    stop_words='english',
                                    #charset_error=None
                                    decode_error='replace'
                                    )
vectorized = vectorizer.fit_transform(dataset.data)
num_samples, num_features = vectorized.shape
print("#samples: %d, #features: %d" % (num_samples, num_features))


from sklearn.cluster import KMeans
km = KMeans(n_clusters=num_clusters, init='k-means++', n_init=1,
            verbose=1)

clustered = km.fit(vectorized)

from sklearn import metrics
print("Homogeneity: %0.3f" % metrics.homogeneity_score(labels, km.labels_))
print("Completeness: %0.3f" % metrics.completeness_score(labels, km.labels_))
print("V-measure: %0.3f" % metrics.v_measure_score(labels, km.labels_))
print("Adjusted Rand Index: %0.3f" %
      metrics.adjusted_rand_score(labels, km.labels_))
print("Adjusted Mutual Information: %0.3f" %
      metrics.adjusted_mutual_info_score(labels, km.labels_))
print(("Silhouette Coefficient: %0.3f" %
       metrics.silhouette_score(vectorized, labels, sample_size=1000)))

new_post_vec = vectorizer.transform([new_post])
new_post_label = km.predict(new_post_vec)[0]

similar_indices = (km.labels_ == new_post_label).nonzero()[0]
print new_post_label
print km.labels_
similar = []
for i in similar_indices:
    dist = sp.linalg.norm((new_post_vec - vectorized[i]).toarray())
    similar.append((dist, dataset.data[i]))

similar = sorted(similar)

show_at_1 = similar[0]
show_at_2 = similar[len(similar) / 2]
show_at_3 = similar[-1]

print(show_at_1)
print(show_at_2)
print(show_at_3)


import pdb
pdb.set_trace()

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: "Hands-On Machine Learning with Scikit-Learn,Keras"是由Aurélien Géron撰写的一本深度学习和机器学习的实践指南。它是学习机器学习和深度学习的极好资源。 这本书首先介绍了机器学习的基础概念,然后深入讨论了如何使用Scikit-Learn和Keras这两个流行的Python机器学习库。Scikit-Learn提供了丰富的机器学习算法和工具,可以帮助我们构建、训练和评估模型。而Keras是一个用于构建深度学习模型的高级神经网络库。 在这本书中,作者结合实践案例和详细的代码示例,带领读者通过实际的项目学习机器学习和深度学习的应用。你将学习如何预处理和清洗数据、选择合适的模型、训练和调整模型参数,以及评估模型的性能。 此外,这本书还探讨了深度学习的各个方面,包括卷积神经网络、循环神经网络、生成对抗网络等。作者通过讲解这些概念和技术,帮助读者理解深度学习的原理和应用,并将其应用于实际项目中。 总体而言,“Hands-On Machine Learning with Scikit-Learn,Keras”提供了一个全面而易于理解的学习路径,帮助读者从初学者逐步成为机器学习和深度学习的专家。无论你是新手还是有一定经验的开发者,这本书都是一个值得推荐的资源。 ### 回答2: "Hands-On Machine Learning with Scikit-Learn, Keras" 是一本介绍机器学习和深度学习的书籍,作者是Aurélien Géron。这本书的目的是帮助读者从实践的角度深入了解使用Scikit-Learn和Keras库进行机器学习和深度学习的方法。 这本书采用了实践驱动的方法,通过编写代码和实际项目的例子,帮助读者理解机器学习和深度学习的核心概念和技术。书中涵盖了各种机器学习和深度学习的主题,包括数据预处理、监督学习、无监督学习、集成学习、深度神经网络等。 书中的案例涉及到了实际应用场景,比如图像分类、文本分类、推荐系统等。读者可以通过具体的例子理解机器学习和深度学习在实际项目中的应用。 这本书还介绍了使用Scikit-Learn和Keras库的基本操作和功能。读者可以学习如何安装和配置这些库,并学会使用它们进行数据处理、模型训练和评估等操作。 总的来说,《Hands-On Machine Learning with Scikit-Learn, Keras》是一本非常实用的机器学习和深度学习实践指南。它适合那些对机器学习和深度学习感兴趣的读者,尤其是那些希望通过具体的例子和实践项目来学习这些技术的人。这本书将帮助读者理解机器学习和深度学习的基本原理和技术,并将它们应用到实际项目中。 ### 回答3: 《机器学习实战:基于Scikit-Learn和Keras的实践》是一本非常受欢迎的机器学习教材,它由Aurelien Geron编写。这本书提供了关于使用Scikit-Learn和Keras进行实践的详细指导和示例。 Scikit-Learn是一个常用的Python机器学习库,它集成了许多常用的机器学习算法和工具,使机器学习模型的开发变得更加简单和高效。Keras是另一个流行的深度学习库,它提供了高级的神经网络建模接口,使深度学习模型的设计和实现变得更加容易。 《机器学习实战:基于Scikit-Learn和Keras的实践》主要分为三个部分。第一部分介绍了机器学习的基本概念和常用技术,如线性回归、逻辑回归、决策树和随机森林等。第二部分介绍了深度学习的基本原理和常用模型,如卷积神经网络和循环神经网络等。第三部分通过几个实际项目的实例,展示了如何使用Scikit-Learn和Keras进行机器学习和深度学习的实践。 这本书在整个实践过程中给出了详细的步骤和代码示例,有助于读者理解和复现。此外,书中还提供了相关的数据集和预训练模型,方便读者进行实际的实验和项目开发。 总体而言,《机器学习实战:基于Scikit-Learn和Keras的实践》是一本很好的机器学习实战指南,适合那些对机器学习和深度学习感兴趣的读者。无论是初学者还是有经验的从业者,都能从中获得宝贵的知识和技能。希望通过阅读这本书,读者能够在机器学习和深度学习领域取得更好的成果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值