Python 机器学习 基础 之 处理文本数据 【处理文本数据/用字符串表示数据类型/将文本数据表示为词袋】的简单说明

Python 机器学习 基础 之 处理文本数据 【处理文本数据/用字符串表示数据类型/将文本数据表示为词袋】的简单说明

目录

Python 机器学习 基础 之 处理文本数据 【处理文本数据/用字符串表示数据类型/将文本数据表示为词袋】的简单说明

一、简单介绍

二、处理文本数据

三、用字符串表示的数据类型

四、示例应用:电影评论的情感分析

五、将文本数据表示为词袋

附录:

一、参考文献

二、网站的电影评论数据集数据下载界面


一、简单介绍

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。Python是一种解释型脚本语言,可以应用于以下领域: Web 和 Internet开发、科学计算和统计、人工智能、教育、桌面界面开发、软件开发、后端开发、网络爬虫。

Python 机器学习是利用 Python 编程语言中的各种工具和库来实现机器学习算法和技术的过程。Python 是一种功能强大且易于学习和使用的编程语言,因此成为了机器学习领域的首选语言之一。Python 提供了丰富的机器学习库,如Scikit-learn、TensorFlow、Keras、PyTorch等,这些库包含了许多常用的机器学习算法和深度学习框架,使得开发者能够快速实现、测试和部署各种机器学习模型。

Python 机器学习涵盖了许多任务和技术,包括但不限于:

  1. 监督学习:包括分类、回归等任务。
  2. 无监督学习:如聚类、降维等。
  3. 半监督学习:结合了有监督和无监督学习的技术。
  4. 强化学习:通过与环境的交互学习来优化决策策略。
  5. 深度学习:利用深度神经网络进行学习和预测。

通过 Python 进行机器学习,开发者可以利用其丰富的工具和库来处理数据、构建模型、评估模型性能,并将模型部署到实际应用中。Python 的易用性和庞大的社区支持使得机器学习在各个领域都得到了广泛的应用和发展。

二、处理文本数据

在前面的文章中,我们讨论过表示数据属性的两种类型的特征:连续特征与分类特征,前者用于描述数量,后者是固定列表中的元素。在许多应用中还可以见到第三种类型的特征:文本。

举个例子,如果我们想要判断一封电子邮件是合法邮件还是垃圾邮件,那么邮件内容一定会包含对这个分类任务非常重要的信息。或者,我们可能想要了解一位政治家对移民问题的看法。这个人的演讲或推文可能会提供有用的信息。在客户服务中,我们通常想知道一条消息是投诉还是咨询。我们可以利用消息的主题和内容来自动判断客户的目的,从而将消息发送给相关部门,甚至可以发送一封全自动回复。

文本数据通常被表示为由字符组成的字符串。在上面给出的所有例子中,文本数据的长度都不相同。这个特征显然与前面讨论过的数值特征有很大不同,我们需要先处理数据,然后才能对其应用机器学习算法。

在机器学习中,处理文本数据是一个重要的任务,尤其在自然语言处理(NLP)领域。文本数据的处理通常涉及特征提取、模型训练和评估。以下是一些关键步骤和方法:

1. 文本预处理

在处理文本数据之前,通常需要进行一些预处理步骤,以确保数据的一致性和质量:

  • 去除标点和特殊字符:删除不必要的标点符号和特殊字符。
  • 小写转换:将所有文本转换为小写,以减少特征数量。
  • 去除停用词:移除常见的无意义的词汇(如 "the", "is", "and" 等)。
  • 词干化和词形还原:将单词还原到其原始或词干形式,例如 "running" 变成 "run"。

2. 特征提取

文本数据需要转换为数值特征,以便输入机器学习模型。常见的方法包括:

  • 词袋模型 (Bag of Words, BoW):将文本转换为词频向量。
  • TF-IDF (Term Frequency-Inverse Document Frequency):调整词频,以减少常见词的影响。
  • 词嵌入 (Word Embeddings):将单词映射到低维向量空间,常用的有 Word2Vec、GloVe 和 FastText。
  • 句子嵌入 (Sentence Embeddings):将整个句子或段落映射到向量空间,如使用 BERT、GPT 等预训练模型。

3. 模型训练和评估

将文本转换为数值特征后,可以使用常见的机器学习模型进行训练和评估,例如朴素贝叶斯、支持向量机、逻辑回归等。

4. 管道和交叉验证

为了更好地处理文本数据,可以使用管道和交叉验证来优化模型。管道可以将预处理步骤和模型训练连接在一起,简化工作流程。交叉验证则可以更可靠地评估模型性能。

5. 高级文本处理

对于更复杂的任务,可以使用高级的文本处理技术,例如:

  • Word2Vec 和 GloVe:用于生成词向量的预训练模型。
  • Transformer 模型:如 BERT、GPT-3 等,可以生成上下文相关的词向量或句子向量。

总结:

处理文本数据涉及多个步骤,从预处理、特征提取到模型训练和评估。使用合适的方法和工具,可以有效地将文本数据转换为数值特征,并训练出性能优异的模型。管道和交叉验证可以帮助简化流程和优化模型,而高级的文本处理技术则能进一步提升模型的表现。

三、用字符串表示的数据类型

在深入研究表示机器学习文本数据的处理步骤之前,我们希望简要讨论你可能会遇到的不同类型的文本数据。文本通常只是数据集中的字符串,但并非所有的字符串特征都应该被当作文本来处理。我们在之前的篇章讨论过,字符串特征有时可以表示分类变量。在查看数据之前,我们无法知道如何处理一个字符串特征。

你可能会遇到四种类型的字符串数据:

  • 分类数据
  • 可以在语义上映射为类别的自由字符串
  • 结构化字符串数据
  • 文本数据

分类数据 (categorical data)是来自固定列表的数据。

比如你通过调查人们最喜欢的颜色来收集数据,你向他们提供了一个下拉菜单,可以从“红色”“绿色”“蓝色”“黄色”“黑色”“白色”“紫色”和“粉色”中选择。这样会得到一个包含 8 个不同取值的数据集,这 8 个不同取值表示的显然是分类变量。你可以通过观察来判断你的数据是不是分类数据(如果你看到了许多不同的字符串,那么不太可能是分类变量),并通过计算数据集中的唯一值并绘制其出现次数的直方图来验证你的判断。你可能还希望检查每个变量是否实际对应于一个在应用中有意义的分类。调查过程进行到一半,有人可能发现调查问卷中将“black”(黑色)错拼为“blak”,并随后对其进行了修改。因此,你的数据集中同时包含“black”和“blak”,它们对应于相同的语义,所以应该将二者合并。

现在想象一下,你向用户提供的不是一个下拉菜单,而是一个文本框,让他们填写自己最喜欢的颜色。许多人的回答可能是像“黑色”或“蓝色”之类的颜色名称。其他人可能会出现笔误,使用不同的单词拼写(比如“gray”和“grey”(两个词的意思都是“灰色”) ),或使用更加形象的具体名称(比如“午夜蓝色”)。你还会得到一些非常奇怪的条目。xkcd 颜色调查(Color Survey Results – xkcd )中有一些很好的例子,其中有人为颜色命名,给出了如“迅猛龙泄殖腔”和“我牙医办公室的橙色。我仍然记得他的头皮屑慢慢地漂落到我张开的下巴”之类的名称,很难将这些名称与颜色自动对应(或者根本就无法对应)。

从文本框中得到的回答属于上述列表中的第二类,可以在语义上映射为类别的自由字符串 (free strings that can be semantically mapped to categories)。可能最好将这种数据编码为分类变量,你可以利用最常见的条目来选择类别,也可以自定义类别,使用户回答对应用有意义。这样你可能会有一些标准颜色的类别,可能还有一个“多色”类别(对于像“绿色与红色条纹”之类的回答)和“其他”类别(对于无法归类的回答)。这种字符串预处理过程可能需要大量的人力,并且不容易自动化。如果你能够改变数据的收集方式,那么我们强烈建议,对于分类变量能够更好表示的概念,不要使用手动输入值。

通常来说,手动输入值不与固定的类别对应,但仍有一些内在的结构 (structure),比如地址、人名或地名、日期、电话号码或其他标识符。这种类型的字符串通常难以解析,其处理方法也强烈依赖于上下文和具体领域。对这种情况的系统处理方法超出了本书的范围。

最后一类字符串数据是自由格式的文本数据 (text data),由短语或句子组成。例子包括推文、聊天记录和酒店评论,还包括莎士比亚文集、维基百科的内容或古腾堡计划收集的 50 000 本电子书。所有这些集合包含的信息大多是由单词组成的句子(推文中链接网站的内容所包含的信息可能比推文本身还要多)。 为了简单起见,我们假设所有的文档都只使用一种语言:英语(接下来的绝大部分内容也适用于其他使用罗马字母的语言,部分适用于具有单词定界符的其他语言。例如,中文没有词边界,还有其他方面的挑战,所以难以应用本章介绍的技术)。 在文本分析的语境中,数据集通常被称为语料库 (corpus),每个由单个文本表示的数据点被称为文档 (document)。这些术语来自于信息检索 (information retrieval,IR)和自然语言处理 (natural language processing,NLP)的社区,它们主要针对文本数据。

四、示例应用:电影评论的情感分析

作为本章的一个运行示例,我们将使用由斯坦福研究员 Andrew Maas 收集的 IMDb(Internet Movie Database,互联网电影数据库)网站的电影评论数据集(你可以在 Sentiment Analysis 下载这个数据集)。 这个数据集包含评论文本,还有一个标签,用于表示该评论是“正面的”(positive)还是“负面的”(negative)。IMDb 网站本身包含从 1 到 10 的打分。为了简化建模,这些评论打分被归纳为一个二分类数据集,评分大于等于 7 的评论被标记为“正面的”,评分小于等于 4 的评论被标记为“负面的”,中性评论没有包含在数据集中。我们不讨论这种方法是否是一种好的数据表示,而只是使用 Andrew Maas 提供的数据。

将数据解压之后,数据集包括两个独立文件夹中的文本文件,一个是训练数据,一个是测试数据。每个文件夹又都有两个子文件夹,一个叫作 pos,一个叫作 neg:

!tree data/aclImdb

pos 文件夹包含所有正面的评论,每条评论都是一个单独的文本文件,neg 文件夹与之类似。scikit-learn 中有一个辅助函数可以加载用这种文件夹结构保存的文件,其中每个子文件夹对应于一个标签,这个函数叫作 load_files 。我们首先将 load_files 函数应用于训练数据(由于数据比较多,这里比较耗时):

from sklearn.datasets import load_files

reviews_train = load_files("data/aclImdb/train/")
# load_files返回一个Bunch对象,其中包含训练文本和训练标签
text_train, y_train = reviews_train.data, reviews_train.target
print("type of text_train: {}".format(type(text_train)))
print("length of text_train: {}".format(len(text_train)))
print("text_train[1]:\n{}".format(text_train[1]))
type of text_train: <class 'list'>
length of text_train: 25000
text_train[1]:
b'Words can\'t describe how bad this movie is. I can\'t explain it by writing only. You have too see it for yourself to get at grip of how horrible a movie really can be. Not that I recommend you to do that. There are so many clich\xc3\xa9s, mistakes (and all other negative things you can imagine) here that will just make you cry. To start with the technical first, there are a LOT of mistakes regarding the airplane. I won\'t list them here, but just mention the coloring of the plane. They didn\'t even manage to show an airliner in the colors of a fictional airline, but instead used a 747 painted in the original Boeing livery. Very bad. The plot is stupid and has been done many times before, only much, much better. There are so many ridiculous moments here that i lost count of it really early. Also, I was on the bad guys\' side all the time in the movie, because the good guys were so stupid. "Executive Decision" should without a doubt be you\'re choice over this one, even the "Turbulence"-movies are better. In fact, every other movie in the world is better than this one.'

你可以看到,text_train 是一个长度为 75 000(对于 v1.0 版数据,其训练集大小是 75 000,而不是 25 000,因为其中还包含 50 000 个用于无监督学习的无标签文档(data\aclImdb\train\unsup )。在进行后续操作之前,建议先将这 50 000 个无标签文档从训练集中剔除,同时可能会影响数据结果) 的列表  ,其中每个元素是包含一条评论的字符串。我们打印出索引编号为 1 的评论。你还可以看到,评论中包含一些 HTML 换行符(<br /> )。虽然这些符号不太可能对机器学习模型产生很大影响,但最好在继续下一步之前清洗数据并删除这种格式:

text_train = [doc.replace(b"<br />", b" ") for doc in text_train]

text_train 的元素类型与你所使用的 Python 版本有关。在 Python 3 中,它们是 bytes 类型,是表示字符串数据的二进制编码。在 Python 2 中,text_train 包含的是字符串。这里不会深入讲解 Python 中不同的字符串类型,但我们推荐阅读 Python 2(Unicode HOWTO — Python 2.7.18 documentation )和 Python 3(Unicode HOWTO — Python 3.12.3 documentation )的文档中关于字符串和 Unicode 的内容。

收集数据集时保持正类和反类的平衡,这样所有正面字符串和负面字符串的数量相等:

import numpy as np

print("Samples per class (training): {}".format(np.bincount(y_train)))
Samples per class (training): [12500 12500]

我们用同样的方式加载测试数据集:

reviews_test = load_files("data/aclImdb/test/")
text_test, y_test = reviews_test.data, reviews_test.target
print("Number of documents in test data: {}".format(len(text_test)))
print("Samples per class (test): {}".format(np.bincount(y_test)))
text_test = [doc.replace(b"<br />", b" ") for doc in text_test]
Number of documents in test data: 25000
Samples per class (test): [12500 12500]

我们要解决的任务如下:给定一条评论,我们希望根据该评论的文本内容对其分配一个“正面的”或“负面的”标签。这是一项标准的二分类任务。但是,文本数据并不是机器学习模型可以处理的格式。我们需要将文本的字符串表示转换为数值表示,从而可以对其应用机器学习算法。

五、将文本数据表示为词袋

用于机器学习的文本表示有一种最简单的方法,也是最有效且最常用的方法,就是使用词袋 (bag-of-words)表示。使用这种表示方式时,我们舍弃了输入文本中的大部分结构,如章节、段落、句子和格式,只计算语料库中每个单词在每个文本中的出现频次 。舍弃结构并仅计算单词出现次数,这会让脑海中出现将文本表示为“袋”的画面。

对于文档语料库,计算词袋表示包括以下三个步骤。

(1) 分词 (tokenization)。将每个文档划分为出现在其中的单词 [ 称为词例(token)],比如按空格和标点划分。

(2) 构建词表 (vocabulary building)。收集一个词表,里面包含出现在任意文档中的所有词,并对它们进行编号(比如按字母顺序排序)。

(3) 编码 (encoding)。对于每个文档,计算词表中每个单词在该文档中的出现频次。

在步骤 1 和步骤 2 中涉及一些细微之处,我们将在本章后面进一步深入讨论。目前,我们来看一下如何利用 scikit-learn 来应用词袋处理过程。图 7-1 展示了对字符串 "This is how you get ants." 的处理过程。其输出是包含每个文档中单词计数的一个向量。对于词表中的每个单词,我们都有它在每个文档中的出现次数。也就是说,整个数据集中的每个唯一单词都对应于这种数值表示的一个特征。请注意,原始字符串中的单词顺序与词袋特征表示完全无关。

图 7-1:词袋处理过程

词袋表示是在 CountVectorizer 中实现的,它是一个变换器(transformer)。我们首先将它应用于一个包含两个样本的玩具数据集,来看一下它的工作原理:

bards_words =["The fool doth think he is wise,",
              "but the wise man knows himself to be a fool"]

我们导入 CountVectorizer 并将其实例化,然后对玩具数据进行拟合,如下所示:

from sklearn.feature_extraction.text import CountVectorizer
vect = CountVectorizer()
vect.fit(bards_words)

拟合 CountVectorizer 包括训练数据的分词与词表的构建,我们可以通过 vocabulary_ 属性来访问词表:

print("Vocabulary size: {}".format(len(vect.vocabulary_)))
print("Vocabulary content:\n {}".format(vect.vocabulary_))
Vocabulary size: 13
Vocabulary content:
 {'the': 9, 'fool': 3, 'doth': 2, 'think': 10, 'he': 4, 'is': 6, 'wise': 12, 'but': 1, 'man': 8, 'knows': 7, 'himself': 5, 'to': 11, 'be': 0}

词表共包含 13 个词,从 "be" 到 "wise"。

我们可以调用 transform 方法来创建训练数据的词袋表示:

bag_of_words = vect.transform(bards_words)
print("bag_of_words: {}".format(repr(bag_of_words)))
bag_of_words: <2x13 sparse matrix of type '<class 'numpy.int64'>'
	with 16 stored elements in Compressed Sparse Row format>

词袋表示保存在一个 SciPy 稀疏矩阵中,这种数据格式只保存非零元素)。这个矩阵的形状为 2×13,每行对应于两个数据点之一,每个特征对应于词表中的一个单词。这里使用稀疏矩阵,是因为大多数文档都只包含词表中的一小部分单词,也就是说,特征数组中的大部分元素都为 0。想想看,与所有英语单词(这是词表的建模对象)相比,一篇电影评论中可能出现多少个不同的单词。保存所有 0 的代价很高,也浪费内存。要想查看稀疏矩阵的实际内容,可以使用 toarray 方法将其转换为“密集的”NumPy 数组(保存所有 0 元素)(这么做之所以是可行的,是因为我们使用的是仅包含 13 个单词的小型玩具数据集。对于任何真实数据集来说,这将会导致 MemoryError (内存错误)):

print("Dense representation of bag_of_words:\n{}".format(
    bag_of_words.toarray()))
Dense representation of bag_of_words:
[[0 0 1 1 1 0 1 0 0 1 1 0 1]
 [1 1 0 1 0 1 0 1 1 1 0 1 1]]

我们可以看到,每个单词的计数都是 0 或 1。bards_words 中的两个字符串都没有包含相同的单词。我们来看一下如何阅读这些特征向量。第一个字符串("The fool doth think he is wise," )被表示为第一行,对于词表中的第一个单词 "be" ,出现 0 次。对于词表中的第二个单词 "but" ,出现 0 次。对于词表中的第三个单词 "doth" ,出现 1 次,以此类推。通过观察这两行可以看出,第 4 个单词 "fool" 、第 10 个单词 "the" 与第 13 个单词 "wise" 同时出现在两个字符串中。

上一节我们详细介绍了词袋处理过程,下面我们将其应用于电影评论情感分析的任务。前面我们将 IMDb 评论的训练数据和测试数据加载为字符串列表(text_train 和 text_test ),现在我们将处理它们:

vect = CountVectorizer().fit(text_train)
X_train = vect.transform(text_train)
print("X_train:\n{}".format(repr(X_train)))

X_train:

<25000x74849 sparse matrix of type '<class 'numpy.int64'>'
	with 3431196 stored elements in Compressed Sparse Row format>

X_train 是训练数据的词袋表示,其形状为 25 000×74 849,这表示词表中包含 74 849 个元素。数据同样被保存为 SciPy 稀疏矩阵。我们来更详细地看一下这个词表。访问词表的另一种方法是使用向量器(vectorizer)的 get_feature_name 方法,它将返回一个列表,每个元素对应于一个特征:

feature_names = vect.get_feature_names_out()
print("Number of features: {}".format(len(feature_names)))
print("First 20 features:\n{}".format(feature_names[:20]))
print("Features 20010 to 20030:\n{}".format(feature_names[20010:20030]))
print("Every 2000th feature:\n{}".format(feature_names[::2000]))
Number of features: 74849
First 20 features:
['00' '000' '0000000000001' '00001' '00015' '000s' '001' '003830' '006'
 '007' '0079' '0080' '0083' '0093638' '00am' '00pm' '00s' '01' '01pm' '02']
Features 20010 to 20030:
['dratted' 'draub' 'draught' 'draughts' 'draughtswoman' 'draw' 'drawback'
 'drawbacks' 'drawer' 'drawers' 'drawing' 'drawings' 'drawl' 'drawled'
 'drawling' 'drawn' 'draws' 'draza' 'dre' 'drea']
Every 2000th feature:
['00' 'aesir' 'aquarian' 'barking' 'blustering' 'bête' 'chicanery'
 'condensing' 'cunning' 'detox' 'draper' 'enshrined' 'favorit' 'freezer'
 'goldman' 'hasan' 'huitieme' 'intelligible' 'kantrowitz' 'lawful' 'maars'
 'megalunged' 'mostey' 'norrland' 'padilla' 'pincher' 'promisingly'
 'receptionist' 'rivals' 'schnaas' 'shunning' 'sparse' 'subset'
 'temptations' 'treatises' 'unproven' 'walkman' 'xylophonist']

如你所见,词表的前 10 个元素都是数字,这可能有些出人意料。所有这些数字都出现在评论中的某处,因此被提取为单词。大部分数字都没有一目了然的语义,除了 "007" ,在电影的特定语境中它可能指的是詹姆斯·邦德(James Bond)这个角色( 对数据的快速分析可以证实这一点。你可以自己尝试验证一下)。从无意义的“单词”中挑出有意义的有时很困难。进一步观察这个词表,我们发现许多以“dra”开头的英语单词。你可能注意到了,对于 "draught" 、"drawback" 和 "drawer" ,其单数和复数形式都包含在词表中,并且作为不同的单词。这些单词具有密切相关的语义,将它们作为不同的单词进行计数(对应于不同的特征)可能不太合适。

在尝试改进特征提取之前,我们先通过实际构建一个分类器来得到性能的量化度量。我们将训练标签保存在 y_train 中,训练数据的词袋表示保存在 X_train 中,因此我们可以在这个数据上训练一个分类器。对于这样的高维稀疏数据,类似 LogisticRegression 的线性模型通常效果最好。

我们首先使用交叉验证对 LogisticRegression 进行评估(细心的读者可能会注意到,我们这里违背了之前中关于交叉验证与预处理的内容。CountVectorizer 的默认设置实际上不会收集任何统计信息,所以我们的结果是有效的。对于应用而言,从一开始就使用 Pipeline 是更好的选择,但我们后面再这么做,这里是为了便于说明。):

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
scores = cross_val_score(LogisticRegression(), X_train, y_train, cv=5)
print("Mean cross-validation accuracy: {:.2f}".format(np.mean(scores)))
Mean cross-validation accuracy: 0.88

我们得到的交叉验证平均分数是 88%,这对于平衡的二分类任务来说是一个合理的性能。我们知道,LogisticRegression 有一个正则化参数 C ,我们可以通过交叉验证来调节它:

from sklearn.model_selection import GridSearchCV
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10]}
grid = GridSearchCV(LogisticRegression(), param_grid, cv=5)
grid.fit(X_train, y_train)

print("Best cross-validation score: {:.2f}".format(grid.best_score_))
print("Best parameters: ", grid.best_params_)
Best cross-validation score: 0.89
Best parameters:  {'C': 0.1}

我们使用 C=0.01 得到的交叉验证分数是 89%。现在,我们可以在测试集上评估这个参数设置的泛化性能:

X_test = vect.transform(text_test)
print("{:.2f}".format(grid.score(X_test, y_test)))
0.88

下面我们来看一下能否改进单词提取。CountVectorizer 使用正则表达式提取词例。默认使用的正则表达式是 "\b\w\w+\b" 。如果你不熟悉正则表达式,它的含义是找到所有包含至少两个字母或数字(\w )且被词边界(\b )分隔的字符序列。它不会匹配只有一个字母的单词,还会将类似“doesn't”或“bit.ly”之类的缩写分开,但它会将“h8ter”匹配为一个单词。然后,CountVectorizer 将所有单词转换为小写字母,这样“soon”“Soon”和“sOon”都对应于同一个词例(因此也对应于同一个特征)。这一简单机制在实践中的效果很好,但正如前面所见,我们得到了许多不包含信息量的特征(比如数字)。减少这种特征的一种方法是,仅使用至少在 2 个文档(或者至少 5 个,等等)中出现过的词例。仅在一个文档中出现的词例不太可能出现在测试集中,因此没什么用。我们可以用 min_df 参数来设置词例至少需要在多少个文档中出现过:

vect = CountVectorizer(min_df=5).fit(text_train)
X_train = vect.transform(text_train)
print("X_train with min_df: {}".format(repr(X_train)))
X_train with min_df: <25000x27271 sparse matrix of type '<class 'numpy.int64'>'
	with 3354014 stored elements in Compressed Sparse Row format>

通过要求每个词例至少在 5 个文档中出现过,我们可以将特征数量减少到 27 271 个,正如上面的输出所示——只有原始特征的三分之一左右。我们再来查看一些词例:

feature_names = vect.get_feature_names_out()

print("First 50 features:\n{}".format(feature_names[:50]))
print("Features 20010 to 20030:\n{}".format(feature_names[20010:20030]))
print("Every 700th feature:\n{}".format(feature_names[::700]))
First 50 features:
['00' '000' '007' '00s' '01' '02' '03' '04' '05' '06' '07' '08' '09' '10'
 '100' '1000' '100th' '101' '102' '103' '104' '105' '107' '108' '10s'
 '10th' '11' '110' '112' '116' '117' '11th' '12' '120' '12th' '13' '135'
 '13th' '14' '140' '14th' '15' '150' '15th' '16' '160' '1600' '16mm' '16s'
 '16th']
Features 20010 to 20030:
['repentance' 'repercussions' 'repertoire' 'repetition' 'repetitions'
 'repetitious' 'repetitive' 'rephrase' 'replace' 'replaced' 'replacement'
 'replaces' 'replacing' 'replay' 'replayable' 'replayed' 'replaying'
 'replays' 'replete' 'replica']
Every 700th feature:
['00' 'affections' 'appropriately' 'barbra' 'blurbs' 'butchered' 'cheese'
 'commitment' 'courts' 'deconstructed' 'disgraceful' 'dvds' 'eschews'
 'fell' 'freezer' 'goriest' 'hauser' 'hungary' 'insinuate' 'juggle'
 'leering' 'maelstrom' 'messiah' 'music' 'occasional' 'parking'
 'pleasantville' 'pronunciation' 'recipient' 'reviews' 'sas' 'shea'
 'sneers' 'steiger' 'swastika' 'thrusting' 'tvs' 'vampyre' 'westerns']

数字的个数明显变少了,有些生僻词或拼写错误似乎也都消失了。我们再次运行网格搜索来看一下模型的性能如何:

grid = GridSearchCV(LogisticRegression(), param_grid, cv=5)
grid.fit(X_train, y_train)
print("Best cross-validation score: {:.2f}".format(grid.best_score_))
Best cross-validation score: 0.89

网格搜索的最佳验证精度还是 89%,这和前面一样。我们并没有改进模型,但减少要处理的特征数量可以加速处理过程,舍弃无用的特征也可能提高模型的可解释性。

如果一个文档中包含训练数据中没有包含的单词,并对其调用  CountVectorizer  的  transform  方法,那么这些单词将被忽略,因为它们没有包含在字典中。这对分类来说不是一个问题,因为从不在训练数据中的单词中学不到任何内容。但对于某些应用而言(比如垃圾邮件检测),添加一个特征来表示特定文档中有多少个所谓“词表外”单词可能会有所帮助。为了实现这一点,你需要设置 min_df ,否则这个特征在训练期间永远不会被用到。

附录:

一、参考文献

参考文献:[德] Andreas C. Müller [美] Sarah Guido 《Python Machine Learning Basics Tutorial》

二、网站的电影评论数据集数据下载界面

下载地址:Sentiment Analysis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/666997.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java中的软引用,你了解吗?

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

关系数据库:关系运算

文章目录 关系运算并&#xff08;Union&#xff09;差&#xff08;Difference&#xff09;交&#xff08;Intersection&#xff09;笛卡尔积&#xff08;Extended Cartesian Product&#xff09;投影&#xff08;projection&#xff09;选择&#xff08;Selection&#xff09;除…

翻译《The Old New Thing》- What a drag: Dragging a virtual file (IStream edition)

What a drag: Dragging a virtual file (IStream edition) - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20080319-00/?p23073 Raymond Chen 2008年03月19日 拖拽虚拟文件&#xff08;IStream 版本&#xff09; 上一次&#xff0c;我们看…

Scikit-Learn 基础教程

目录 &#x1f40b;Scikit-Learn 基础教程 &#x1f40b;Scikit-Learn 简介 &#x1f40b; 数据预处理 &#x1f988;数据集导入 &#x1f988;数据清洗 &#x1f988;特征选择 &#x1f988;特征标准化 &#x1f40b; 模型选择 &#x1f988;分类模型 &#x1f988;回…

【 0 基础 Docker 极速入门】镜像、容器、常用命令总结

Docker Images&#xff08;镜像&#xff09;生命周期 Docker 是一个用于创建、部署和运行应用容器的平台。为了更好地理解 Docker 的生命周期&#xff0c;以下是相关概念的介绍&#xff0c;并说明它们如何相互关联&#xff1a; Docker&#xff1a; Docker 是一个开源平台&#…

HTML旋转照片盒子

效果图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible" content…

docker私有镜像仓库的搭建及认证

简介&#xff1a; docker私有镜像仓库的搭建及认证 前言 在生产上使用的 Docker 镜像可能包含我们的代码、配置信息等&#xff0c;不想被外部人员获取&#xff0c;只允许内 网的开发人员下载。 Docker 官方提供了一个叫做 registry 的镜像用于搭建本地私有仓库使用。在内部网…

C 基础 - 预处理命令和基本语法详解

#include <stdio.h> //预处理指令int main() //函数 {printf("Hello, World!"); //输出语句return 0; //返回语句 } 目录 一.预处理指令 1.#define #ifdef #ifndef #if #else #elif #endif 2.#inlcude a.新增一个文件 b.#include c.运行结果 d.扩…

Liunx中使用他人身份来执行命令或新建文件

前言 在一些情况下。我们想要借助某个用户的身份来执行命令或者新建文件&#xff0c; 比如某个用户的bash是 nologin 或者 false。 该怎么做呢&#xff1f;&#xff1f; 答&#xff1a;使用 sudo -u 即可。 例如&#xff1a; sudo -u ygz1 touch temp1.txt哈哈哈&#xff0…

【FPGA】Verilog语言从零到精通

接触fpga一段时间&#xff0c;也能写点跑点吧……试试系统地康康呢~这个需要耐心但是回报巨大的工作。正原子&&小梅哥 15_语法篇&#xff1a;Verilog高级知识点_哔哩哔哩_bilibili 1Verilog基础 Verilog程序框架&#xff1a;模块的结构 类比&#xff1a;c语言的基础…

javascript DOM 属性详解:读取、修改、移除

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 一、读取…

Tesseract-OCR使用 jTessBoxEditor 进行训练及python调用

Python-tesseract 是 python 的光学字符识别 &#xff08;OCR&#xff09; 工具。 也就是说&#xff0c;它将识别并“读取”嵌入在图像中的文本。 1、下载安装 jTessBoxEditor和tesseract-ocr 我下载的是jTessBoxEditor-2.2.0版本的&#xff0c;里面自带tesseract-ocr。 两种…

哪款桌面便签软件安全好用?2024好用便签app推荐

桌面便签软件已经成为许多人日常生活和工作中不可或缺的工具&#xff0c;它们实用、灵活&#xff0c;能够帮助我们快速记录重要信息&#xff0c;提醒任务事项。随着科技的进步&#xff0c;市面上的便签软件层出不穷&#xff0c;功能也越发强大和实用。在众多的便签软件中&#…

Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译

文章目录 Tcp协议Tcp协议常见API接口1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. int listen(int socket, int backlog);4. int accept(int socket, struct socka…

[.NET开发者的福音]一个方便易用的在线.NET代码编辑工具.NET Fiddle

前言 今天给大家分享一个方便易用的.NET在线代码编辑工具&#xff0c;能够帮助.NET开发人员快速完成代码编写、测试和分享的需求&#xff08;.NET开发者的福音&#xff09;&#xff1a;.NET Fiddle。 .NET Fiddle介绍 我们可以不用再担心环境与庞大的IDE安装的问题&#xff0…

python实现——分类类型数据挖掘任务(图形识别分类任务)

分类类型数据挖掘任务 基于卷积神经网络&#xff08;CNN&#xff09;的岩石图像分类。有一岩石图片数据集&#xff0c;共300张岩石图片&#xff0c;图片尺寸224x224。岩石种类有砾岩&#xff08;Conglomerate&#xff09;、安山岩&#xff08;Andesite&#xff09;、花岗岩&am…

github有趣项目:自制“我的世界” project make

videocodehttps://www.youtube.com/watch?v4O0_-1NaWnY,https://www.bilibili.com/video/BV1oj411p7qM/?https://github.com/jdah/minecraft-weekend MAKE git clone --recurse-submodules https://github.com/jdah/minecraft-weekend.git 正克隆到 minecraft-weekend... …

【笔记】关于brew install ffmpeg出现问题解决

Macos系统需要安装ffmpeg使用&#xff0c;通过brew install ffmpeg安装相关依赖时&#xff0c;当安装至flac时出现下列问题 环境&#xff1a;有代理开启 使用国内数据源 brew install ffmpeg --verbose --debug 安装过程中显示日志 curl: (35) error:1400442E:SSL routines:C…

前端3剑客(第1篇)-初识HTML

100编程书屋_孔夫子旧书网 当今主流的技术中&#xff0c;可以分为前端和后端两个门类。 前端&#xff1a;简单的理解就是和用户打交道 后端&#xff1a;主要用于组织数据 而前端就Web开发方向来说&#xff0c; 分为三门语言&#xff0c; HTML、CSS、JavaScript 语言作用HT…

Apache Pulsar 中文社区有奖问卷调查(2024 上半年度)

Apache Pulsar 中文社区有奖问卷调查&#xff08;2024 上半年度&#xff09; &#x1f4e3; &#x1f4e3; &#x1f4e3; Hi&#xff0c;Apache Pulsar 社区的小伙伴们&#xff0c;社区 2024 上半年度的有奖问卷调查来啦&#xff01; &#x1f64c; 本次调查旨在了解用户使用 …