本项目预期结果:

alt text

步骤一:导入评论数据

在5月6日课程中,我们已经获取了B站视频的前200条热门评论。
我们利用之前课程结果“B站评论.json”。
我们首先实现读取json文件内容:

import json
with open('B站评论.json', 'r', encoding='utf-8') as json_file:
    str_json = json.load(json_file)
print(str_json)

能看到,获取到了一个列表,每一项为一条评论内容。

步骤二:对每一条评论进行分词

构建一个循环,读出每一条评论内容

import jieba
import json
with open('B站评论.json', 'r', encoding='utf-8') as json_file:
    str_json = json.load(json_file)

for item in str_json:
    tokens = list(jieba.cut(item, cut_all=False))
    print(tokens)

可见,每次分词后得到一个列表,列表内容为分词结果。

但是!这样的结果是没有办法进行词频统计的。
多个列表没法很好的进行后续的词频统计,我们需要将结果整合到一个列表中

# ....
words_list = []
for item in str_json:
    tokens = list(jieba.cut(item, cut_all=False))
    # 结合成一个列表
    words_list.extend(tokens)
print(words_list)

words_list.extend() 和words_list.append()区别!重要!

我们之前都是使用append(),但是此处需要使用extend(),我们来做个辨析:
在Python中,extendappend都是用于向列表中添加元素的方法,但它们的作用和使用场景有所不同:

append

  • append方法用于在列表末尾添加一个元素。
  • 如果提供的参数是一个可迭代对象(如列表、元组、字符串等),append会将这个可迭代对象作为单个元素添加到列表中。

例如(只做展示,不用于此项目):

words_list = ['hello', 'world']
tokens = ['I', 'am', 'dl']
words_list.append(tokens)  # 将tokens作为一个元素添加到words_list中
print(words_list)  # 输出: ['hello', 'world', ['I', 'am', 'dl']]

extend

  • extend方法用于将一个可迭代对象的所有元素添加到列表末尾。
  • append不同,extend会将可迭代对象中的每个元素分别添加到列表中,而不是作为一个整体。

例如(只做展示,不用于此项目):

words_list = ['hello', 'world']
tokens = ['I', 'am', 'dl']
words_list.extend(tokens)  # 将tokens中的每个元素分别添加到words_list中
print(words_list)  # 输出: ['hello', 'world', 'I', 'am', 'dl']

结论

本项目中,由于每次分词结果都是一个列表。我们是希望将每个列表中的每个元素加入到新列表中,而不是将每个列表加入新列表!
所以此处使用 extend

步骤三:词频统计

词频统计(Word Frequency Count)是自然语言处理(NLP)和文本分析中的一项基本任务,它涉及计算文档或语料库中每个单词出现的次数。词频统计对于多种应用场景非常重要,包括但不限于:

  1. 文本摘要:通过识别出现频率高的单词,可以推断出文档中的关键主题或概念。
  2. 情感分析:某些词语的出现频率可能与文本的情感倾向有关。
  3. 关键词提取:高频率的单词可能是文档的关键词。
  4. 文本分类:词频可以作为文本分类器的特征之一。
  5. 语言模型:在构建语言模型时,词频统计有助于了解语言的使用模式。
  6. 信息检索:搜索引擎优化(SEO)和信息检索系统会利用词频数据来评估文档的相关性。

词频统计的步骤通常包括:

  1. 预处理:对文本进行清洗,包括去除标点符号、转换为小写(如果区分大小写的语言)、去除停用词(stop words,即在文本分析中通常不携带有用信息的常见词)等。
  2. 分词:将文本分割成单词或词汇单元。
  3. 计数:对每个单词出现的次数进行计数。这通常通过创建一个字典(或哈希表)来完成,其中键是单词,值是该单词出现的次数。
  4. 排序:根据计数结果对单词进行排序,以识别最常见的单词。
  5. 可视化:有时,词频统计的结果会通过条形图、饼图等形式进行可视化展示。

collections库

我们进行词频统计需要用到collections 库
Counter是一个非常实用的类,用于快速进行词频统计。提供了丰富的方法来处理计数数据,是Python中处理计数问题的一个非常有用的工具。

示例代码(只做展示,不用于此项目):

from collections import Counter
# 假设我们有以下文本
text = "hello world hello universe"
# 分词
words = text.split()
# 使用Counter进行词频统计
word_counts = Counter(words)
# 输出词频统计结果
print(word_counts)

输出将是:

Counter({'hello': 2, 'world': 1, 'universe': 1})

这表明在给定的文本中,“hello”出现了两次,“world”和“universe”各出现了一次。

collections库的使用

在原先代码的基础上:

# ...
# 使用Counter进行词频统计
word_counts = Counter(words_list)
# 输出词频统计结果
print(word_counts)

alt text
可见,结果是Counter 对象,属于一种特殊的字典。
Counter 对象的一些特性包括:

  • 元素的计数是整数值:每个键对应的值都是一个非负整数,表示该元素出现的次数。
  • 无序性:Counter 是一个无序的集合
    由图可知,当前结果存在几个重要的问题:
  1. 统计了标点符号,这本没有任何意义
  2. 统计许多“停用词”,这也没有意义
    这就牵扯到词频分析的“预处理”了

步骤四:数据预处理,去除停用词

在自然语言处理(NLP)中,停用词(Stop Words)是指在文本处理时通常会被忽略的词汇,因为它们对于文本分析和理解通常贡献不大。这些词包括但不限于:

  1. 常见虚词:如“的”、“和”、“是”等,在中文中这些词非常常见,但在理解句子的主要意思时通常不是关键。
  2. 介词:如“在”、“对”、“关于”等,它们用于构建句子结构,但往往不携带关键信息。
  3. 连词:如“和”、“或”、“但是”等,它们用于连接句子或子句,但本身不包含具体内容。
  4. 助词:如“了”、“的”、“地”、“得”等,用于辅助句子的语气或时态,但通常不作为信息的载体。
  5. 冠词:如英文中的“a”、“an”、“the”等,在中文中没有冠词,但概念相似。
  6. 代词:如“我”、“你”、“他”等,虽然它们在某些情况下可以携带重要信息,但在进行词频统计或某些文本分析时,可能会被考虑作为停用词。
  7. 量词:如“个”、“只”、“件”等,它们用于计数,但在分析文本的主题时可能不是关键。
  8. 感叹词:如“哦”、“啊”、“嗯”等,通常用于表达情感,但在文本分析中可能不被视为重要。
  9. 填充词:如“呃”、“嗯”等,这些词在口语中常用,但在书面文本分析中通常没有太大价值。
  10. 各种符号:如,.,。等
    在进行文本挖掘、搜索引擎优化、文本分类、情感分析等任务时,去除停用词可以减少噪声,提高处理效率和准确性。然而,是否将某些词视为停用词,以及停用词的具体列表,往往取决于具体的应用场景和分析目标。

使用现有的停用词列表(网上找的,还是很全的)

stopwords.txt

在现实项目中可以根据情况进行自定义添加或删除。

创建并导入停用词列表

stopwords_path = 'stopwords.txt'
stopwords = set()
with open('stopwords.txt', 'r', encoding='utf-8') as file_stopwords:
    for line in file_stopwords:
        stopwords.add(line.strip())
print(stopwords)

这段代码是用来创建一个停用词集合(stopwords),它将包含从指定文件中读取的停用词。下面是代码的逐行解释:

  1. stopwords_path = 'stopwords.txt':这行代码定义了一个变量 stopwords_path,它的值是一个字符串 'stopwords.txt',这个字符串是包含停用词的文本文件的名称。这个文件应该位于与你的Python脚本相同的目录中,或者你需要提供文件的完整路径。
  2. stopwords = set():这里初始化了一个空的集合(set),用来存储后续读取的停用词。集合是一个无序的不重复元素集,适合用来存储唯一性重要的数据,如停用词。
  3. with open('stopwords.txt', 'r', encoding='utf-8') as file_stopwords::这行代码以只读模式('r')打开名为 'stopwords.txt'的文件,并指定文件编码为 'utf-8',这对于处理包含中文或其他非ASCII字符的文件是必要的。with语句是一个上下文管理器,它确保文件在使用后会被正确关闭,即使在读取文件过程中发生异常也是如此。
  4. for line in file_stopwords::这个 for循环遍历文件 file_stopwords中的每一行。在Python中,文件默认以读取模式打开时,for line in file会自动逐行读取文件,其中 line是包括换行符的字符串。
  5. stopwords.add(line.strip()):在循环体内,这行代码使用 strip()方法移除每一行字符串两端的空白字符(包括空格、制表符、换行符等),然后将处理后的单词添加到 stopwords集合中。由于集合不允许有重复的元素,即使文件中的停用词有重复,它们在集合中也只会存储一次。
    最终,stopwords集合包含了文件 'stopwords.txt'中定义的所有停用词,每个停用词都是唯一的,并且没有前后的空白字符。这个集合可以用于后续的文本处理,例如在进行词频统计之前移除文本中的停用词。

在词频分析前对停用词进行过滤

对之前的代码进行更改:

words_list = []
for item in str_json:
    # 分词
    tokens = list(jieba.cut(item, cut_all=False))
    # tokens结果是 ['您好', ',', '我', '是', '衡水二中', '的', '一', '名', '学生']
    filtered_tokens = []
    for token in tokens:
      # token在 '您好' ',' ...中循环。
        if token not in stopwords:
          # 将不在停用词表中的添加如过滤后列表
            filtered_tokens.append(token)
    # 将过滤后的分词结果添加到words_list
    words_list.extend(filtered_tokens)

结果为:
alt text
可见结果基本符合预期。

步骤五:利用词云将结果可视化

纯数据的词频结果,既不直观也不好看。一般我们使用词云进行数据的可视化。
要创建一个词云,您需要使用一个可以生成词云的库,比如 wordcloud
wordcloud 是一个流行的Python库,用于生成词云,即根据文本数据中的词频以不同大小显示单词的视觉表现形式。词云通过图形化的方式展示文本中各个单词的重要性,通常词频越高的单词在词云中显示得越大,位置也越显著。

以下是 wordcloud 库的一些关键特性:

  1. 多种布局形状:允许用户自定义词云的形状,如矩形、圆形,甚至可以使用自己的图片作为模板。
  2. 颜色和背景:支持设置词云的颜色方案和背景颜色。
  3. 字体选择:可以指定字体文件,对于生成中文词云等非拉丁字符的词云尤为重要。
  4. 词频统计:可以直接从词频统计(如 Counter 对象)或原始文本生成词云。
  5. 停用词过滤:允许排除一些不需要显示在词云中的单词。
  6. 可定制性:提供多种参数调整,如最大词数、字体大小、词云尺寸等。
  7. 易于使用:具有简单的API,可以快速生成词云。
  8. 可视化:生成的词云可以保存为图片或直接在Jupyter Notebook中展示。
  9. 兼容性:与常见的Python可视化库如 matplotlib 兼容,方便集成和展示。
    安装 wordcloud 库通常可以通过 pip 进行:
pip install wordcloud

引入库

from wordcloud import WordCloud
import matplotlib.pyplot as plt

设置WordCloud类

wordcloud = WordCloud(
    font_path='C:\\Windows\\Fonts\\HGWT_CNKI.TTF',
    width=1200,
    height=800,
    background_color='white'
)

注意!WordCloud库,不带中文字体!!必须手动指定!

  1. font_path: 这个参数指定了生成词云时使用的字体文件的路径。对于中文词云来说,需要使用支持中文字符的字体文件。这里指定的是 Windows 系统中常见的 HGWT_CNKI.TTF 字体,位于 C:\Windows\Fonts 目录下。如果您在其他操作系统上生成词云,需要选择一个合适的支持中文的字体文件。
  2. widthheight: 这两个参数分别定义了生成词云图片的宽度和高度,单位是像素。这里设置的宽度为 1200 像素,高度为 800 像素。较大的尺寸可以使得词云更加清晰,但同时也会增加计算和渲染的时间。
  3. background_color: 这个参数定义了词云的背景颜色。这里设置为 'white',即白色背景。您也可以选择其他颜色,如 'black'(黑色)等,这会影响词云的整体视觉效果。

显示图片

这里我们又用到了“老朋友”matplotlib

# 绘制词云图
plt.figure(figsize=(12, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')  # 去除坐标轴
plt.savefig('ciyun.png')

其中interpolation=‘bilinear’ 是 imshow() 函数的一个参数,它定义了图像插值的方法。插值是在图像放大或缩小时用来计算像素值的一种算法。‘bilinear’ 表示双线性插值,它在放大图像时可以提供平滑的边缘,减少锯齿效应。这对于词云图像尤其重要,因为词云中的文字边缘通常很细,使用适当的插值方法可以避免文字边缘出现不美观的锯齿。
结果如下:
alt text

存在以下问题:

  1. 评论中高频出现“罗老师”,“罗翔”,但是分词的时候会将其拆分成“罗”,“老师”
  2. 结果中“读”,“非”,“弹幕”,“太”等等。这些词其实是没有必要的。

步骤六: 优化结果

固定特有词

jieba.load_userdict('userdict.txt')

临时加入停用词

可以直接更改停用词文件,但有时候,只是需要在这个项目中临时加入一些停用词如:“弹幕”
这时候建议使用以下办法:

stopwords.add('\n')

结果

import jieba
import json
from collections import Counter
from wordcloud import WordCloud
import matplotlib.pyplot as plt

# 加载自定义词典
jieba.load_userdict('userdict.txt')
# 读取JSON文件
with open('B站评论—胖猫-另1.json', 'r', encoding='utf-8') as json_file:
    str_json = json.load(json_file)

stopwords_path = 'stopwords.txt'
stopwords = set()
with open(stopwords_path, 'r', encoding='utf-8') as file_stopwords:
    for line in file_stopwords:
        stopwords.add(line.strip())
stopwords.add(' ')
stopwords.add('\n')
words_list = []
for item in str_json:
    # 使用jieba进行分词
    tokens = list(jieba.cut(item, cut_all=False))
    filtered_tokens = []
    for token in tokens:
        if token not in stopwords:
            filtered_tokens.append(token)
    words_list.extend(filtered_tokens)

# print(words_list)
word_counts = Counter(words_list)
print(word_counts)
wordcloud = WordCloud(
    font_path='C:\\Windows\\Fonts\\HGWT_CNKI.TTF',
    width=1200,
    height=800,
    background_color='white'
)
wordcloud.generate_from_frequencies(word_counts)
# 绘制词云图
plt.figure(figsize=(12, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')  # 去除坐标轴
plt.savefig('B站-ciyun-pangmao-另1.png')


alt text

后续

alt text
alt text