Python 机器学习 基础 之 处理文本数据 【停用词/用tf-idf缩放数据/模型系数/多个单词的词袋/高级分词/主题建模/文档聚类】的简单说明

Python 机器学习 基础 之 处理文本数据 【停用词/用tf-idf缩放数据/模型系数/多个单词的词袋/高级分词/主题建模/文档聚类】的简单说明

目录

Python 机器学习 基础 之 处理文本数据 【停用词/用tf-idf缩放数据/模型系数/多个单词的词袋/高级分词/主题建模/文档聚类】的简单说明

一、简单介绍

二、停用词

三、用tf-idf缩放数据

四、研究模型系数

五、多个单词的词袋(n 元分词)

六、高级分词、词干提取与词形还原

七、主题建模与文档聚类

1、隐含狄利克雷分布

附录:

一、参考文献

二、spacy 环境配置


一、简单介绍

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

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

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

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

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

二、停用词

删除没有信息量的单词还有另一种方法,就是舍弃那些出现次数太多以至于没有信息量的单词。有两种主要方法:使用特定语言的停用词(stopword)列表,或者舍弃那些出现过于频繁的单词。scikit-learn 的 feature_extraction.text 模块中提供了英语停用词的内置列表:

from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS
print("Number of stop words: {}".format(len(ENGLISH_STOP_WORDS)))
print("Every 10th stopword:\n{}".format(list(ENGLISH_STOP_WORDS)[::10]))
Number of stop words: 318
Every 10th stopword:
['up', 'upon', 'can', 'even', 'few', 'could', 'whenever', 'though', 'system', 'seem', 'how', 'always', 'whereas', 'perhaps', 'rather', 'ltd', 'will', 'became', 'thru', 'if', 're', 'last', 'yet', 'anyone', 'become', 'although', 'from', 'four', 'find', 'it', 'etc', 'two']

显然,删除上述列表中的停用词只能使特征数量减少 318 个(即上述列表的长度),但可能会提高性能。我们来试一下:

# 指定stop_words="english"将使用内置列表。
# 我们也可以扩展这个列表并传入我们自己的列表。
vect = CountVectorizer(min_df=5, stop_words="english").fit(text_train)
X_train = vect.transform(text_train)
print("X_train with stop words:\n{}".format(repr(X_train)))
X_train with stop words:
<25000x26966 sparse matrix of type '<class 'numpy.int64'>'with 2149958 stored elements in Compressed Sparse Row format>

现在数据集中的特征数量减少了 305 个(27271-26966),说明大部分停用词(但不是所有)都出现了。我们再次运行网格搜索:

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.88

使用停用词后的网格搜索性能略有下降——不至于担心,但鉴于从 27 000 多个特征中删除 305 个不太可能对性能或可解释性造成很大影响,所以使用这个列表似乎是不值得的。固定的列表主要对小型数据集很有帮助,这些数据集可能没有包含足够的信息,模型从数据本身无法判断出哪些单词是停用词。作为练习,你可以尝试另一种方法,即通过设置 CountVectorizer 的 max_df 选项来舍弃出现最频繁的单词,并查看它对特征数量和性能有什么影响。

三、用tf-idf缩放数据

另一种方法是按照我们预计的特征信息量大小来缩放特征,而不是舍弃那些认为不重要的特征。最常见的一种做法就是使用词频 - 逆向文档频率 (term frequency - inverse document frequency,tf-idf)方法。这一方法对在某个特定文档中经常出现的术语给予很高的权重,但对在语料库的许多文档中都经常出现的术语给予的权重却不高。如果一个单词在某个特定文档中经常出现,但在许多文档中却不常出现,那么这个单词很可能是对文档内容的很好描述。scikit-learn 在两个类中实现了 tf-idf 方法:TfidfTransformerTfidfVectorizer ,前者接受 CountVectorizer 生成的稀疏矩阵并将其变换,后者接受文本数据并完成词袋特征提取与 tf-idf 变换。tf-idf 缩放方案有几种变体,你可以在维基百科上阅读相关内容(https://en.wikipedia.org/wiki/Tf-idf )。单词 w 在文档 d 中的 tf-idf 分数在 TfidfTransformer 类和 TfidfVectorizer 类中都有实现,其计算公式如下所示(这里给出这个公式主要是为了完整性,你在使用 tf-idf 时无需记住它):

其中 N 是训练集中的文档数量,Nw 是训练集中出现单词 w 的文档数量,tf (词频)是单词 w 在查询文档 d (你想要变换或编码的文档)中出现的次数。两个类在计算 tf-idf 表示之后都还应用了 L2 范数。换句话说,它们将每个文档的表示缩放到欧几里得范数为 1。利用这种缩放方法,文档长度(单词数量)不会改变向量化表示。

由于 tf-idf 实际上利用了训练数据的统计学属性,所以我们将使用在之前介绍过的管道,以确保网格搜索的结果有效。这样会得到下列代码:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(TfidfVectorizer(min_df=5),LogisticRegression())
param_grid = {'logisticregression__C': [0.001, 0.01, 0.1, 1, 10]}grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(text_train, y_train)
print("Best cross-validation score: {:.2f}".format(grid.best_score_))
Best cross-validation score: 0.89

如你所见,使用 tf-idf 代替仅统计词数对性能有所提高。我们还可以查看 tf-idf 找到的最重要的单词。请记住,tf-idf 缩放的目的是找到能够区分文档的单词,但它完全是一种无监督技术。因此,这里的“重要”不一定与我们感兴趣的“正面评论”和“负面评论”标签相关。首先,我们从管道中提取 TfidfVectorizer :

vectorizer = grid.best_estimator_.named_steps["tfidfvectorizer"]
# 变换训练数据集
X_train = vectorizer.transform(text_train)
# 找到数据集中每个特征的最大值
max_value = X_train.max(axis=0).toarray().ravel()
sorted_by_tfidf = max_value.argsort()
# 获取特征名称
feature_names = np.array(vectorizer.get_feature_names_out())print("Features with lowest tfidf:\n{}".format(feature_names[sorted_by_tfidf[:20]]))print("Features with highest tfidf: \n{}".format(feature_names[sorted_by_tfidf[-20:]]))
Features with lowest tfidf:
['suplexes' 'gauche' 'hypocrites' 'oncoming' 'songwriting' 'galadriel''emerald' 'mclaughlin' 'sylvain' 'oversee' 'cataclysmic' 'pressuring''uphold' 'thieving' 'inconsiderate' 'ware' 'denim' 'reverting' 'booed''spacious']
Features with highest tfidf: 
['gadget' 'sucks' 'zatoichi' 'demons' 'lennon' 'bye' 'dev' 'weller''sasquatch' 'botched' 'xica' 'darkman' 'woo' 'casper' 'doodlebops''smallville' 'wei' 'scanners' 'steve' 'pokemon']

tf-idf 较小的特征要么是在许多文档里都很常用,要么就是很少使用,且仅出现在非常长的文档中。有趣的是,许多 tf-idf 较大的特征实际上对应的是特定的演出或电影。这些术语仅出现在这些特定演出或电影的评论中,但往往在这些评论中多次出现。例如,对于 "pokemon" 、"smallville" 和 "doodlebops" 是显而易见的,但这里的 "scanners" 实际上指的也是电影标题。这些单词不太可能有助于我们的情感分类任务(除非有些电影的评价可能普遍偏正面或偏负面),但肯定包含了关于评论的大量具体信息。

我们还可以找到逆向文档频率较低的单词,即出现次数很多,因此被认为不那么重要的单词。训练集的逆向文档频率值被保存在 idf_ 属性中:

sorted_by_idf = np.argsort(vectorizer.idf_)
print("Features with lowest idf:\n{}".format(feature_names[sorted_by_idf[:100]]))
Features with lowest idf:
['the' 'and' 'of' 'to' 'this' 'is' 'it' 'in' 'that' 'but' 'for' 'with''was' 'as' 'on' 'movie' 'not' 'have' 'one' 'be' 'film' 'are' 'you' 'all''at' 'an' 'by' 'so' 'from' 'like' 'who' 'they' 'there' 'if' 'his' 'out''just' 'about' 'he' 'or' 'has' 'what' 'some' 'good' 'can' 'more' 'when''time' 'up' 'very' 'even' 'only' 'no' 'would' 'my' 'see' 'really' 'story''which' 'well' 'had' 'me' 'than' 'much' 'their' 'get' 'were' 'other''been' 'do' 'most' 'don' 'her' 'also' 'into' 'first' 'made' 'how' 'great''because' 'will' 'people' 'make' 'way' 'could' 'we' 'bad' 'after' 'any''too' 'then' 'them' 'she' 'watch' 'think' 'acting' 'movies' 'seen' 'its''him']

正如所料,这些词大多是英语中的停用词,比如 "the" 和 "no" 。但有些单词显然是电影评论特有的,比如 "movie" 、"film" 、"time" 、"story" 等。有趣的是,"good" 、"great" 和 "bad" 也属于频繁出现的单词,因此根据 tf-idf 度量也属于“不太相关”的单词,尽管我们可能认为这些单词对情感分析任务非常重要。

四、研究模型系数

最后,我们详细看一下 Logistic 回归模型从数据中实际学到的内容。由于特征数量非常多(删除出现次数不多的特征之后还有 27 271 个),所以显然我们不能同时查看所有系数。但是,我们可以查看最大的系数,并查看这些系数对应的单词。我们将使用基于 tf-idf 特征训练的最后一个模型。

下面这张条形图(图 7-2)给出了 Logistic 回归模型中最大的 25 个系数与最小的 25 个系数,其高度表示每个系数的大小:

import mglearn
import matplotlib.pyplot as pltmglearn.tools.visualize_coefficients(grid.best_estimator_.named_steps["logisticregression"].coef_,feature_names, n_top_features=40)plt.tight_layout()
plt.savefig('Images/00HandleTextData-01.png', bbox_inches='tight')
plt.show()
图 7-2:在 tf-idf 特征上训练的 Logistic 回归的最大系数和最小系数

左侧的负系数属于模型找到的表示负面评论的单词,而右侧的正系数属于模型找到的表示正面评论的单词。大多数单词都是非常直观的,比如 "worst" (最差)、"waste" (浪费)、"disappointment" (失望)和 "laughable" (可笑)都表示不好的电影评论,而 "excellent" (优秀)、"wonderful" (精彩)、"enjoyable" (令人愉悦)和 "refreshing" (耳目一新)则表示正面的电影评论。有些词的含义不那么明确,比如 "bit" (一点)、"job" (工作)和 "today" (今天),但它们可能是类似 "good job" (做得不错)和“best today ”(今日最佳)等短语的一部分。

五、多个单词的词袋(n 元分词)

使用词袋表示的主要缺点之一是完全舍弃了单词顺序。因此,“it's bad, not good at all”(电影很差,一点也不好)和“it's good, not bad at all”(电影很好,还不错)这两个字符串的词袋表示完全相同,尽管它们的含义相反。将“not”(不)放在单词前面,这只是上下文很重要的一个例子(可能是一个极端的例子)。幸运的是,使用词袋表示时有一种获取上下文的方法,就是不仅考虑单一词例的计数,而且还考虑相邻的两个或三个词例的计数。

两个词例被称为二元分词 (bigram),三个词例被称为三元分词 (trigram),更一般的词例序列被称为 n 元分词 (n -gram)。我们可以通过改变 CountVectorizer 或 TfidfVectorizer 的 ngram_range 参数来改变作为特征的词例范围。ngram_range 参数是一个元组,包含要考虑的词例序列的最小长度和最大长度。下面是在之前用过的玩具数据上的一个示例:

print("bards_words:\n{}".format(bards_words))
bards_words:
['The fool doth think he is wise,', 'but the wise man knows himself to be a fool']

默认情况下,为每个长度最小为 1 且最大为 1 的词例序列(或者换句话说,刚好 1 个词例)创建一个特征——单个词例也被称为一元分词 (unigram):

cv = CountVectorizer(ngram_range=(1, 1)).fit(bards_words)
print("Vocabulary size: {}".format(len(cv.vocabulary_)))
print("Vocabulary:\n{}".format(cv.get_feature_names_out()))
Vocabulary size: 13
Vocabulary:
['be' 'but' 'doth' 'fool' 'he' 'himself' 'is' 'knows' 'man' 'the' 'think''to' 'wise']

要想仅查看二元分词(即仅查看由两个相邻词例组成的序列),可以将 ngram_range 设置为 (2, 2) :

cv = CountVectorizer(ngram_range=(2, 2)).fit(bards_words)
print("Vocabulary size: {}".format(len(cv.vocabulary_)))
print("Vocabulary:\n{}".format(cv.get_feature_names_out()))
Vocabulary size: 14
Vocabulary:
['be fool' 'but the' 'doth think' 'fool doth' 'he is' 'himself to''is wise' 'knows himself' 'man knows' 'the fool' 'the wise' 'think he''to be' 'wise man']

使用更长的词例序列通常会得到更多的特征,也会得到更具体的特征。bard_words 的两个短语中没有相同的二元分词:

print("Transformed data (dense):\n{}".format(cv.transform(bards_words).toarray()))
Transformed data (dense):
[[0 0 1 1 1 0 1 0 0 1 0 1 0 0][1 1 0 0 0 1 0 1 1 0 1 0 1 1]]

对于大多数应用而言,最小的词例数量应该是 1,因为单个单词通常包含丰富的含义。在大多数情况下,添加二元分词会有所帮助。添加更长的序列(一直到五元分词)也可能有所帮助,但这会导致特征数量的大大增加,也可能会导致过拟合,因为其中包含许多非常具体的特征。原则上来说,二元分词的数量是一元分词数量的平方,三元分词的数量是一元分词数量的三次方,从而导致非常大的特征空间。在实践中,更高的 n 元分词在数据中的出现次数实际上更少,原因在于(英语)语言的结构,不过这个数字仍然很大。

下面是在 bards_words 上使用一元分词、二元分词和三元分词的结果:

cv = CountVectorizer(ngram_range=(1, 3)).fit(bards_words)print("Vocabulary size: {}".format(len(cv.vocabulary_)))
print("Vocabulary:\n{}".format(cv.get_feature_names_out()))
Vocabulary size: 39
Vocabulary:
['be' 'be fool' 'but' 'but the' 'but the wise' 'doth' 'doth think''doth think he' 'fool' 'fool doth' 'fool doth think' 'he' 'he is''he is wise' 'himself' 'himself to' 'himself to be' 'is' 'is wise''knows' 'knows himself' 'knows himself to' 'man' 'man knows''man knows himself' 'the' 'the fool' 'the fool doth' 'the wise''the wise man' 'think' 'think he' 'think he is' 'to' 'to be' 'to be fool''wise' 'wise man' 'wise man knows']

我们在 IMDb 电影评论数据上尝试使用 TfidfVectorizer ,并利用网格搜索找出 n 元分词的最佳设置:

pipe = make_pipeline(TfidfVectorizer(min_df=5), LogisticRegression())
# 运行网格搜索需要很长时间,因为网格相对较大,且包含三元分词
param_grid = {"logisticregression__C": [0.001, 0.01, 0.1, 1, 10, 100],"tfidfvectorizer__ngram_range": [(1, 1), (1, 2), (1, 3)]}grid = GridSearchCV(pipe, param_grid, cv=5)
grid.fit(text_train, y_train)
print("Best cross-validation score: {:.2f}".format(grid.best_score_))
print("Best parameters:\n{}".format(grid.best_params_))
Best cross-validation score: 0.91
Best parameters:
{'logisticregression__C': 100, 'tfidfvectorizer__ngram_range': (1, 3)}

从结果中可以看出,我们添加了二元分词特征与三元分词特征之后,性能提高了一个百分点多一点。我们可以将交叉验证精度作为 ngram_range 和 C 参数的函数并用热图可视化,正如我们在之前所做的那样(见图 7-3):

def drawHeatmap(scores, xlabel,ylabel='True label', fmt='{:0.2f}', colorbar=None):# 反转scores数组的行顺序,以便(0, 0)在左下角  scores = scores[::-1, :]  # 绘制热图  fig, ax = plt.subplots()  if(colorbar is None):colorbar = scorescax = ax.matshow(colorbar, cmap='viridis')  fig.colorbar(cax)  # 假设param_grid['gamma']和param_grid['C']已经定义  # 这里我们使用字符串列表作为示例  param_grid = {  'gamma': ['0.001','0.01', '0.1', '1', '10', '100'],  'C':   ['(1,1)','(1,2)','(1,3)']}  # 设置xticks和yticks的位置  ticks_x = np.arange(len(param_grid['gamma']))  ticks_y = np.arange(len(param_grid['C']))[::-1]  # 反转yticks的顺序以匹配反转的scores  # 设置xticklabels和yticklabels  ax.set_xticks(ticks_x)  ax.set_xticklabels(param_grid['gamma'])  ax.xaxis.set_tick_params(rotation=45)  ax.set_yticks(ticks_y)  ax.set_yticklabels(param_grid['C'])  # 设置x轴和y轴的标签  ax.set_xlabel(xlabel)  ax.set_ylabel(ylabel)  # 添加数值到每个单元格  for (i, j), z in np.ndenumerate(scores):  ax.text(j, i, fmt.format(z), ha='center', va='center')  # 从网格搜索中提取分数
scores = grid.cv_results_['mean_test_score'].reshape(-1, 3).T
# 热图可视化
# heatmap = mglearn.tools.heatmap(
#    scores, xlabel="C", ylabel="ngram_range", cmap="viridis", fmt="%.3f",
#    xticklabels=param_grid['logisticregression__C'],
#    yticklabels=param_grid['tfidfvectorizer__ngram_range'])drawHeatmap(scores,xlabel="C", ylabel="ngram_range",fmt='{:0.3f}')plt.tight_layout()
plt.savefig('Images/00HandleTextData-02.png', bbox_inches='tight')
plt.show()
图 7-3:交叉验证平均精度作为参数 ngram_range 和 C 的函数的热图可视化

从热图中可以看出,使用二元分词对性能有很大提高,而添加三元分词对精度只有很小贡献。为了更好地理解模型是如何改进的,我们可以将最佳模型的重要系数可视化,其中包含一元分词、二元分词和三元分词(见图 7-4):

# 提取特征名称与系数
vect = grid.best_estimator_.named_steps['tfidfvectorizer']
feature_names = np.array(vect.get_feature_names_out())
coef = grid.best_estimator_.named_steps['logisticregression'].coef_
mglearn.tools.visualize_coefficients(coef, feature_names, n_top_features=40)plt.tight_layout()
plt.savefig('Images/00HandleTextData-03.png', bbox_inches='tight')
plt.show()
图 7-4:同时使用 tf-idf 缩放与一元分词、二元分词和三元分词时的最重要特征

有几个特别有趣的特征,它们包含单词 "worth" (值得),而这个词本身并没有出现在一元分词模型中:"not worth" (不值得)表示负面评论,而 "definitely worth" (绝对值得)和 "well worth" (很值得)表示正面评论。这是上下文影响 "worth" 一词含义的主要示例。

接下来,我们只将三元分词可视化,以进一步深入了解这些特征有用的原因。许多有用的二元分词和三元分词都由常见的单词组成,这些单词本身可能没有什么信息量,比如 "none of the" (没有一个)、"the only good" (唯一好的)、"on and on" (不停地)、"this is one" (这是一部)、"of the most" (最)等短语中的单词。但是,与一元分词特征的重要性相比,这些特征的影响非常有限,正如图 7-5 所示。

# 找到三元分词特征
mask = np.array([len(feature.split(" ")) for feature in feature_names]) == 3
# 仅将三元分词特征可视化
mglearn.tools.visualize_coefficients(coef.ravel()[mask],feature_names[mask], n_top_features=40)plt.tight_layout()
plt.savefig('Images/00HandleTextData-04.png', bbox_inches='tight')
plt.show()
图 7-5:仅将对模型重要的三元分词特征可视化

六、高级分词、词干提取与词形还原

如前所述,CountVectorizerTfidfVectorizer 中的特征提取相对简单,还有更为复杂的方法。在更加复杂的文本处理应用中,通常需要改进的步骤是词袋模型的第一步:分词(tokenization)。这一步骤为特征提取定义了一个单词是如何构成的。

我们前面看到,词表中通常同时包含某些单词的单数形式和复数形式,比如 "drawback""drawbacks""drawer""drawers""drawing""drawings" 。对于词袋模型而言,"drawback""drawbacks" 的语义非常接近,区分二者只会增加过拟合,并导致模型无法充分利用训练数据。同样我们还发现,词表中包含像 "replace""replaced""replace ment""replaces""replacing" 这样的单词,它们都是动词“to replace”的不同动词形式或相关名词。与名词的单复数形式一样,将不同的动词形式及相关单词视为不同的词例,这不利于构建具有良好泛化性能的模型。

这个问题可以通过用词干 (word stem)表示每个单词来解决,这一方法涉及找出 [ 或合并 (conflate)] 所有具有相同词干的单词。如果使用基于规则的启发法来实现(比如删除常见的后缀),那么通常将其称为词干提取 (stemming)。如果使用的是由已知单词形式组成的字典(明确的且经过人工验证的系统),并且考虑了单词在句子中的作用,那么这个过程被称为词形还原 (lemmatization),单词的标准化形式被称为词元 (lemma)。词干提取和词形还原这两种处理方法都是标准化 (normalization)的形式之一,标准化是指尝试提取一个单词的某种标准形式。标准化的另一个有趣的例子是拼写校正,这种方法在实践中很有用,但超出了本书的范围。

为了更好地理解标准化,我们来对比一种词干提取方法(Porter 词干提取器,一种广泛使用的启发法集合,从 nltk 包导入)与 spacy 包 (安装 spacy 包之后需要下载相应的语言包,你可以在命令行输入 python3 -m spacy download en 来下载英语语言包) 中实现的词形还原(想了解接口的细节,请参阅 nltk (NLTK :: Natural Language Toolkit )和 spacy (spaCy · Industrial-strength Natural Language Processing in Python )的文档。我们这里更关注一般性原则):

import spacy
import nltk# 加载spacy的英语模型
en_nlp = spacy.load('en_core_web_sm')
# 将nltk的Porter词干提取器实例化
stemmer = nltk.stem.PorterStemmer()# 定义一个函数来对比spacy中的词形还原与nltk中的词干提取
def compare_normalization(doc):# 在spacy中对文档进行分词doc_spacy = en_nlp(doc)# 打印出spacy找到的词元print("Lemmatization:")print([token.lemma_ for token in doc_spacy])# 打印出Porter词干提取器找到的词例print("Stemming:")print([stemmer.stem(token.norm_.lower()) for token in doc_spacy])

我们将用一个句子来比较词形还原与 Porter 词干提取器,以显示二者的一些区别(1.7.5 版的 spacy 将 'our' 、'i' 等代词全部还原为 '-PRON-' ,详情请参见 spacy 官方文档):

compare_normalization(u"Our meeting today was worse than yesterday, ""I'm scared of meeting the clients tomorrow.")
Lemmatization:
['our', 'meeting', 'today', 'be', 'bad', 'than', 'yesterday', ',', 'I', 'be', 'scared', 'of', 'meet', 'the', 'client', 'tomorrow', '.']
Stemming:
['our', 'meet', 'today', 'wa', 'wors', 'than', 'yesterday', ',', 'i', 'am', 'scare', 'of', 'meet', 'the', 'client', 'tomorrow', '.']

词干提取总是局限于将单词简化成词干,因此 "was" 变成了 "wa" ,而词形还原可以得到正确的动词基本词形 "be" 。同样,词形还原可以将 "worse" 标准化为 "bad" ,而词干提取得到的是 "wors" 。另一个主要区别在于,词干提取将两处 "meeting" 都简化为 "meet" 。利用词形还原,第一处 "meeting" 被认为是名词,所以没有变化,而第二处 "meeting" 被认为是动词,所以变为 "meet" 。一般来说,词形还原是一个比词干提取更复杂的过程,但用于机器学习的词例标准化时通常可以给出比词干提取更好的结果。

虽然 scikit-learn 没有实现这两种形式的标准化,但 CountVectorizer 允许使用 tokenizer 参数来指定使用你自己的分词器将每个文档转换为词例列表。我们可以使用 spacy 的词形还原了创建一个可调用对象,它接受一个字符串并生成一个词元列表:

# 技术细节:我们希望使用由CountVectorizer所使用的基于正则表达式的分词器,
# 并仅使用spacy的词形还原。
# 为此,我们将en_nlp.tokenizer(spacy分词器)替换为基于正则表达式的分词。
# 引入 CountVectorizer
from sklearn.feature_extraction.text import CountVectorizer
import re
# 在CountVectorizer中使用的正则表达式
regexp = re.compile('(?u)\\b\\w\\w+\\b')# 加载spacy语言模型,并保存旧的分词器
en_nlp = spacy.load('en_core_web_sm')
old_tokenizer = en_nlp.tokenizer
# 将分词器替换为前面的正则表达式
en_nlp.tokenizer = lambda string: old_tokenizer.tokens_from_list(regexp.findall(string))# 用spacy文档处理管道创建一个自定义分词器
# (现在使用我们自己的分词器)
def custom_tokenizer(document):doc_spacy = en_nlp(document, entity=False, parse=False)return [token.lemma_ for token in doc_spacy]# 利用自定义分词器来定义一个计数向量器
lemma_vect = CountVectorizer(tokenizer=custom_tokenizer, min_df=5)

我们变换数据并检查词表的大小:

text_train = reviews_train.data
# 利用带词形还原的CountVectorizer对text_train进行变换
X_train_lemma = lemma_vect.fit_transform(text_train)
print("X_train_lemma.shape: {}".format(X_train_lemma.shape))# 标准的CountVectorizer,以供参考
vect = CountVectorizer(min_df=5).fit(text_train)
X_train = vect.transform(text_train)
print("X_train.shape: {}".format(X_train.shape))
X_train_lemma.shape: (25000, 91079)
X_train.shape: (25000, 27272)

从输出中可以看出,词形还原将特征数量从 27 271 个(标准的 CountVectorizer 处理过程)减少到 21 596 个。词形还原可以被看作是一种正则化,因为它合并了某些特征。因此我们预计,数据集很小时词形还原对性能的提升最大。为了说明词形还原的作用,我们将使用 StratifiedShuffleSplit 做交叉验证,仅使用 1% 的数据作为训练数据,其余数据作为测试数据:

# 仅使用1%的数据作为训练集来构建网格搜索
from sklearn.model_selection import StratifiedShuffleSplitparam_grid = {'C': [0.001, 0.01, 0.1, 1, 10]}
cv = StratifiedShuffleSplit(n_splits=5, test_size=0.99,train_size=0.01, random_state=0)
grid = GridSearchCV(LogisticRegression(), param_grid, cv=cv)
# 利用标准的CountVectorizer进行网格搜索
grid.fit(X_train, y_train)
print("Best cross-validation score ""(standard CountVectorizer): {:.3f}".format(grid.best_score_))
# 利用词形还原进行网格搜索
grid.fit(X_train_lemma, y_train)
print("Best cross-validation score ""(lemmatization): {:.3f}".format(grid.best_score_))
Best cross-validation score (standard CountVectorizer): 0.717
Best cross-validation score (lemmatization): 0.743

在这个例子中,词形还原对性能有较小的提高。与许多特征提取技术一样,其结果因数据集的不同而不同。词形还原与词干提取有时有助于构建更好的模型(或至少是更简洁的模型),所以我们建议你,在特定任务中努力提升最后一点性能时可以尝试下这些技术。

七、主题建模与文档聚类

常用于文本数据的一种特殊技术是主题建模 (topic modeling),这是描述将每个文档分配给一个或多个主题的任务(通常是无监督的)的概括性术语。这方面一个很好的例子是新闻数据,它们可以被分为“政治”“体育”“金融”等主题。如果为每个文档分配一个主题,那么这是一个文档聚类任务。如果每个文档可以有多个主题,那么这个任务与之前的分解方法有关。我们学到的每个成分对应于一个主题,文档表示中的成分系数告诉们这个文档与该主题的相关性强弱。通常来说,人们在谈论主题建模时,他们指的是一种叫作隐含狄利克雷分布 (Latent Dirichlet Allocation,LDA)的特定分解方法。

1、隐含狄利克雷分布

从直观上来看,LDA 模型试图找出频繁共同出现的单词群组(即主题)。LDA 还要求,每个文档可以被理解为主题子集的“混合”。重要的是要理解,机器学习模型所谓的“主题”可能不是我们通常在日常对话中所说的主题,而是更类似于 PCA 或 NMF 所提取的成分,它可能具有语义,也可能没有。即使 LDA“主题”具有语义,它可能也不是我们通常所说的主题。回到新闻文章的例子,我们可能有许多关于体育、政治和金融的文章,由两位作者所写。在一篇政治文章中,我们预计可能会看到“州长”“投票”“党派”等词语,而在一篇体育文章中,我们预计可能会看到类似“队伍”“得分”和“赛季”之类的词语。这两组词语可能会同时出现,而例如“队伍”和“州长”就不太可能同时出现。但是,这并不是我们预计可能同时出现的唯一的单词群组。这两位记者可能偏爱不同的短语或者选择不同的单词。可能其中一人喜欢使用“划界”(demarcate)这个词,而另一人喜欢使用“两极分化”(polarize)这个词。其他“主题”可能是“记者 A 常用的词语”和“记者 B 常用的词语”,虽然这并不是通常意义上的主题。

我们将 LDA 应用于电影评论数据集,来看一下它在实践中的效果。对于无监督的文本文档模型,通常最好删除非常常见的单词,否则它们可能会支配分析过程。我们将删除至少在 15% 的文档中出现过的单词,并在删除前 15% 之后,将词袋模型限定为最常见的 10 000 个单词(还有另一种机器学习模型通常也简称为 LDA,那就是线性判别分析(Linear Discriminant Analysis),一种线性分类模型。这造成了很多混乱。在本书中,LDA 是指隐含狄利克雷分布。):


vect = CountVectorizer(max_features=10000, max_df=.15)
X = vect.fit_transform(text_train)

我们将学习一个包含 10 个主题的主题模型,它包含的主题个数很少,我们可以查看所有主题。与 NMF 中的分量类似,主题没有内在的顺序,而改变主题数量将会改变所有主题(事实上,NMF 和 LDA 解决的是非常相关的问题,我们也可以用 NMF 来提取主题)。 我们将使用 "batch" 学习方法,它比默认方法("online" )稍慢,但通常会给出更好的结果。我们还将增大 max_iter ,这样会得到更好的模型:

from sklearn.decomposition import LatentDirichletAllocation
# 创建 LDA 模型实例
lda = LatentDirichletAllocation(n_components=10, learning_method="batch",max_iter=25, random_state=0)
# 我们在一个步骤中构建模型并变换数据
# 计算变换需要花点时间,二者同时进行可以节省时间
document_topics = lda.fit_transform(X)

与之前中所讲的分解方法类似,LatentDirichletAllocation 有一个 components_ 属性,其中保存了每个单词对每个主题的重要性。components_ 的大小为 (n_topics, n_words) :


lda.components_.shape
(10, 10000)

为了更好地理解不同主题的含义,我们将查看每个主题中最重要的单词。print_topics 函数为这些特征提供了良好的格式:

# 对于每个主题(components_的一行),将特征排序(升序)
# 用[:, ::-1]将行反转,使排序变为降序
sorting = np.argsort(lda.components_, axis=1)[:, ::-1]
# 从向量器中获取特征名称
feature_names = np.array(vect.get_feature_names_out())# 打印出前10个主题:
mglearn.tools.print_topics(topics=range(10), feature_names=feature_names,sorting=sorting, topics_per_chunk=5, n_words=10)
topic 0       topic 1       topic 2       topic 3       topic 4       
--------      --------      --------      --------      --------      
director      show          book          family        funny         
work          series        original      young         comedy        
performance   war           10            father        cast          
actors        episode       now           us            role          
cast          tv            again         woman         humor         
screen        years         world         own           fun           
performances  american      saw           world         jokes         
role          episodes      read          real          actors        
both          world         didn          mother        performance   
quite         shows         am            between       always        topic 5       topic 6       topic 7       topic 8       topic 9       
--------      --------      --------      --------      --------      
horror        music         original      thing         action        
gore          john          team          worst         police        
effects       old           series        didn          murder        
blood         young         jack          nothing       killer        
pretty        girl          action        minutes       crime         
budget        song          new           guy           plays         
house         gets          down          actually      lee           
zombie        dance         tarzan        want          gets          
dead          songs         freddy        going         role          
low           rock          indian        re            cop   

从重要的单词来看,主题 1 似乎是关于历史和战争的电影,主题 2 可能是关于糟糕的喜剧,主题 3 可能是关于电视连续剧,主题 4 可能提取了一些非常常见的单词,而主题 6 似乎是关于儿童电影,主题 8 似乎提取了与获奖相关的评论。仅使用 10 个主题,每个主题都需要非常宽泛,才能共同涵盖我们的数据集中所有不同类型的评论。

接下来,我们将学习另一个模型,这次包含 100 个主题。使用更多的主题,将使得分析过程更加困难,但更可能使主题专门针对于某个有趣的数据子集:

lda100 = LatentDirichletAllocation(n_components=100, learning_method="batch",max_iter=25, random_state=0)
document_topics100 = lda100.fit_transform(X)

查看所有 100 个主题可能有点困难,所以我们选取了一些有趣的而且有代表性的主题:

topics = np.array([7, 16, 24, 25, 28, 36, 37, 45, 51, 53, 54, 63, 89, 97])sorting = np.argsort(lda100.components_, axis=1)[:, ::-1]
feature_names = np.array(vect.get_feature_names_out())
mglearn.tools.print_topics(topics=topics, feature_names=feature_names,sorting=sorting, topics_per_chunk=7, n_words=20)
topic 7       topic 16      topic 24      topic 25      topic 28      topic 36      topic 37      
--------      --------      --------      --------      --------      --------      --------      
drew          didn          ben           emma          years         role          ship          
baseball      going         lines         elvira        saw           oscar         titanic       
maria         seemed        actors        jeremy        again         award         crew          
sports        things        director      hudson        remember      actor         day           
whale         doesn         audience      paltrow       ago           picture       world         
ben           interesting   every         sirk          now           won           air           
red           nothing       worst         austen        watched       roles         sea           
angels        bit           without       bacall        old           supporting    lost          
barrymore     lot           simply        mr            am            academy       plane         
pitch         felt          dialogue      kyle          since         nominated     macarthur     
fever         thing         parody        malone        before        performance   events        
frankie       seems         us            thompson      last          grant         real          
sox           ending        script        stack         didn          winning       death         
team          might         self          dorothy       few           cast          war           
irish         work          less          preston       came          actors        earth         
wendigo       feel          care          wind          year          year          captain       
deaf          though        attempt       robert        day           years         disaster      
casper        actually      mind          written       thought       century       james         
deer          thought       shallow       jane          found         three         water         
gypo          quite         imagine       toni          find          comedy        london        topic 45      topic 51      topic 53      topic 54      topic 63      topic 89      topic 97      
--------      --------      --------      --------      --------      --------      --------      
documentary   world         moon          show          drugs         jack          our           
footage       green         mike          shows         drug          king          us            
festival      new           columbo       tv            freeman       hotel         human         
interviews    bus           cat           television    money         stephen       world         
documentaries heston        hat           episode       disturbing    kubrick       own           
media         streets       mel           season        real          shining       reality       
interesting   panic         mst3k         episodes      experiment    nicholson     every         
stooges       city          brooks        always        ll            danny         real          
subject       orleans       cassidy       air           morgan        stanley       mind          
history       health        austin        funny         abuse         wendy         need          
chavez        palance       hyde          program       rat           wang          understand    
wrestling     plague        baldwin       reality       rats          zombi         feel          
scorsese      3d            skull         every         spacey        gere          want          
shorts        director      tall          lot           less          room          things        
making        macy          ho            new           10            flock         different     
verhoeven     kazan         myers         abc           justin        claire        nature        
gerard        around        cure          seasons       nothing       bruno         lives         
christine     mario         gackt         now           kevin         birds         without       
international soylent       full          sitcom        addicted      snow          soul          
narration     big           ken           real          timberlake    find          makes     

这次我们提取的主题似乎更加具体,不过很多都难以解读。主题 7 似乎是关于恐怖电影和惊悚片,主题 16 和 54 似乎是关于不好的评论,而主题 63 似乎主要是关于喜剧的正面评论。如果想要利用发现的主题做出进一步的推断,那么我们应该查看分配给这些主题的文档,以验证我们通过查看每个主题排名最靠前的单词所得到的直觉。例如,主题 45 似乎是关于音乐的。我们来查看哪些评论被分配给了这个主题:

# 按主题45“music”进行排序
music = np.argsort(document_topics100[:, 45])[::-1]
# 打印出这个主题最重要的前5个文档
for i in music[:10]:# 显示前两个句子print(b".".join(text_train[i].split(b".")[:2]) + b".\n")
b"This movie is basically a documentary of the chronologically ordered series of events that took place from April 10, 2002 through April 14, 2002 in the Venezuelan Presidential Palace, Caracas Venezuela.<br /><br />The pathos of the movie is real and one feels the pain, sorrow and joy of the people who lived through this failed coup d'etat of President Hugo Chavez.\n"
b'Reviewed at the World Premiere screening Sept. 9, 2006 at the Isabel Bader Theatre during the Toronto International Film Festival (TIFF).\n'
b'Moe and Larry are newly henpecked husbands, having married Shemp\'s demanding sisters. At his music studio, Shemp learns he will inherit a fortune if he marries someone himself! <br /><br />"Husbands Beware" is a remake of 1947\'s "Brideless Groom," widely considered by many to be one of the best Stooge films with Shemp.\n'
b'Sharp, well-made documentary focusing on Mardi Gras beads. I have always liked this approach to film-making - communicate ideas about a larger, more complex, and often inscrutable phenomenon by breaking the issue down into something familiar and close to home.\n'
b"This is a great movie, it shows what our government will to to other countries if we don't like their government. This isn't as bad as what Reagan and Bush number one did to South America, but the US still has no business messing around with other countries like this.\n"
b'Another good Stooge short!Christine McIntyre is so lovely and evil and the same time in this one!She is such a great actress!The Stooges are very good and especially Shemp and Larry!This to is a good one to watch around Autumn time!.\n'
b'"Why did they make them so big? Why didn\'t they just give the money to the poor?" The question about cathedrals was asked by a student to Mr. Harvey during a school field trip to Salisbury Cathedral.\n'
b'In Micro Phonies the stooges are at there best. In this short the trio are handymen working in a recording studio.\n'
b'This documentary has been aired on both RTE and BBC in the last number of months. Having seen it twice now I would recommend it to anyone with an interest in media and documentary film making.\n'
b'This three stooges flick is at a tie with my other favorite flick "Disorder in the Court". This is an uproar of laughter for any Three Stooges fan to enjoy.\n'

可以看出,这个主题涵盖许多以音乐为主的评论,从音乐剧到传记电影,再到最后一条评论中难以归类的类型。查看主题还有一种有趣的方法,就是通过对所有评论的 document_topics 进行求和来查看每个主题所获得的整体权重。我们用最常见的两个单词为每个主题命名。图 7-6 给出了学到的主题权重:

fig, ax = plt.subplots(1, 2, figsize=(10, 10))
topic_names = ["{:>2} ".format(i) + " ".join(words)for i, words in enumerate(feature_names[sorting[:, :2]])]
# 两列的条形图:
for col in [0, 1]:start = col * 50end = (col + 1) * 50ax[col].barh(np.arange(50), np.sum(document_topics100, axis=0)[start:end])ax[col].set_yticks(np.arange(50))ax[col].set_yticklabels(topic_names[start:end], ha="left", va="top")ax[col].invert_yaxis()ax[col].set_xlim(0, 2000)yax = ax[col].get_yaxis()yax.set_tick_params(pad=130)plt.tight_layout()
plt.savefig('Images/00HandleTextData-05.png', bbox_inches='tight')
plt.show()
图 7-6:LDA 学到的主题权重

最重要的主题是主题 97,它可能主要包含停用词,可能还有一些稍负面的单词;主题 16 明显是有关负面评论的;然后是一些特定类型的主题与主题 36 和 37,这二者似乎都包含表示赞美的单词。

除了几个不太具体的主题之外,LDA 似乎主要发现了两种主题:特定类型的主题与特定评分的主题。这是一个有趣的发现,因为大部分评论都由一些与电影相关的评论与一些证明或强调评分的评论组成。

在没有标签的情况下(或者像本章的例子这样,即使有标签的情况下),像 LDA 这样的主题模型是理解大型文本语料库的有趣方法。不过 LDA 算法是随机的,改变 random_state 参数可能会得到完全不同的结果。虽然找到主题可能很有用,但对于从无监督模型中得出的任何结论都应该持保留态度,我们建议通过查看特定主题中的文档来验证你的直觉。 LDA.transform 方法生成的主题有时也可以用于监督学习的紧凑表示。当训练样例很少时,这一方法特别有用。

附录:

一、参考文献

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

二、spacy 环境配置

1、spacy 如何安装,以及数据集使用,官网介绍如下

https://github.com/explosion/spacy-models/releases

进入后,可以看到如下界面,并下载支持对应spacy版本的Spacy-models;

此处的  lg 为large的缩写,根据spacy官方文档的解读,

模型指示符 如英文模型en,

后缀为 sm:en_core_web_sm-3.7.1 代表 small 模型;

后缀为 md: 代表 middle 模型;

后缀为 lg: 代表 large 模型;

后缀为 trf: 代表涵盖 transformer 模型;

2、选择需要的模型并找到适合的版本号下载

建议直接按照如下方式 下载到本地(放到python解释器安装的目录,经测试这样的下载速度较快。

查看python解释器安装目录指令:

python -c "import sys; print(sys.executable)"

3、这里以en_core_web_sm-3.5.0 为例

en_core_web_sm-3.5.0地址:Release en_core_web_sm-3.5.0 · explosion/spacy-models · GitHub

首先安装 spacy ,pip install spacy

然后 下载 en_core_web_sm 数据,python -m spacy download en_core_web_sm

如果下载 en_core_web_sm 数据,报如下类似的错:

requests.exceptions.SSLError: HTTPSConnectionPool(host='raw.githubusercontent.com', port=443): Max retries exceeded with url: /explosion/spacy-models/master/compatib ility.json (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl. c:992)')))

4、下载 en_core_web_sm-3.5.0-py3-none-any.whl

5、可以在安装了spacy 的环境中,安装下载的 en_core_web_sm-3.5.0-py3-none-any.whl

pip install en_core_web_sm-3.5.0-py3-none-any.whl

6、使用下面代码,运行检验即可

import spacynlp = spacy.load("en_core_web_lg")

如果上两行代码运行都未报错,即表明安装spacy成功,模型可以正常调用。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是PLAB?

接上文PLAB---》 可以看到和TLAB很像&#xff0c;PLAB即 Promotion Local Allocation Buffers。用在年轻代对象晋升到老年代时。 在多线程并行执行YGC时&#xff0c;可能有很多对象需要晋升到老年代&#xff0c;此时老年代的指针就"热"起来了&#xff0c;于是搞了个…

秒杀基本功能开发(显示商品列表和商品详情)

文章目录 1.数据库表设计1.商品表2.秒杀商品表3.修改一下秒杀时间为今天到明天 2.pojo和vo编写1.com/sxs/seckill/pojo/Goods.java2.com/sxs/seckill/pojo/SeckillGoods.java3.com/sxs/seckill/vo/GoodsVo.java 3.Mapper编写1.GoodsMapper.java2.GoodsMapper.xml3.分别编写Seck…

数据库(10)——图形化界面工具DataGrip

以后关于数据库的图片演示就使用DataGrip了 : ) 创建数据库和表 在连接上数据库之后&#xff0c;可以选择Schema创建一个新的数据库。 点击OK后&#xff0c;就已经创建了一个空的表。 要在数据库中建立一张新的表&#xff0c;右键数据库&#xff0c;点击new table 要给新表添…

Java对sqlserver表的image字段图片读取和输出本地

Java代码实现对sqlserver数据库表的image字段图片的读取&#xff0c;和输出存储到本地 由于表image字段图片存的内容是二进制值&#xff0c;如何输出保存到本地&#xff1a; 代码示例&#xff1a;&#xff08;注&#xff1a;连接sqlserver数据库需配置其驱动文件&#xff09; …

让EXCEL VBA支持鼠标滚轮,vb6 IDE鼠标滚轮插件原理

vb6 IDE鼠标滚轮插件怎么运行的(适用于VBA) 使用 Spy&#xff0c;我发现代码窗口正在获取 WM_MOUSEWHEEL 事件&#xff0c;但没有触发 WM_VSCROLL 消息。因此&#xff0c;我编写了一个简单的消息钩子&#xff0c;当它捕获鼠标滚轮事件时触发滚动事件。 我从 Spy 得知代码窗口的…

Android 项目Gradle文件讲解(Groovy和Kotlin)

Android 项目Gradle文件讲解&#xff08;Groovy和Kotlin&#xff09; 前言正文一、Gradle的作用二、Gradle的种类① 工程build.gradle② 项目build.gradle③ settings.gradle④ gradle.properties⑤ gradle-wrapper.properties⑥ local.properties 三、Groovy和Kotlin的语言对比…

系统安全及其应用

系统安全及其应用 部署服务器的初始化步骤&#xff1a; 1、配置IP地址&#xff0c;网关&#xff0c;DNS解析 2、安装源&#xff0c;外网&#xff08;在线即可yum&#xff09; 内网&#xff08;只能用源码包编译安装&#xff09; 3、磁盘分区 lvm raid 4、系统权限配置和基础安…

【ArcGISPro】3.1.5下载和安装教程

下载教程 arcgis下载地址&#xff1a;Трекер (rutracker.net) 点击磁力链下载弹出对应的软件进行下载 ArcGISPro3.1新特性 ArcGIS Pro 3.1是ArcGIS Pro的最新版本&#xff0c;它引入了一些新的特性和功能&#xff0c;以提高用户的工作效率和数据分析能力。以下是ArcGIS…

神经网络的工程基础(二)——随机梯度下降法|文末送书

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 本文涉及到的代码链接如下&#xff1a;regression2chatgpt/ch06_optimizer/stochastic_gradient_descent.ipynb 本文将讨论利用…

QT——QSlider实现,QT滑动控件的使用

目录 简介滑动块调节两种方法滑动条触发信号量理想滑动块运用&#xff08;参考&#xff09; 简介 QT中滑动条的控件叫QSlider&#xff0c;继承自QAbstractSlider类。 主要用途是通过滑块的滑动的方式在一定范围内调节某个值。根据调节的后得到的结果去执行一些处理&#xff0c…

第十三章 进程与线程

第十三章 进程与线程 程序与进程的概念 程序&#xff1a; 英文单词为Program&#xff0c;是指一系列有序指令的集合&#xff0c;使用编程语言所编写&#xff0c;用于实现一定的功能。 进程&#xff1a; 进程则是指启动后的程序&#xff0c;系统会为进程分配内存空间。 函数式…

浅析R16移动性增强那些事儿(DAPS/CHO/MRO)

R16移动性增强相关技术总结 Dual Active Protocol Handover Dual Active Protocol Handover意为双激活协议栈切换&#xff0c;下文简称DAPS切换&#xff0c;DAPS切换的核心思想是切换过程中&#xff0c;在UE成功连接到目标基站前继续保持和源基站的连接和数据传输&#xff0c;…

贷款借钱平台 小额贷款系统开发小额贷款源码 贷款平台开发搭建

这款是贷款平台源码/卡卡贷源码/小贷源码/完美版 后台51800 密码51800 数据库替换application/database.php程序采用PHPMySQL&#xff0c;thinkphp框架代码开源&#xff0c;不加密后台效果&#xff1a;手机版效果 这款是贷款平台源码/卡卡贷源码/小贷源码/完美版 后台51800 密码…

【软考】2024年5月系统架构设计师考试感受

目录 一 考试时间 二 考试方式 三 考试批次安排 四 回忆版真题 五 考试感受 一 考试时间 2024年5月系统架构设计师考试时间如下&#xff1a; 5&#x1f237;️25日上午 8点30-12点30: 综合知识和案例分析&#x1f49a; 5&#x1f237;️25日下午 14点30-16点30: 论文…

《庆余年算法番外篇》:范闲通过最短路径算法在阻止黑骑截杀林相

剧情背景 在《庆余年 2》22集中&#xff0c;林相跟大宝交代完为人处世的人生哲理之后&#xff0c;就要跟大宝告别了 在《庆余年 2》23集中&#xff0c;林相在告老还乡的路上与婉儿和大宝告别后 范闲也在与婉儿的对话中知道黑骑调动是绝密&#xff0c;并把最近一次告老还乡梅…

民国漫画杂志《时代漫画》第39期.PDF

时代漫画39.PDF: https://url03.ctfile.com/f/1779803-1248636473-6bd732?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

Base64码转换

title: Base64码转换 date: 2024-06-01 20:30:28 tags: vue3 后端图片前端显示乱码 现象 后端传来一个图片&#xff0c;前端能够接收&#xff0c;但是console.log()后发现图片变成了乱码&#xff0c;但是检查后台又发现能够正常的收到了这张图片。 处理方法 笔者有尝试将图…

Leetcode3165. 不包含相邻元素的子序列的最大和(Go中的线段树分治包含多类数据使用maintain进行维护)

题目截图 题目分析 不能取相邻的&#xff0c;就是打家劫舍 然后更改某一个值就是单点更新 更新后&#xff0c;需要更新区间的值 需要注意的是&#xff0c;使用分治时需要考虑到一头一尾的问题&#xff0c;所以有4种情况&#xff08;选or不选在两个位置&#xff09; 这四种情况…

利用 Scapy 库编写 Teardrop 攻击脚本

一、介绍 Teardrop攻击是一种历史上比较著名的拒绝服务&#xff08;Denial of Service, DoS&#xff09;攻击&#xff0c;主要利用了IP数据包分片和重组过程中的漏洞来攻击目标系统。以下是对Teardrop攻击的详细介绍&#xff1a; 1.1 攻击原理 IP协议允许数据包在传输过程中…

jpom ruoyi 发布后端

添加ssh 添加标签 添加仓库 添加构建 构建 命令 APP_NAMEenterprise IMAGE_NAMEenterprise:latest APP_PORT8080 RUN_ENVjenkins cd ruoyi-admin docker stop $APP_NAME || true docker rm $APP_NAME || true docker rmi $IMAGE_NAME || true docker build -f Dockerfil…