一、前言:
相信不少学人工智能自然语言处理或者对机器学习,深度学习等等模型处理文本任务的同学都会产生这个疑问: 咦 ? 这算法模型归根到底不就是个数学和计算机硬件综合的多行命令代码吗 ? 它是怎么读懂我们人类的语言的 ? 甚至在有些时候比我们人类本身判断的还要准确 ! 那么今天,就由笔者来带领大家揭开这一转化最基础的奥秘之一---文本转数字或向量的密码,计算机与人类间的翻译器之 词袋模型。
二、定义与介绍
定义
词袋模型(Bag of Words, BoW)是自然语言处理(NLP)中一种非常基础且广泛使用的特征提取方法。词袋模型是一种文本表示方法,它将文本数据转换为数值形式,使得机器学习算法能够处理。在词袋模型中,文本被表示为一个词频向量,其中每个维度对应一个特定的词,而该维度的值表示该词在文本中出现的次数。它将文本数据看作是一个袋子(或集合)中的词汇组成的集合,忽略了词汇之间的顺序和语法结构,仅仅关注每个词汇在文本中的出现频率。它的核心思想是将文本转换为特征向量,以便能够应用于机器学习算法。
特点
- 无序性:词袋模型不考虑词的顺序,只关注词的出现频率。
- 稀疏性:由于词汇表可能非常大,但文档中实际出现的词可能很少,因此生成的向量通常是稀疏的。
步骤
-
收集语料库:首先,需要收集一组文本数据,这组数据称为语料库(corpus)。语料库可以是一系列文档、文章、新闻等。
-
构建词汇表:首先需要确定一个词汇表,这可以是整个语料库中所有不重复的词的集合。
-
文本分词:将文本分割成单独的词或短语,这个过程称为分词(Tokenization),中文文本数据下笔者推荐使用jieba分词,相比较其他分词工具来说更准确和高效些,英文推荐NLTK等等。
-
词频统计:对于每个文档,统计词汇表中每个词的出现次数。
-
向量表示:将文本转换为特征向量的过程称为向量化,将统计得到的词频转换为向量形式,向量的每个元素对应词汇表中的一个词,元素的值为该词在文档中的出现次数。例如计数向量化(Count Vectorization)和 TF-IDF 向量化(Term Frequency-Inverse Document Frequency Vectorization)
-
应用机器学习算法:得到文本的特征向量表示后,可以将其应用于各种机器学习算法,例如分类、聚类、情感分析等。
看到这里,聪明的小伙伴可能都会产生一个疑惑: ??? 难道就这样就结束了 ? 只是拿词频作为数值替换每一个词,那么语言文本之间的上下逻辑和前后联系怎么办 ??? 哎,这里我们就要讲解一下词袋模型的基本假设了。
基本假设
词袋模型的基本假设是,文本中的每个词汇都是独立的,词汇的出现与其它词汇无关。基于这个假设,词袋模型将文本表示为一个固定长度的向量,向量的每个维度对应一个词汇,其值表示该词汇在文本中的出现次数或者权重。
应用
- 文本分类:词袋模型常用于文本分类任务,如垃圾邮件检测、情感分析等(顺带提一下,笔者大一攻读学习的主要方向就是情感分析)。尽管现代NLP模型(如BERT、GPT)已经取得了显著进展,但在某些简单任务中,词袋模型仍然是一个有效的基线方法。
- 文本相似度计算:可以用来计算文档之间的相似度。
三、词袋模型的优缺点
优点
- 简单直观:模型容易理解和实现。
- 计算效率:处理速度快,尤其是在处理大量数据时。
缺点
- 丢失语义信息:词袋模型不保留词的顺序,因此无法捕捉词序带来的语义变化。忽略了词汇之间的顺序和语法结构,无法捕捉到词汇之间的关系。
- 无法处理同义词:不同的同义词在词袋模型中被视为不同的词,即使它们具有相同或相似的意义。
- 无法处理多义词:同一个词在不同上下文中可能有不同的意义,但词袋模型无法区分这些差异。
- 维度灾难问题:词袋模型也存在维度灾难的问题,当词汇表很大时,特征向量的维度也会很大,导致计算和存储的开销增加。
简单点说,词袋模型的最大的缺点,还是无法很好地提取和表示文本之间的语法等等关系
改进
为了解决词袋模型的一些缺点,研究人员提出了一些改进方法,如:
- TF-IDF(Term Frequency-Inverse Document Frequency):一种加权方法,考虑词频和逆文档频率,降低常见词的权重,提高罕见词的权重。
- 词嵌入(Word Embeddings):如Word2Vec、GloVe等模型,将词语表示为低维连续向量,能够捕捉词语的语义信息。
- 上下文嵌入:如BERT、GPT等模型,能够捕捉词语在上下文中的语义信息。
词袋模型虽然简单,但它是许多更复杂文本表示方法的基础,并且在某些情况下仍然非常有效。好,老粉都知道我现在要干嘛了,嘿嘿,为了便于大家理解后续的代码,我们在下面给出一个文本示例
四、词袋模型文本案例示例
示例
假设我们有以下两个文档:
- 文档1:"I love machine learning"
- 文档2:"Machine learning is great"
步骤1:文本预处理
假设我们不进行停用词去除和词干提取,直接分词:
- 文档1:["I", "love", "machine", "learning"]
- 文档2:["Machine", "learning", "is", "great"]
步骤2:创建词汇表
从所有文档中提取唯一词语,得到词汇表:
- 词汇表:["I", "love", "machine", "learning", "is", "great"]
步骤3:构建词频向量
根据词汇表统计每个词在文档中的出现次数:
-
文档1:[1, 1, 1, 1, 0, 0]
- "I": 1次
- "love": 1次
- "machine": 1次
- "learning": 1次
- "is": 0次
- "great": 0次
-
文档2:[0, 0, 1, 1, 1, 1]
- "I": 0次
- "love": 0次
- "machine": 1次
- "learning": 1次
- "is": 1次
- "great": 1次
到这里,我们就得到了我们想要的数值向量,而后送入模型进行训练即可。
五、词袋模型示例代码
步骤
- 文本预处理:包括分词、去除停用词(可选)。
- 创建词汇表:提取所有文档中的唯一单词。
- 构建词频向量:统计每个单词在文档中出现的次数。
示例代码
1.原生python构建
import re
from collections import defaultdict
# 停用词列表(可选)
stopwords = set(['is', 'a', 'the', 'and', 'of', 'in', 'to', 'on', 'for'])
# 文档列表
documents = [
"I love machine learning",
"Machine learning is great",
"Natural language processing is a part of artificial intelligence"
]
# 文本预处理函数
def preprocess(text):
# 转小写
text = text.lower()
# 去除标点符号
text = re.sub(r'[^\w\s]', '', text)
# 分词
words = text.split()
# 去除停用词(如果需要)
words = [word for word in words if word not in stopwords]
return words
# 创建词汇表
vocab = set()
for doc in documents:
words = preprocess(doc)
vocab.update(words)
vocab = sorted(vocab) # 按字母顺序排序词汇表
word_to_index = {word: idx for idx, word in enumerate(vocab)}
# 构建词频向量
def build_bow_vector(doc, word_to_index):
words = preprocess(doc)
vector = [0] * len(word_to_index)
for word in words:
if word in word_to_index:
index = word_to_index[word]
vector[index] += 1
return vector
# 对所有文档构建词频向量
bow_vectors = [build_bow_vector(doc, word_to_index) for doc in documents]
# 输出词汇表和词频向量
print("词汇表:", vocab)
print("词频向量:")
for vector in bow_vectors:
print(vector)
代码说明
-
预处理函数
preprocess:- 将文本转换为小写。
- 去除标点符号。
- 分词。
- 去除停用词(可选)。
-
创建词汇表:
- 遍历所有文档,提取唯一单词并存入集合
vocab。 - 对词汇表进行排序并创建单词到索引的映射
word_to_index。
- 遍历所有文档,提取唯一单词并存入集合
-
构建词频向量:
- 对每个文档,使用预处理函数得到单词列表。
- 初始化一个长度为词汇表大小的向量,所有值为0。
- 遍历单词列表,统计每个单词的出现次数并更新向量。
-
输出:
- 输出词汇表和每个文档对应的词频向量。
运行结果
词汇表: ['artificial', 'great', 'intelligence', 'language', 'learning', 'love', 'machine', 'natural', 'part', 'processing']
词频向量:
[0, 0, 0, 0, 1, 1, 1, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 1, 0, 0, 0]
[1, 0, 1, 1, 0, 0, 0, 1, 1, 1]
2.使用scikit-learn库实现词袋模型
from sklearn.feature_extraction.text import CountVectorizer
# 文档列表
documents = ["I love machine learning", "Machine learning is great"]
# 创建CountVectorizer对象
vectorizer = CountVectorizer()
# 拟合并转换文档
X = vectorizer.fit_transform(documents)
# 输出词汇表
print("词汇表:", vectorizer.get_feature_names_out())
# 输出词频向量
print("词频向量:\n", X.toarray())
运行结果:
词汇表: ['great' 'is' 'learning' 'love' 'machine']
词频向量:
[[0 0 1 1 1]
[1 1 1 0 1]]
总结
通过上述代码,我们实现了一个简单的词袋模型,将文本数据转换为词频向量。尽管没有使用任何外部库,但这种方法足够直观并且适用于小规模文本数据的处理。在实际应用中,通常会使用更高效的库(如scikit-learn)来处理大规模文本数据。
以上就是笔者关于特征提取中有关词袋模型的相关详解,欢迎大家点赞,收藏,交流和关注!!!