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

jhcelue jhcelue     2022-09-04     192

关键词:

前言:

    本系列是在作者学习《机器学习系统设计》([美] WilliRichert)过程中的思考与实践,全书通过Python从数据处理。到特征project,再到模型选择,把机器学习解决这个问题的过程一一呈现。

书中设计的源码和数据集已上传到我的资源:http://download.csdn.net/detail/solomon1558/8971649

       第3章通过词袋模型+K均值聚类实现相关文本的匹配。本文主要解说文本预处理部分内容。涉及切分文本、数据清洗、计算TF-IDF值等内容。

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

1. 统计词语

    使用一个简单的数据集进行实验,它包含5个文档:

    01.   txt     This is a toy post about machine learning.Actually, it contains not much interesting stuff.

    02.   txt     Imaging databases provide storagecapabilities.

    03.   txt     Most imaging databases safe imagespermanently.

    04.   txt     Imaging databases store data.

    05.   txt     Imaging databases store data. Imagingdatabases store data. Imaging databases store data.

    在这个文档数据集中。我们想要找到和文档”imaging database”最相近的文档。为了将原始文本转换成聚类算法能够使用的特征数据,首先须要使用词袋(bag-of-word)方法来衡量文本间相似性。终于生成每一个文本的特征向量。

     词袋方法基于简单的词频统计。统计每个帖子中的词频,表示成一个向量,即向量化。Scikit-learn的CountVectorizer能够高效地完毕统计词语的工作,Scikit的函数和类能够通过sklearn包引入进来:

posts = [open(os.path.join(DIR, f)).read() for f in os.listdir(DIR)]
vectorizer = CountVectorizer(min_df=1, stop_words="english")
X_train = vectorizer.fit_transform(posts)

    如果待训练的文本存放在文件夹DIR下,我们将数据集传给CountVectorizer。

參数min_df决定了CounterVectorizer怎样处理那些不常常使用的词语(最小文档词频)。当min_df为一个整数时,全部出现次数小于这个值的词语都将被扔掉;当它是一个比例时,将整个数据集中出现比例小于这个值的词语都将被丢弃。

    我们须要告诉这个想量化处理器整个数据集的信息,使它能够预先知道都有哪些词语:

X_train = vectorizer.fit_transform(posts)
num_samples, num_features = X_train.shape
print ("#sample: %d, #feature: %d" % (num_samples, num_features))
print(vectorizer.get_feature_names())

    程序的输出例如以下。5个文档中包括了25个词语

            #sample: 5, #feature: 25

            [u‘about‘, u‘actually‘, u‘capabilities‘, u‘contains‘,u‘data‘, u‘databases‘, u‘images‘, u‘imaging‘, u‘interesting‘, u‘is‘, u‘it‘,u‘learning‘, u‘machine‘, u‘most‘, u‘much‘, u‘not‘, u‘permanently‘, u‘post‘,u‘provide‘, u‘safe‘, u‘storage‘, u‘store‘, u‘stuff‘, u‘this‘, u‘toy‘]

    对新文档进行向量化:

#a new post
new_post = "imaging databases"
new_post_vec = vectorizer.transform([new_post])

    把每一个样本的词频数组当做向量进行相似度计算,须要使用数组的所有元素[使用成员函数toarray()]。

通过norm()函数计算新文档与所有训练文档向量的欧几里得范数(最小距离),从而衡量它们之间的相似度。

#------- calculate raw distances betwee new and old posts and record the shortest one-------------------------
def dist_raw(v1, v2):
    delta = v1 - v2
    return sp.linalg.norm(delta.toarray())
best_doc = None
best_dist = sys.maxint
best_i = None
for i in range(0, num_samples):
    post = posts[i]
    if post == new_post:
        continue
    post_vec = X_train.getrow(i)
    d = dist_raw(post_vec, new_post_vec)
    print "=== Post %i with dist = %.2f: %s" % (i, d, post)
    if d<best_dist:
        best_dist = d
        best_i = i
print("Best post is %i with dist=%.2f" % (best_i, best_dist))

            === Post 0 with dist = 4.00:This is a toy post about machine learning. Actually, it contains not muchinteresting stuff.

            === Post 1 with dist =1.73:Imaging databases provide storage capabilities.

            === Post 2 with dist =2.00:Most imaging databases safe images permanently.

            === Post 3 with dist =1.41:Imaging databases store data.

            === Post 4 with dist =5.10:Imaging databases store data. Imaging databases store data. Imaging databasesstore data.

            Best post is 3 with dist=1.41

    结果显示文档3与新文档最为相似。然而文档4和文档3的内容一样,但反复了3遍。所以,它和新文档的相似度应该与文档3是一样的。

#-------case study: why post 4 and post 5 different ?-----------
print(X_train.getrow(3).toarray())
print(X_train.getrow(4).toarray())

            [[0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]]

            [[0 0 0 0 3 3 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0]]

2. 文本处理

2.1 词频向量归一化

       对第2节中的dist_raw函数进行扩展,在归一化的向量上(向量各分量除以其模长)计算向量间的距离。

def dist_norm(v1, v2):
    v1_normalized = v1 / sp.linalg.norm(v1.toarray())
    v2_normalized = v2 / sp.linalg.norm(v2.toarray())
    delta = v1_normalized - v2_normalized
    return sp.linalg.norm(delta.toarray())

            === Post 0 with dist = 1.41: This is a toy post aboutmachine learning. Actually, it contains not much interesting stuff.

            === Post 1 with dist = 0.86: Imaging databases providestorage capabilities.

            === Post 2 with dist = 0.92: Most imaging databasessafe images permanently.

            === Post 3 with dist = 0.77:Imagingdatabases store data.

            === Post 4 with dist = 0.77:Imaging databases store data. Imaging databases store data. Imaging databasesstore data.

            Best post is 3 with dist=0.77   

    词频向量归一化之后,文档3和文档4与新文档具有了同样的相似度。从词频统计的角度来说,这样处理更为正确。

2.2 排除停用词

    文本中类似”the”、”of”这些单词常常出如今各种不同的文本中,被称为停用词。因为停用词对于区分文本没有多大帮助,因此删除停用词是文本处理中的一个常见步骤。

CountVectorizer中有一个简单的參数stop_words()能够完毕该任务:

vectorizer = CountVectorizer(min_df=1, stop_words=‘english‘)

2.3词干处理

    为了将语义类似但形式不同的词语放在一起统计,我们须要一个函数将词语归约到特定的词干形式。自然语言处理工具包(NLTK)提供了一个很easy嵌入到CountVectorizer的词干处理器。

    把文档传入CountVectorizer之前,我们须要对它们进行词干处理。

该类提供了几种钩子。能够用它们定制预处理和词语切分阶段的操作。

预处理器和词语切分器能够当作參数传入构造函数。

我们并不想把词干处理器放入它们不论什么一个其中,由于那样的话,之后还须要亲自对词语进行切分和归一化。相反。我们能够通过改写build_analyzer方法来实现:

import nltk.stem
english_stemmer = nltk.stem.SnowballStemmer(‘english‘)
class StemmedCountVectorizer(CountVectorizer):
    def build_analyzer(self):
        analyzer = super(StemmedCountVectorizer, self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))
vectorizer = StemmedCountVectorizer(min_df=1, stop_words=‘english‘)

    依照例如以下步骤对每一个帖子进行处理:

(1)   在预处理阶段将原始文档变成小写字母形式(这在父类中完毕);

(2)   在词语切分阶段提取全部单词;

(3)   将每一个词语转换成词干形式。

3. 计算TF-IDF

    至此,我们採用统计词语的方式,从充满噪声的文本中提取了紧凑的特征向量。这些特征的值就是对应词语在全部训练文本中出现的次数,我们默认较大的特征值意味着合格词语对文本更为重要。

可是在训练文本中,不同的词语对文本的可区分性贡献更大。

    这须要通过统计每一个文本的词频,而且对出如今多个文本中的词语在权重上打折来解决。即当某个词语常常出如今一些特定的文本中,而在其它地方非常少出现时。应该赋予该词语更大的权值。

    这正是词频-反转文档频率(TF-IDF)所要做的:TF代表统计部分,而IDF把权重折扣考虑了进去。一个简单的实现例如以下:

import scipy as sp
def tfidf(t, d, D):
    tf = float(d.count(t)) / sum(d.count(w) for w in set(d))
    idf = sp.log(float(len(D)) / (len([doc for doc in D if t in doc])))
    return tf * idf

    在实际应用过程中,scikit-learn已经将该算法封装进了TfidfVectorizer(继承自CountVectorizer)中。进行这些操作后,我们得到的文档向量不会再包括词语拥挤值,而是每一个词语的TF-IDF值。

代码清单:

import os
import sys
import scipy as sp
from sklearn.feature_extraction.text import CountVectorizer

DIR = r"../data/toy"
posts = [open(os.path.join(DIR, f)).read() for f in os.listdir(DIR)]
new_post = "imaging databases"

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

class StemmedCountVectorizer(CountVectorizer):
    def build_analyzer(self):
        analyzer = super(StemmedCountVectorizer, self).build_analyzer()
        return lambda doc: (english_stemmer.stem(w) for w in analyzer(doc))
#vectorizer = StemmedCountVectorizer(min_df=1, stop_words=‘english‘)

from sklearn.feature_extraction.text import TfidfVectorizer

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

vectorizer = StemmedTfidfVectorizer(min_df=1, stop_words=‘english‘)
print(vectorizer)
X_train = vectorizer.fit_transform(posts)

num_samples, num_features = X_train.shape
print("#samples: %d, #features: %d" % (num_samples, num_features))

new_post_vec = vectorizer.transform([new_post])
print(new_post_vec, type(new_post_vec))
print(new_post_vec.toarray())
print(vectorizer.get_feature_names())

def dist_raw(v1, v2):
    delta = v1 - v2
    return sp.linalg.norm(delta.toarray())
def dist_norm(v1, v2):
    v1_normalized = v1 / sp.linalg.norm(v1.toarray())
    v2_normalized = v2 / sp.linalg.norm(v2.toarray())
    delta = v1_normalized - v2_normalized
    return sp.linalg.norm(delta.toarray())

dist = dist_norm
best_dist = sys.maxsize
best_i = None

for i in range(0, num_samples):
    post = posts[i]
    if post == new_post:
        continue
    post_vec = X_train.getrow(i)
    d = dist(post_vec, new_post_vec)
    print("=== Post %i with dist=%.2f: %s" % (i, d, post))
    if d < best_dist:
        best_dist = d
        best_i = i
print("Best post is %i with dist=%.2f" % (best_i, best_dist))

4. 总结

    文本预处理过程包括的步骤总结例如以下:

 (1)   切分文本;

 (2)   扔掉出现过于频繁。而又对匹配相关文档没有帮助的词语;

 (3)   扔掉出现频率非常低。仅仅有非常小可能出如今未来帖子中的词语;

 (4)   统计剩余的词语。

 (5)   考虑整个预料集合,从词频统计中计算TF-IDF值。

     通过这一过程。我们将一堆充满噪声的文本转换成了一个简明的特征表示。

然而,尽管词袋模型及其扩展简单有效,但仍然有一些缺点须要注意:

 (1)   它并不涵盖词语之间的关联关系。採用之前的向量化方法,文本”Car hits wall”和”Wall hits car”会有同样的特征向量。

 (2)   它没法捕捉否定关系。

比如”I will eat ice cream”和”I will not eat ice cream”。虽然它们意思截然相反。但从特征向量来看它们非常相似。这个问题事实上非常easy解决,仅仅须要既统计单个词语(又叫unigrams)。又考虑成队的词语(bigrams)或者trigrams(一行中的三个词语)就可以。

(3)   对于拼写错误的词语会处理失败。

spark与scikit-learn机器学习流程组件设计哲学比较

概述:估算器,变换器和管道-spark.ml该spark.ml软件包旨在提供基于DataFrame构建的一组统一的高级API,帮助用户创建和调整实用的机器学习流程。有关子包的指南,请参阅下面的算法指南部分spark.ml,包括PipelinesAPI特有的功能转换... 查看详情

如何将 python scikit-learn 应用于图像/声音/视频以进行机器学习? [关闭]

】如何将pythonscikit-learn应用于图像/声音/视频以进行机器学习?[关闭]【英文标题】:Howtoapplypythonscikit-learntoimages/sound/videosformachinelearning?[closed]【发布时间】:2017-05-0207:54:27【问题描述】:如果有人可以解释并举例说明如何使用s... 查看详情

stanford机器学习---第十四讲.机器学习应用举例之photoocr

...ctaveTutorial、LogisticRegression、Regularization、神经网络、机器学习系统设计、SVM(SupportVectorMachines支持向量机)、聚类、降维、异常检 查看详情

scikit-learn机器学习实践——垃圾短信识别

...习的垃圾短信识别。其实除了使用NLTK,我们还可以使用Scikit-Learn这个集成了诸多机器学习算法的模块进行上述的实验。Scikit-Learn的API设计非常合理和高效,对于初触机器学习的同学来说非常友好,值得大家尝试和使用。本人也... 查看详情

sklearn学习笔记之开始

简介??自2007年发布以来,scikit-learn已经成为Python重要的机器学习库了。scikit-learn简称sklearn,支持包括分类、回归、降维和聚类四大机器学习算法。还包含了特征提取、数据处理和模型评估三大模块。??sklearn是Scipy的扩展,建立在... 查看详情

scikit-learn和pandas基于windows单机机器学习环境的搭建

...想学习机器学习,却苦于环境的搭建,这里给出windows上scikit-learn研究开发环境的搭建步骤。Step1.Python的安装    python有2.x和3.x的版本之分,但是很多好的机器学习python库都不支持3.x,因此,推荐安装2.7版本的python。当前最... 查看详情

scikit-learn和pandas基于windows单机机器学习环境的搭建

...想学习机器学习,却苦于环境的搭建,这里给出windows上scikit-learn研究开发环境的搭建步骤。Step1.Python的安装    python有2.x和3.x的版本之分,但是很多好的机器学习python库都不支持3.x,因此,推荐安装2.7版本的python。当前最... 查看详情

scikit-learn和pandas基于windows单机机器学习环境的搭建

...想学习机器学习,却苦于环境的搭建,这里给出windows上scikit-learn研究开发环境的搭建步骤。Step1.Python的安装    python有2.x和3.x的版本之分,但是很多好的机器学习python库都不支持3.x,因此,推荐安装2.7版本的python。当前最... 查看详情

scikit-learn和pandas基于windows单机机器学习环境的搭建

...想学习机器学习,却苦于环境的搭建,这里给出windows上scikit-learn研究开发环境的搭建步骤。Step1.Python的安装    python有2.x和3.x的版本之分,但是很多好的机器学习python库都不支持3.x,因此,推荐安装2.7版本的python。当前最... 查看详情

机器学习:神经网络之表达

...*****注:本系列博客是博主学习Stanford大学AndrewNg教授的《机器学习》课程笔记。博主深感学过课程后,不进行总结非常easy遗忘。依据课程加上自己对不明确问题的补充遂有此系列博客。本系列博客包含线性回归、逻辑回归、神... 查看详情

spark机器学习

...学习算法结合成单个pipeline或者单个工作流。这个概念和scikit-learn里的概念类似,根据官方的说法是,此抽象概念的设计灵感来自于scikit-learn。·        DataF 查看详情

《机器学习系统设计》之数据理解和提炼

前言:   本系列是在作者学习《机器学习系统设计》([美]WilliRichert)过程中的思考与实践,全书通过Python从数据处理,到特征project,再到模型选择。把机器学习解决这个问题的过程一一呈现。书中设计的源码和数据... 查看详情

pytorch&scikit-learn机器学1-赋予计算机从数据中学习的能力(代码片段)

...学习的一般概念三种类型的学习和基本术语成功设计机器学习系统的基石安装和设置用于数据分析和机器学习的Python构建智能机器,将数据转化为知识机器学习的一般概念在这个现代技术的时代有大量的结构化和非结构化数据。... 查看详情

andrewng机器学习课程笔记之应用机器学习的建议

AndrewNg机器学习课程笔记(五)之应用机器学习的建议版权声明:本文为博主原创文章,转载请指明转载地址http://www.cnblogs.com/fydeblog/p/7368472.html 前言学习了AndrewNg课程,开始写了一些笔记,现在写完第5章了,先把这5章的内... 查看详情

机器学习scikit-learn图谱

scikit-learn是机器学习领域非常热门的一个开源库。基于Python语言写成。能够免费使用。网址:http://scikit-learn.org/stable/index.html上面有非常多的教程,编程实例。并且还做了非常好的总结,以下这张图基本概括了传统机器学习领域... 查看详情

02-14scikit-learn库之逻辑回归

目录scikit-learn库之逻辑回归一、LogisticRegression1.1使用场景1.2代码1.3参数详解1.4属性1.5方法二、LogisticRegressionCV三、logistic_regression_path更新、更全的《机器学习》的更新网站,更有python、go、数据结构与算法、爬虫、人工智能教学... 查看详情

使用 Scikit-Learn 数据上传查询机器学习

】使用Scikit-Learn数据上传查询机器学习【英文标题】:QueryonMachineLearningwithScikit-Learndatauploading【发布时间】:2016-10-3104:04:48【问题描述】:我正在尝试使用Scikit-Learn开发基于机器学习的图像分类系统。我想做的是多类分类。我在... 查看详情

机器学习神器scikit-learn保姆教程!

Scikit-learn是一个非常知名的Python机器学习库,它广泛地用于统计分析和机器学习建模等数据科学领域。建模无敌:用户通过scikit-learn能够实现各种监督和非监督学习的模型功能多样:同时使用sklearn还能够进行数据的... 查看详情