NLP项目:维基百科文章爬虫和分类【02】 - 语料库转换管道

一、说明
我的NLP项目在维基百科条目上下载、处理和应用机器学习算法。相关上一篇文章中,展示了项目大纲,并建立了它的基础。首先,一个 Wikipedia 爬网程序对象,它按名称搜索文章,提取标题、类别、内容和相关页面,并将文章存储为纯文本文件。其次,一个语料库对象,它处理完整的文章集,允许方便地访问单个文件,并提供全局数据,如单个令牌的数量。
二、背景介绍
在本文中,我将继续展示如何创建一个NLP项目,以从其机器学习领域对不同的维基百科文章进行分类。你将了解如何创建自定义 SciKit Learn 管道,该管道使用 NLTK 进行标记化、词干提取和矢量化,然后应用贝叶斯模型来应用分类。所有代码也可以在Jupyter Notebook中看到。
本文的技术背景是 Python v3.11 和几个附加库,最重要的是 pandas v2.0.1、scikit-learn v1.2.2 和 nltk v3.8.1。所有示例也应该适用于较新的版本。
2.1 需求和使用的 Python 库
请务必阅读并运行上一篇文章的要求,以便有一个 Jupyter 笔记本来运行所有代码示例。
对于本文,需要以下库:这些步骤中的每一个都将成为管道对象的一部分,管道对象是读取、预处理、矢量化和聚类文本的顺序过程。我们将在此项目中使用以下 Python 库和对象:
pandas
DataFrame用于存储文本、标记和矢量的对象
sk-learn
Pipeline对象实现处理步骤链BaseEstimator并生成表示管道步骤的自定义类TransformerMixin
NLTK
- PlaintextCorpusReader 用于可遍历对象,可访问文档、提供标记化方法并计算有关所有文件的统计信息
- sent_tokenizer 和 word_tokenizer 用于生成令牌
- 减少标记的stopword列表
2.2 SciKit Learn Pipeline
为了便于获得一致的结果和轻松定制,SciKit Learn 提供了 Pipeline 对象。该对象是一系列转换器、实现拟合fit和transform变换方法的对象以及实现拟合fit方法的最终估计器。执行管道对象意味着调用每个转换器来修改数据,然后将最终的估计器(机器学习算法)应用于此数据。管道对象公开其参数,以便可以更改超参数,甚至可以跳过整个管道步骤。
我们将使用此概念来构建一个管道,该管道开始创建语料库对象,然后预处理文本,然后提供矢量化,最后提供聚类或分类算法。为了突出本文的范围,我将在下一篇文章中仅解释转换器步骤,并接近聚类和分类。
三、管道准备
让我们从大局开始。最终的管道对象将按如下方式实现:
pipeline = Pipeline([('corpus', WikipediaCorpus()),('preprocess', TextPreprocessor()),('tokenizer', Tokenizer()),('encoder', OneHotEncoder())
]) 然后,此管道从一个空的 Pandas 数据帧对象开始,随后将数据添加到该对象,即我们实现如下所示的数据帧对象:

对于上述每个步骤,我们将使用自定义类,该类从推荐的 ScitKit Learn 基类继承方法。
from sklearn.base import BaseEstimator, TransformerMixin
from nltk.tokenize import sent_tokenize, word_tokenizeclass SciKitTransformer(BaseEstimator, TransformerMixin):def fit(self, X=None, y=None):return selfdef transform(self, X=None):return self 让我们开始实现。
3.1 管道步骤 1:创建语料库
第一步是重用上一篇文章中解释的 Wikipedia 语料库对象,并将其包装在基类中,并提供两个 DataFrame 列 title 和 raw。在标题列中,我们存储除 .txt 扩展名之外的文件名。在原始列中,我们存储文件的完整内容。
此转换使用列表推导式和 NLTK 语料库读取器的内置方法。
class WikipediaCorpus(PlaintextCorpusReader):def __init__(self, root_path):PlaintextCorpusReader.__init__(self, root_path, r'.*')class WikipediaCorpus(SciKitTransformer):def __init__(self, root_path=''):self.root_path = root_pathself.corpus = WikipediaReader(self.root_path)def transform(self, X=None):X = pd.DataFrame().from_dict({'title': [filename.replace('.txt', '') for filename in self.corpus.fileids()],'raw': [self.corpus.raw(doc) for doc in corpus.fileids()]})return X 3.2 管道步骤 2:文本预处理
在 NLP 应用程序中,通常会检查原始文本中不需要的符号,或者可以删除的停用词,甚至应用词干提取和词形还原。
对于维基百科的文章,我决定将文本分成句子和标记,而不是标记转换,最后将它们重新组合在一起。转换如下:
- 删除所有停用词
- 删除所有非ASCII字母,非数字标记
- 仅保留 .,以及用于序列分隔
,;. - 使用单个空格删除所有出现的多个空格
这是 TextPreprocessor 的完整实现。 DataFrame 对象使用 Pandas apply 方法预处理的新列进行扩展。
class TextPreprocessor(SciKitTransformer):def __init__(self, root_path=''):self.root_path = root_pathself.corpus = WikipediaReader(self.root_path)self.tokenizer = word_tokenizedef preprocess(self, text):preprocessed = ''for sent in sent_tokenize(text):if not len(sent) <= 3:text = ' '.join([word for word in word_tokenize(sent) if not word in stopwords.words("english")])text = re.sub('[^A-Za-z0-9,;\.]+', ' ', text)text = re.sub(r'\s+', ' ', text)# preserve text tokenstext = re.sub(r'\s\.', '.', text)text = re.sub(r'\s,', ',', text)text = re.sub(r'\s;', ';', text)# remove all non character, non number charspreprocessed += ' '+ text.strip()return preprocesseddef transform(self, X):X['preprocessed'] = X['raw'].apply(lambda text: self.preprocess(text))return X 3.3 管道步骤 3-标记化
现在,使用与之前相同的 NLT word_tokenizer 对预处理后的文本进行再次标记化,但可以使用不同的标记化器实现进行交换。
和以前一样,通过在预处理列上使用 apply 来扩展 DataFrame,添加一个新列 tokens。
class TextTokenizer(SciKitTransformer):def preprocess(self, text):return [token.lower() for token in word_tokenize(text)]def transform(self, X):X['tokens'] = X['preprocessed'].apply(lambda text: self.preprocess(text))return X 3.4 管道步骤 4:编码器
对标记化文本进行编码是矢量化的先导。为了使本文保持重点,我将提供一种相当简单的编码方法,该方法计算所有文本的完整词汇表,并对特定文章中出现的所有单词进行独热编码。词汇表的基础是错误的:我使用精炼标记列表作为输入,但也可以使用NLTK-CorpusReader对象中的vocab方法。
class OneHotEncoder(SciKitTransformer):def encode(self, token_series, tokens):one_hot = {}for _, token_list in token_series.items():for token in token_list:one_hot[token] = 0for token in tokens:one_hot[token] = 1return one_hotdef transform(self, X):token_list = X['tokens']X['one-hot-encoding'] = X['tokens'].apply(lambda tokens: self.encode(token_list, tokens))return X 这种编码非常昂贵,因为每次运行的完整词汇表都是从头开始构建的——这可以在未来的版本中改进。
四、完整的源代码
以下是完整的示例:
import numpy as np
import pandas as pdfrom nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
from sklearn.base import TransformerMixin
from sklearn.pipeline import Pipeline
from nltk.corpus.reader.plaintext import CategorizedPlaintextCorpusReader
from nltk.tokenize.stanford import StanfordTokenizerclass WikipediaPlaintextCorpus(PlaintextCorpusReader):def __init__(self, root_path):PlaintextCorpusReader.__init__(self, root_path, r'.*')class SciKitTransformer(BaseEstimator, TransformerMixin):def fit(self, X=None, y=None):return selfdef transform(self, X=None):return selfclass WikipediaCorpus(SciKitTransformer):def __init__(self, root_path=''):self.root_path = root_pathself.wiki_corpus = WikipediaPlaintextCorpus(self.root_path)def transform(self, X=None):X = pd.DataFrame().from_dict({'title': [filename.replace('.txt', '') for filename in self.wiki_corpus.fileids()],'raw': [self.wiki_corpus.raw(doc) for doc in corpus.fileids()]})return Xclass TextPreprocessor(SciKitTransformer):def __init__(self, root_path=''):self.root_path = root_pathself.corpus = WikipediaPlaintextCorpus(self.root_path)def preprocess(self, text):preprocessed = ''for sent in sent_tokenize(text):text = ' '.join([word for word in word_tokenize(sent) if not word in stopwords.words("english")])text = re.sub('[^A-Za-z0-9,;\.]+', ' ', text)text = re.sub(r'\s+', ' ', text)# preserve text tokenstext = re.sub(r'\s\.', '.', text)text = re.sub(r'\s,', ',', text)text = re.sub(r'\s;', ';', text)# remove all non character, non number charspreprocessed += ' '+ text.strip()return preprocesseddef transform(self, X):X['preprocessed'] = X['raw'].apply(lambda text: self.preprocess(text))return Xclass TextTokenizer(SciKitTransformer):def preprocess(self, text):return [token.lower() for token in word_tokenize(text)]def transform(self, X):X['tokens'] = X['preprocessed'].apply(lambda text: self.preprocess(text))return Xclass OneHotEncoder(SciKitTransformer):def encode(self, token_series, tokens):one_hot = {}for _, token_list in token_series.items():for token in token_list:one_hot[token] = 0for token in tokens:one_hot[token] = 1return one_hotdef transform(self, X):token_list = X['tokens']X['one-hot-encoding'] = X['tokens'].apply(lambda tokens: self.encode(token_list, tokens))return Xcorpus = WikipediaPlaintextCorpus('articles2')
pipeline = Pipeline([('corpus', WikipediaCorpus(root_path='./articles2')),('preprocess', TextPreprocessor(root_path='./articles2')),('tokenizer', TextTokenizer()),('encoder', OneHotEncoder())
]) 管道对象在 Jupyter 笔记本中呈现如下:

五、结论
SciKit Learn Pipeline 对象提供了一种将多个转换和机器学习模型堆叠在一起的便捷方法。所有相关的超参数都可以公开并配置以获得可重复的结果。在本文中,您学习了如何通过四个步骤为 Wikipedia 文章创建文本处理管道:a) WikipediaCorpus 用于访问纯文本文件和全局统计信息(例如单词出现次数),b) TextPreprocessor 用于从文本中删除符号和停用词,c) TextTokenizer从预处理的文本创建标记,d) OneHotEncoder 提供简单的统计,总语料库词汇中的单词出现在特定文章中。下一篇文章将继续如何将标记和编码转换为数值向量表示。
参考资料:塞巴斯蒂安
相关文章:
NLP项目:维基百科文章爬虫和分类【02】 - 语料库转换管道
一、说明 我的NLP项目在维基百科条目上下载、处理和应用机器学习算法。相关上一篇文章中,展示了项目大纲,并建立了它的基础。首先,一个 Wikipedia 爬网程序对象,它按名称搜索文章,提取标题、类别、内容和相关页面&…...
如何在Ubuntu 20.04.6 LTS系统上运行Playwright自动化测试
写在前面 这里以 Ubuntu 20.04.6 LTS为例。示例代码:自动化测试代码。 如果过程中遇到其他非文本中提到的错误,可以使用搜索引擎搜索错误,找出解决方案,再逐步往下进行。 一、 环境准备 1.1 安装python3 1.1.1 使用APT安装Py…...
c++ sort函数cmp比较参数传入
开始 假定有一个结构体 struct node{int p,r,val; };第一种 定义cmp函数,sort直接传入cmp bool cmp(node a,node b){return a.p<b.p;} sort(vec.begin(),vec.end(),cmp);第二种 lamada表达式??这个中括号里面可以不为空,但是…...
【计算机网络笔记】什么是计算机网络?
前言计算机网络的定义交换网络什么是Internet从组成细节角度看从服务角度看 最后感谢 💖 本篇文章总字数:1342字 预计阅读时间:5~10min 建议收藏之后慢慢阅读 前言 计算机网络通信技术计算机技术。 计算机网络是通信技术与计算机技术紧密结…...
极简C++(2) 类与对象
类与对象的基本概念 CLASS类将数据以及数据上的操作封装在一起 OBJECT对象是有具体类类型的变量 打个比方,类就像一个制作月饼的摸具,那么我们可以通过这个摸具来放入面粉和馅料编程一个月饼,那么摸具就是类,而各种各样的月饼便是…...
【Java 进阶篇】JavaScript流程控制语句详解
JavaScript是一门高级编程语言,具备丰富的流程控制语句,用于控制程序的执行流程。在本篇博客中,我们将深入探讨JavaScript的流程控制语句,包括条件语句、循环语句、以及其他一些控制语句。这篇博客将逐步介绍这些概念,…...
【Page-level Heap Fengshui -- Cross-Cache Overflow】corCTF2022-cache-of-castaways
前言 什么叫 Cross Cache 呢?其实就是字面意思,我们知道内核中的大部分结构体都有自己的专属 slab 内存池。那现在我们可以想象一下这个场景,我们拥有一个特定 kmem-cache 的溢出漏洞,那么我们该如何利用呢? 程序分析…...
vue-mixin
1.vue中,混入(mixin)是一种特殊的使用方式。一个混入对象可以包含任意的组件配置选项(data, props, components, watch,computed…)可以根据需求"封装"一些可复用的单元,并在使用时根据一定的策略合并到组件的选项中,使用时和组件自…...
力扣刷题 day43:10-13
1.完全平方数 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 …...
3、在docker 容器中安装tomcat
1、在服务器上查找tomcat镜像,查看前5条 docker search tomcat --limit 5 2、拉取镜像到本地 拉取官方的tomcat到本地 docker pull tomcat:9.0.34-jdk8 3、查看本地镜像 docker images |grep tomcat 4、启动tomcat 服务 使用默认配置 docker ru…...
工业互联网系列1 - 智能制造中有哪些数据在传输
工业互联网以网络为基础,需要传输的数据种类多种多样,这些数据对于实时监控、生产优化、设备维护和决策支持等方面都至关重要。 以下是一些常见智能制造业中需要传输的数据类型: 传感器数据:制造设备上安装的传感器(如…...
centos7部署Nginx和RabbitMQ
文章目录 Nginx安装部署【简单】简介安装 RabbitMQ安装部署【简单】简介安装 Nginx安装部署【简单】 简介 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx可以托管用户编写的WEB应用程序成为可访问的网页服务&am…...
Nacos集群搭建
Nacos集群搭建 1.集群结构图 Nacos集群图: 其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。 三个nacos节点的地址: 节点ipportnacos1192.168.150.18845nacos2192.168.150.18846nacos3192.168.150…...
运维小工具分享
1.windwos时间同步工具 通过NetTime软件同步 通过一个免费的同步时间软件来进行对时操作 软件官网链接:http://timesynctool.com/ 修改Windows主机时间,修改时间,时间差为10年、3年、4月份、24小时、2小时、1分钟;都可以及时与“…...
Eclipse插件安装版本不兼容问题解决方案——Papyrus插件为例
项目场景: Eclipse Papyrus安装后,没有新建Papyrus工程选项,也没有新建Papyrus Model的选项。 打开Papyrus Model会报错 问题描述 同样的,安装其他插件也是。可能某个插件之前安装是好用的,结果Eclipse的版本更新了,就再也安装不好用了 原因分析: 根本原因是因为包之…...
【Qt之QTimer】使用及技巧
简介 QTimer是Qt中的定时器类,用于执行定时操作,如在一段时间间隔后触发某个槽函数或执行特定的代码。它提供了灵活的定时功能,可以用于处理各种时间相关的任务。它是基于Qt的事件循环机制工作的。 主要函数说明 构造函数: QTim…...
零基础快速自学SQL,2天足矣。
此文是《10周入门数据分析》系列的第6篇。 想了解学习路线,可以先行阅读“ 学习计划 | 10周入门数据分析 ” 上一篇分享了数据库的基础知识,以及如何安装数据库,今天这篇分享数据库操作和SQL。 SQL全称是 Structured Query Language&#x…...
Meta开源数字水印Stable Signature,极大增强生成式AI安全
全球社交、科技巨头Meta(Facebook、Instagram等母公司)在官网宣布,开源数字水印产品Stable Signature,并公开论文。 据悉,Stable Signature是由Meta和INRIA(法国国家信息与自动化研究所)联合开…...
python实现分词器
在Python中实现分词有很多方法,具体取决于你的应用场景和数据。下面我会介绍一种常用的分词库——jieba。如果你的数据是英文,你也可以使用nltk库。 中文分词 使用jieba进行中文分词: 首先,你需要安装jieba库。如果还未安装&am…...
第五十二章 学习常用技能 - Global 映射
文章目录 第五十二章 学习常用技能定义数据库定义命名空间Global映射 第五十二章 学习常用技能 定义数据库 创建本地数据库: 登录管理门户。选择系统管理 > 配置 > 系统配置 > 本地数据库。选择创建新数据库以打开数据库向导。输入新数据库的以下信息&a…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
