深度学习笔记(6)文本分类
文章目录
- 深度学习笔记(6)文本分类
- 一、文本分析与关键词提取
- 1.关键概念
- 1.停用词
- 2 Tf-idf:关键词提取
- 3.相似度
- 二、文本分析案例
- 1.数据处理
- 2.分词:实用结巴分词器
- 3.清洗
- 4.TF-IDF
- 5.LDA:主题模型
- 6.贝叶斯算法分类
一、文本分析与关键词提取
1.关键概念
1.停用词
大量出现并且没啥大用的词,我们就把它去掉。通常用停用词表来进行过滤。(晚上有些现成的词表可以下载)
2 Tf-idf:关键词提取
1.先去掉停用词,再进行词频统计
2.分析词频高的词进行idf
如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性,正是我们所需要的关键词。
TF表示词频,即一个词在文档中出现的次数。TF的计算公式通常如下:
TF
(
t
,
d
)
=
词
t
在文档
d
中出现的次数
文档
d
中词的总数
% TF(词频) \text{TF}(t, d) = \frac{\text{词 } t \text{ 在文档 } d \text{ 中出现的次数}}{\text{文档 } d \text{ 中词的总数}}
TF(t,d)=文档 d 中词的总数词 t 在文档 d 中出现的次数
IDF
(
t
)
=
log
文档总数
包含词
t
的文档数
+
1
% IDF(逆文档频率) \text{IDF}(t) = \log\frac{\text{文档总数}}{\text{包含词 } t \text{ 的文档数} + 1}
IDF(t)=log包含词 t 的文档数+1文档总数
TF-IDF
(
t
,
d
)
=
TF
(
t
,
d
)
×
IDF
(
t
)
% TF-IDF \text{TF-IDF}(t, d) = \text{TF}(t, d) \times \text{IDF}(t)
TF-IDF(t,d)=TF(t,d)×IDF(t)
比如下面的一个例子(文档数可以用google搜索的数据)
3.相似度
相似度
句子A:我喜欢看电视,不喜欢看电影
句子B:我不喜欢看电视,也不喜欢看电影。
分词:
句子A:我/喜欢/看/电视,不/喜欢/看/电影
句子B:我/不/喜欢/看/电视,也/不/喜欢/看/电影。
语料库:我,喜欢,看,电视,电影,不,也。
词频:
句子A:我1,喜欢2,看2,电视1,电影1,不1,也0。
句子B:我1,喜欢2,看2,电视1,电影1,不2,也1。
词频向量:
句子A : [1, 2, 2, 1, 1, 1, 0]
句子B : [1, 2, 2, 1, 1, 2, 1]
二、文本分析案例
1.数据处理
1.实用jieba分词器进行分词:可以非常方便地为中文文本进行分词,即将连续的中文文本切分成具有独立意义的词语。
import pandas as pd
import jieba
基本处理
打开当前文本然后起几个列名字,因为是中文,所以指定成utf-8的文字格式
import pandas as pd # 导入pandas库,用于数据处理
# 读取文本文件,并指定列名
df_news = pd.read_table(
'./data/val.txt', # 文件路径
names=['category', 'theme', 'URL', 'content'], # 指定列名
encoding='utf-8' # 指定文件编码格式为UTF-8
)
# 删除含有缺失值的行
df_news = df_news.dropna()
# 显示数据框的前5行,用于检查数据
df_news.head()```
```python
# 获取DataFrame的形状,即行数和列数
df_news_shape = df_news.shape
2.分词:实用结巴分词器
因为结巴分词器要求输入的是list格式,所以要转成list格式
# 将DataFrame中'content'列的数据转换为列表
content = df_news['content'].values.tolist()
# 打印列表中索引为1000的元素,即DataFrame中'content'列的第1001条记录
print(content[1000])
下面这段代码通过jieba库对文本内容进行分词处理,并将分词后的结果存储在一个新的列表中。在添加分词结果到列表之前,它检查分词后的列表长度是否大于1,以确保不是空行或只有一个词的行。这样做是为了排除那些没有实际内容的行。
content_S = [] # 初始化一个空列表,用于存储分词后的结果
# 遍历原始内容列表中的每一行
for line in content:
# 使用jieba库进行分词,返回分词后的列表
current_segment = jieba.lcut(line)
# 检查分词后的结果是否包含多个词(即长度大于1)并且不是空行(即不是'\r\n')
if len(current_segment) > 1 and current_segment != '\r\n':
# 如果条件满足,将当前分词结果添加到content_S列表中
content_S.append(current_segment)
这段代码创建了一个新的pandas DataFrame,其中包含一个名为’content_S’的列,该列存储了之前通过jieba分词处理后的文本内容。使用head()函数可以快速查看DataFrame的前5行数据,以确认分词结果是否正确。
# 创建一个新的DataFrame,其中包含分词后的内容
df_content = pd.DataFrame({'content_S': content_S})
# 显示新创建的DataFrame的前5行,用于检查分词后的数据
df_content.head()
3.清洗
使用停用词表去掉那些垃圾词
# 读取停用词文件,将其转换为DataFrame
stopwords = pd.read_csv(
"stopwords.txt", # 停用词文件的路径
index_col=False, # 不将任何一列设为索引
sep="\t", # 文件中的分隔符为制表符
quoting=3, # 引用模式3,忽略双引号
names=['stopword'], # 为DataFrame指定列名
encoding='utf-8' # 文件编码格式为UTF-8
)
# 显示前20个停用词,用于检查停用词列表
stopwords.head(20)
这段代码定义了一个drop_stopwords函数,该函数接受文本内容和停用词列表作为输入,并返回清理后的文本内容和所有非停用词。清理过程包括移除每一行中的停用词,并将非停用词添加到新的列表中。最后,通过调用这个函数并传入相应的参数,得到清理后的文本和词列表。
# 定义一个函数,用于移除文本中的停用词
def drop_stopwords(contents, stopwords):
contents_clean = [] # 初始化一个列表,用于存储清理后的文本
all_words = [] # 初始化一个列表,用于存储所有非停用词
# 遍历文本中的每一行
for line in contents:
line_clean = [] # 初始化一个列表,用于存储清理后的当前行
# 遍历当前行中的每一个词
for word in line:
# 如果这个词是停用词,则跳过
if word in stopwords:
continue
# 否则,将这个词添加到清理后的当前行列表中
line_clean.append(word)
# 同时,将这个词添加到所有非停用词列表中
all_words.append(str(word))
# 将清理后的当前行添加到清理后的文本列表中
contents_clean.append(line_clean)
# 返回清理后的文本列表和所有非停用词列表
return contents_clean, all_words
#print (contents_clean) # 注释掉,不执行打印操作
# 将DataFrame中的文本内容转换为列表
contents = df_content.content_S.values.tolist()
# 将停用词DataFrame中的停用词转换为列表
stopwords = stopwords.stopword.values.tolist()
# 调用drop_stopwords函数,传入文本内容和停用词列表,获取清理后的文本和所有非停用词
contents_clean, all_words = drop_stopwords(contents, stopwords)
这里面有些字母,也没啥意义,建议在停用词表中去掉。
下面这段代码将之前从文本中提取的所有非停用词列表转换为一个pandas DataFrame,其中包含一个名为’all_words’的列。使用head()函数可以快速查看DataFrame的前5行数据,以确认非停用词列表是否正确地被加载和展示。
# 创建一个新的DataFrame,其中包含所有非停用词
df_all_words = pd.DataFrame({'all_words': all_words})
# 显示新创建的DataFrame的前5行,用于检查包含所有非停用词的数据
df_all_words.head()
下面这段代码的目的是统计文本中每个非停用词的出现次数,并按照出现次数从高到低进行排序,最后查看出现次数最多的几个词。这在文本分析中是一个常见的步骤,用于理解文本的主要内容和关键词。
import numpy # 导入numpy库,用于数据处理
# 创建一个新的DataFrame,其中包含所有非停用词
df_all_words = pd.DataFrame({'all_words': all_words})
# 显示新创建的DataFrame的前5行,用于检查包含所有非停用词的数据
df_all_words.head()
# 使用groupby对所有的词进行分组,并计算每个词出现的次数
# 直接使用numpy.size作为聚合函数,而不是一个字典
words_count = df_all_words.groupby(by=['all_words']).size().reset_index(name='count')
# 按照词出现的次数进行降序排序
words_count = words_count.sort_values(by=["count"], ascending=False)
# 显示排序后的前5行数据,查看出现次数最多的词
words_count.head()
然后导入词云这样的差距 实现可视化的一个操作,开源地址是这个https://github.com/amueller/word_cloud
from wordcloud import WordCloud # 导入WordCloud库,用于生成词云
import matplotlib.pyplot as plt # 导入matplotlib.pyplot库,用于绘制图表
# 启用matplotlib的inline模式,以便在Jupyter笔记本中直接显示图表
%matplotlib inline
import matplotlib # 导入matplotlib库,用于设置图表的显示参数
# 设置matplotlib图表的默认大小为宽度10.0,高度5.0
matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)
# 创建一个WordCloud对象,设置字体路径、背景颜色和最大字体大小
wordcloud = WordCloud(font_path="./data/simhei.ttf", background_color="white", max_font_size=80)
# 从words_count DataFrame中提取出现次数最多的前100个词及其频率
word_frequence = {x[0]: x[1] for x in words_count.head(100).values}
# 将提取的词频数据传递给WordCloud对象,生成词云
wordcloud = wordcloud.fit_words(word_frequence)
# 使用matplotlib显示生成的词云图像
plt.imshow(wordcloud)
4.TF-IDF
使用jieba.analyse.extract_tags方法提取content_S_str中的前5个关键词,并打印这些关键词。extract_tags方法允许指定要提取的关键词数量(通过topK参数)和是否包含权重(通过withWeight参数)。在这个例子中,我们不包含权重,只打印关键词。
import jieba.analyse # 导入jieba.analyse模块,用于文本分析
# 定义一个变量,用于存储索引位置
index = 2400
# 打印DataFrame中指定索引位置的'content'列的文本内容
print(df_news['content'][index])
# 将content_S列表中指定索引位置的文本内容合并为一个字符串
content_S_str = "".join(content_S[index])
# 使用jieba.analyse.extract_tags方法提取指定文本内容中的前5个关键词,不包含权重
# topK参数指定要提取的关键词数量,withWeight参数指定是否包含权重
print(" ".join(jieba.analyse.extract_tags(content_S_str, topK=5, withWeight=False)))
5.LDA:主题模型
LDA是一种强大的文本分析工具,能够揭示文档中的潜在主题结构。它广泛应用于自然语言处理和信息检索领域,为文本数据的挖掘和分析提供了新的视角和方法。格式要求:list of list形式,分词好的的整个语料
Gensim:Gensim 是一个 Python 库,主要用于处理和分析大规模的文本数据集。它提供了许多文本处理和信息提取的工具,例如词嵌入(Word Embedding)、主题建模(Topic Modeling)、命名实体识别(Named Entity Recognition)等。Gensim 特别适合于处理大规模的文本数据集,因为它提供了高效的算法和工具来处理和分析这些数据。
from gensim import corpora, models, similarities
import gensim
# 导入Gensim库的必要部分
# corpora模块用于处理和操作语料库
# models模块包含了一些预定义的模型,如LDA、TF-IDF等
# similarities模块包含了一些相似性度量方法,如余弦相似性
# 创建一个Dictionary对象,它用于存储词汇和它们的索引
# 这里的contents_clean是一个列表,其中包含已经清理过的文本内容
dictionary = corpora.Dictionary(contents_clean)
# 使用doc2bow方法将文档转换为BOW(Bag of Words)向量形式
# 这里的contents_clean是一个列表,其中包含已经清理过的文本内容
corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean]
导入LDA 模块,语料传进来,映射字典传进来,指定的主题值越准越好 ,因为是无监督的,所以要自己指定。
# 导入Gensim库的LDA模型模块
from gensim import models
# 创建一个LdaModel对象,用于训练LDA模型
# corpus参数是一个包含文档的列表,其中每个文档是一个词袋向量
# id2word参数是一个Dictionary对象,它包含词汇和它们的索引
# num_topics参数指定要生成的主题数量
lda = models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20)
这段代码首先打印了LDA模型中第一个主题的前5个关键词及其权重。然后,通过一个循环遍历了LDA模型中的所有主题,并打印了每个主题的前5个关键词及其权重。这样可以帮助我们更好地理解每个主题所代表的含义,从而为文本分类、关键词提取等任务提供指导。
# 打印第一个主题的关键词及其权重
# lda.print_topic(1, topn=5) 表示打印编号为1的主题,并且只打印前5个关键词
print(lda.print_topic(1, topn=5))
# 打印所有主题的关键词及其权重
# for topic in lda.print_topics(num_topics=20, num_words=5):
# 循环遍历lda模型中的所有主题
# num_topics参数指定要打印的主题数量
# num_words参数指定每个主题要打印的关键词数量
# 打印当前主题的关键词及其权重
for topic in lda.print_topics(num_topics=20, num_words=5):
print(topic[1])
6.贝叶斯算法分类
'contents_clean’列存储了清理后的文本内容,而’label’列存储了每个文本对应的类别标签。最后,代码使用tail()函数显示DataFrame的最后几行,以检查数据的完整性。
# 导入pandas库,用于数据处理
import pandas as pd
# 创建一个新的DataFrame,其中包含清理后的文本内容和对应的标签
# 'contents_clean'列存储清理后的文本内容
# 'label'列存储每个文本对应的类别标签 category列就是对应的标签列
df_train = pd.DataFrame({'contents_clean': contents_clean, 'label': df_news['category']})
# 显示DataFrame的最后几行,用于检查数据的完整性
df_train.tail()
# 打印DataFrame中'label'列的唯一值,以查看标签的种类
print(df_train.label.unique())
# 定义一个字典,将文本标签映射为数字标签
# 例如,"汽车"映射为1,"财经"映射为2,依此类推
label_mapping = {"汽车": 1, "财经": 2, "科技": 3, "健康": 4, "体育": 5, "教育": 6, "文化": 7, "军事": 8, "娱乐": 9, "时尚": 0}
# 使用map方法将DataFrame中的'label'列的文本标签映射为数字标签
# 使用上述定义的字典作为映射表
df_train['label'] = df_train['label'].map(label_mapping)
# 显示映射后的DataFrame的前几行,以查看标签的映射结果
df_train.head()
划分测试集和训练集
# 导入sklearn.model_selection模块中的train_test_split函数
from sklearn.model_selection import train_test_split
# 使用train_test_split函数将数据集划分为训练集和测试集
# x_train和x_test分别存储训练集和测试集的文本内容
# y_train和y_test分别存储训练集和测试集的标签
x_train, x_test, y_train, y_test = train_test_split(
df_train['contents_clean'].values, # 输入数据集的文本内容
df_train['label'].values, # 输入数据集的标签
random_state=1 # 设置随机状态,确保每次运行时分割结果一致
)
试将训练集的文本内容转换为一个单词列表,并存储在变量 words 中。
# 初始化一个空列表,用于存储转换后的单词列表
words = []
# 遍历训练集的每个文档
for line_index in range(len(x_train)):
# 尝试将当前文档的单词列表添加到words列表中
try:
# 将当前文档的单词列表转换为一个字符串,并添加到words列表中
words.append(' '.join(x_train[line_index]))
except:
# 如果转换过程中出现异常,打印出发生异常的文档索引和单词索引
print(line_index, word_index)
# 打印words列表中的第一个元素,以检查转换是否成功
print(words[0])
下面这段代码是简单演示下sklearn的构造向量的输入长什么样
用空格来分词,逗号分隔文章,代码如下
from sklearn.feature_extraction.text import CountVectorizer
texts = ["dog cat fish","dog cat cat","fish bird", 'bird']
cv = CountVectorizer()
cv_fit = cv.fit_transform(texts)
# 获取特征名称(即词的列表)
feature_names = cv.get_feature_names_out()
# 打印特征名称
print(feature_names)
# 打印转换后的词频向量
print(cv_fit.toarray())
# 打印词频向量的列之和
print(cv_fit.toarray().sum(axis=0))
结果如图,第一篇文章bird出现0,cat出现1,dog出现1,fish出现1 依此类推
那么同理,使用下面代码进行构造向量
from sklearn.feature_extraction.text import CountVectorizer
# 创建一个CountVectorizer对象
# analyzer参数指定如何分析文本,这里指定为'word',即只考虑单词
# max_features参数指定最大特征数量,这里设置为4000
# lowercase参数指定是否将文本转换为小写,这里设置为False
vec = CountVectorizer(analyzer='word', max_features=4000, lowercase=False)
# 使用fit方法训练CountVectorizer,使用words数据集
# fit方法会学习单词和它们的频率,并创建一个模型
vec.fit(words)
然后对文本作一个分类器
from sklearn.naive_bayes import MultinomialNB
# 导入Multinomial Naive Bayes分类器
# MultinomialNB适用于文本数据,它假设特征的分布是多项式的
classifier = MultinomialNB()
# 创建一个Multinomial Naive Bayes分类器实例
# 默认情况下,它将使用多项式估计,并假设特征的分布是多项式的
classifier.fit(vec.transform(words), y_train)
# 使用fit方法训练分类器
# 参数vec.transform(words)将words数据集转换为词频向量
# y_train是训练数据集的标签,它应该是一个包含标签的列表或数组
同样对测试集预处理,注意,测试集和训练集预处理要一样
test_words = []
for line_index in range(len(x_test)):
try:
#x_train[line_index][word_index] = str(x_train[line_index][word_index])
test_words.append(' '.join(x_test[line_index]))
except:
print (line_index,word_index)
test_words[0]
classifier.score(vec.transform(test_words), y_test)
测试分0.804
上面的是基本的贝叶斯,那么实用TFI-DF预测代码如下
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(analyzer='word', max_features=4000, lowercase = False)
vectorizer.fit(words)
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vectorizer.transform(words), y_train)
classifier.score(vectorizer.transform(test_words), y_test)
测试分0.8152