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

前言:

本系列是在作者学习《机器学习系统设计》([美] 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()

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 19:46:28

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

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

前言: 本系列是在作者学习<机器学习系统设计>([美] WilliRichert)过程中的思考与实践,全书通过Python从数据处理,到特征工程,再到模型选择,把机器学习解决问题的过程一一呈现.书中设计的源代码和数据集已上传到我的资源:http://download.csdn.net/detail/solomon1558/8971649 第3章通过词袋模型+K均值聚类实现相关文本的匹配.本文主要讲解文本预处理部分内容,涉及切分文本.数据清洗.计算TF-IDF值等内容. 1. 统计词语 使用一个

NLP系列(3)_用朴素贝叶斯进行文本分类(下)

作者: 龙心尘 && 寒小阳 时间:2016年2月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50629110 http://blog.csdn.net/han_xiaoyang/article/details/50629587 声明:版权所有,转载请联系作者并注明出处 1. 引言 上一篇文章我们主要从理论上梳理了朴素贝叶斯方法进行文本分类的基本思路.这篇文章我们主要从实践上探讨一些应用过程中的tricks,并进一步分

应用scikit-learn做文本分类

http://blog.csdn.net/abcjennifer/article/details/23615947 文本挖掘的paper没找到统一的benchmark,只好自己跑程序,走过路过的前辈如果知道20newsgroups或者其它好用的公共数据集的分类(最好要所有类分类结果,全部或取部分特征无所谓)麻烦留言告知下现在的benchmark,万谢! 嗯,说正文.20newsgroups官网上给出了3个数据集,这里我们用最原始的20news-19997.tar.gz. 分为以下几个过程: 加载

如何使用“预训练的词向量”,做文本分类

不多比比了,看代码!!! def train_W2V(w2vCorpus, size=100): w2vModel = Word2Vec(sentences=w2vCorpus, hs=0, negative=5, min_count=5, window=8, iter=1, size=size) w2vModel.save(inPath+'w2vModel.model') return w2vModel def load_W2V(W2V_path, loader_mySelf=1): if l

文本分类:survey

作者:尘心链接:https://zhuanlan.zhihu.com/p/76003775 简述 文本分类在文本处理中是很重要的一个模块,它的应用也非常广泛,比如:垃圾过滤,新闻分类,词性标注等等.它和其他的分类没有本质的区别,核心方法为首先提取分类数据的特征,然后选择最优的匹配,从而分类.但是文本也有自己的特点,根据文本的特点,文本分类的一般流程为:1.预处理:2.文本表示及特征选择:3.构造分类器:4.分类. 通常来讲,文本分类任务是指在给定的分类体系中,将文本指定分到某个或某几个类别中.被

广告行业中那些趣事系列2:BERT实战NLP文本分类任务(附github源码)

摘要:上一篇广告中那些趣事系列1:广告统一兴趣建模流程,我们了解了如何为广告主圈人群以及如何刻画用户的兴趣度.要想给用户打标签,我们需要构建数据源和标签的关联,也就是item-tag.针对数量较少的app数据源我们可以使用人工打标的方式来识别,但是对于news.用户query等数量较多的数据源则需要通过机器学习模型来进行打标.实际项目中我们使用NLP中鼎鼎大名的BERT模型来进行文本分类. 通过本篇学习,小伙伴们可以迅速上手BERT模型用于文本分类任务.对数据挖掘.数据分析和自然语言处理感兴趣的

中文文本分类

本文介绍文本挖掘与文本分类的一些基本概念和流程,为后续学习分类算法做好铺垫. 一. 文本挖掘的概念 文本挖掘(Text Mining)是从非结构化文本信息中获取用户感兴趣或者有用的模式 的过程.其中被普遍认可的文本挖掘定义如下:文本挖掘是指从大量文本数据中抽取事先未知的.可理解的.最终可用的知识的过程,同时运用这些知识更好地组织信息以便将来参考. 简言之,文本挖掘就是从非结构化的文本中寻找知识的过程. 文本挖掘的七个主要领域: (1)搜索和信息检索(IR):存储和文本文档的检索,包括搜索引擎和关

Tensorflor实现文本分类

Tensorflor实现文本分类 下面我们使用CNN做文本分类 cnn实现文本分类的原理 下图展示了如何使用cnn进行句子分类.输入是一个句子,为了使其可以进行卷积,首先需要将其转化为向量表示,通常使用word2vec实现.d=5表示每个词转化为5维的向量,矩阵的形状是[sentence_length × 5],即[7 ×5].6个filter(卷积核),与图像中使用的卷积核不同的是,nlp使用的卷积核的宽与句子矩阵的宽相同,只是长度不同.这里有(2,3,4)三种size,每种size有两个fi

基于协同训练的半监督文本分类算法

标签: 半监督学习,文本分类 作者:炼己者 --- 本博客所有内容以学习.研究和分享为主,如需转载,请联系本人,标明作者和出处,并且是非商业用途,谢谢! 如果大家觉得格式看着不舒服,也欢迎大家去看我的简书 半监督学习文本分类系列 用半监督算法做文本分类(sklearn) sklearn半监督学习(sklearn) 基于自训练的半监督文本分类算法 一. 摘要 本文主要讲述基于协同训练的半监督算法做文本分类,用三个差异性比较大的分类器对未标注数据进行标注,它们可以进行交叉验证,大大提升了对未标注数据