词袋模型(Bag-of-Words,BoW)是一种表示和处理文本数据的模型或框架,它提供了一种简单的思想,使得我们能够实现文本转换为数值形式,以便进行进一步的分析,例如:进行新闻分类、文档检索、情感分析等任务。
1. 文本数值化
我们通过一个例子来理解使用词袋模型实现文本数值化的过程。文本内容如下:
我生活在中国,我爱中国 我爱北京天安门
对文本分词(将文本分割成独立词的序列):
['我', '生活', '在', '中国', ',', '我', '爱', '中国'] ['我', '爱', '北京', '天安门']
去除停用词(去除那些在文本中频繁出现但对意义贡献不大的单词,如 “的”、”是”等):
['我', '生活', '中国', ',', '我', '爱', '中国'] ['我', '爱', '北京', '天安门']
构建词汇表(基于所有文本内容创建一个、包含所有词汇的词汇表):
['中国' '北京' '天安门' '我' '爱' '生活']
文本向量化(将每个文本表示成一个向量,向量维度等于词汇表的大小。每个维度的值对应词汇表中的一个词,其值为该词在所有文本中出现的次数、one-hot、tf-idf):
使用词频统计量:
中国 北京 天安门 我 爱 生活 2 0 0 2 1 1 0 1 1 1 1 0
使用 one hot 统计量:
中国 北京 天安门 我 爱 生活 1 0 0 1 1 1 0 1 1 1 1 0
使用 TF-IDF 统计量:
中国 北京 天安门 我 爱 生活 0.57615236 0. 0. 0.40993715 0.40993715 0.57615236 0. 0.57615236 0.57615236 0.40993715 0.40993715 0.
文本数据就被数值化为向量,我们就可以基于该向量进行一些文本任务。例如:我讲的垃圾邮件识别器项目使用的就是基于词袋模型的向量表示来训练朴素贝叶斯算法模型。
为什么叫做词袋模型呢?
词袋模型之所以被称为 “词袋” 模型,是因为这种模型在实现文本数值化的过程类似于把所有的词汇扔进一个袋子里,忽略了它们在原文中的顺序和语法结构,只关心每个词汇出现的次数。
2. API 使用方法
pip install scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install jieba -i https://pypi.tuna.tsinghua.edu.cn/simple/
示例代码:
from sklearn.feature_extraction.text import CountVectorizer from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import TfidfVectorizer import jieba def test(): # 语料库,文档库 texts = ['我生活在中国,我爱中国', '我爱北京天安门'] # 1. 文本分词 ['我 生活 在 中国 ,我 爱 中国', '我 爱 北京 天安门'] texts = [' '.join(jieba.lcut(text)) for text in texts] print(texts) # 2. 去除停用词 # 首先得先有一个停用词表 stopwords = [line.strip() for line in open('stopwords.txt', encoding='utf-8')] # print(stopwords) # 3. 构建词汇表 vectorizer = CountVectorizer(stop_words=stopwords, binary=True) vectorizer.fit(texts) # 默认情况下,CountVectorizer 会去除单字词、标点符号 print(vectorizer.get_feature_names_out()) # 4. 文本向量化 vectors = vectorizer.transform(texts) print(vectors) print(vectors.toarray()) # 训练并且计算文本对应数值向量表示 vectors = vectorizer.fit_transform(texts) # 用于将已经得到的词频向量转换为 TF-IDF 向量 tfidf = TfidfTransformer() vectors = tfidf.fit_transform(vectors.toarray()) print(vectors.toarray()) # 直接针对语料进行转换的 tfidf = TfidfVectorizer() vectors = tfidf.fit_transform(texts) print(vectors) # 向量的维度取决于词表的大小,假设词表有 10 万个词,得到的高维度向量中大部分的分量的值都是0,这种向量叫高维稀疏向量 # 缺点:需要更多的存储空间 if __name__ == '__main__': test()
3. API 参数详解
文档处理相关参数
# 指定文档预处理函数 preprocessor=None # 文本内容是否小写 lowercase=True
词表构建相关参数:
# 指定分词是词粒度(word)还是字符粒度(char) analyzer='word' # 用于切分出词的规则 token_pattern=r"(?u)\b\w\w+\b" # 增加 N-Gram 特征词 ngram_range=(1, 1) # 将某个词在整个文档列表中出现次数大于 max_df 的词从词表中去除 max_df=1.0 # 将某个词在整个文档列表中出现次数小于 max_df 的词从词表中去除 min_df=1 # 将 TF 值最大的前 Top N 保留 max_features=None # 指定自定义词表 vocabulary=None # 去除停用词 stop_words=None
示例代码:
from sklearn.feature_extraction.text import CountVectorizer import jieba jieba.setLogLevel(500) def preprocess(text): return ' '.join(jieba.lcut(text)) # 1. preprocess def test01(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(preprocessor=preprocess) vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 2. analyzer def test02(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(analyzer='char') vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 3. token_pattern def test03(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(preprocessor=preprocess, token_pattern=r"(?u)\b\w+\b") vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 4. ngram_range def test04(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(preprocessor=preprocess, ngram_range=(1, 2)) vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 5. max_df、min_df def test05(): texts = ['我生活在中国,我爱中国北京,中国是我的家', '我爱北京天安门'] # 整数:如果某个词在超过 1 个文档中存在,则该词将会从词表中删除 # 小数:如果某个词再超过 40% 的文档中出现过,则该词将会从词表中删除 vectorizer = CountVectorizer(preprocessor=preprocess, max_df=1) vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 6. max_features def test06(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(preprocessor=preprocess, max_features=3) vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 7. vocabulary def test07(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(preprocessor=preprocess, vocabulary=['中国', '北京']) vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) # 8. stop_words def test08(): texts = ['我生活在中国,我爱中国,中国是我的家', '我爱北京天安门'] vectorizer = CountVectorizer(preprocessor=preprocess, stop_words=['中国', '天安门']) vectorizer.fit(texts) print(vectorizer.get_feature_names_out()) if __name__ == '__main__': test08()