美文网首页
NLP笔记Day2:词频统计及可视化

NLP笔记Day2:词频统计及可视化

作者: Wi先森 | 来源:发表于2021-02-02 17:18 被阅读0次

    在本次练习中,我们主要实现build_freqs()函数,并且把数据喂进去看看可视化的结果。在整个推特情感分析项目中,这个函数的任务是构建一个字典。我们可以在字典里面查找每个词出现的次数。字典对于后续提取数据集的特征值是非常有帮助的。

    不单单是计算频次,而是计算一个单词,描述正向的次数和负向的次数。也就是说,当一个单词出现在一个句子时,这个句子更可能是在讲正向的话,还是负向的。

    导入库

    先来导入我们需要用到的库

    import nltk
    from nltk.corpus import twitter_samples
    import matplotlib.pyplot as plt
    import numpy as np
    

    导入两个在utils.py中定义好的函数

    • process_tweet() 数据清洗,分词函数
    • build_freqs() 计算一个单词关联正向或负向的频次,然后构建出 freqs 字典,其中的数据键是 (word, label),数据值是频次(一个数值)
    from nltk.book import *
    from utils import process_tweet, build_freqs
    
    *** Introductory Examples for the NLTK Book ***
    Loading text1, ..., text9 and sent1, ..., sent9
    Type the name of the text or sentence to view it.
    Type: 'texts()' or 'sents()' to list the materials.
    text1: Moby Dick by Herman Melville 1851
    text2: Sense and Sensibility by Jane Austen 1811
    text3: The Book of Genesis
    text4: Inaugural Address Corpus
    text5: Chat Corpus
    text6: Monty Python and the Holy Grail
    text7: Wall Street Journal
    text8: Personals Corpus
    text9: The Man Who Was Thursday by G . K . Chesterton 1908
    

    加载 NLTK 样本数据集

    像前一篇做数据预处理的步骤一样,先把数据加载到列表中来。在这个练习当中,加载数据非常简单,只需要一行命令。但我们在实际情况中会碰到多种数据源,比如:关系型数据库,非关系型数据库,接口如WebSerivices,文本,excel表格等等。因此许多从业人员也会抱怨,做数据科学80~90%的时间都花在了处理数据本身之上。

    all_positve_tweets = twitter_samples.strings('positive_tweets.json')
    all_negative_tweets = twitter_samples.strings('negative_tweets.json')
    
    tweets = all_positve_tweets + all_negative_tweets
    
    print("Number of tweets", len(tweets))
    
    Number of tweets 10000
    

    接下来,我们会创建一个标签数组(array),后续用于关联实际数据的情感。数组的使用跟列表差不多,但会更便于计算。
    这里labels数组共10000个元素,前5000个全是 ‘1‘ 代表正向情感,后5000个全是 ‘0‘ 代表负向。
    我们用numpy库来进行这样的处理。

    • np.ones() 创建全 1 数组
    • np.zeros() 创建全 0 数组
    • np.append() 连接数组
    # 分别给 np.ones() 和 np.zeros() 输入两个list的长度值,然后再连接到一块去
    labels = np.append(np.ones((len(all_positve_tweets))), np.zeros((len(all_negative_tweets))))
    # 显示出来看看更直观
    labels
    
    array([ 1.,  1.,  1., ...,  0.,  0.,  0.])
    

    构建字典

    在Python,字典是可变的,被索引好的集合。它把每一个成员存储为 键-值对(key-value pairs),并使用哈希表来建立查找索引。这有利于在上千条数据中进行快速检索。

    定义

    Python字典的声明使用大括号

    dictionary = {'key1': 1, 'key2': 2}
    

    这里定义的字典包含两个条目,在这个例子里,我们使用了字符串类型,根据实际情况还可以是浮点数,整数,元组(tuple)等

    增加/修改入口

    用中括号可以对字典进行操作,如果字典键已存在,值会被覆盖

    # 增加新入口
    dictionary['key3'] = -5
    
    # 覆盖值
    dictionary['key1'] = 0
    
    print(dictionary)
    
    {'key1': 0, 'key2': 2, 'key3': -5}
    

    访问值和查找键

    对字典进行检索和提取是常用操作,建议反复练习,这里有两个方法:

    • 使用中括号:键已存在时用,若键不存在则报错
    • 使用get()函数:如果值不存在,则可以存在一个默认值
    # 中括号查找
    print(dictionary['key2'])
    
    2
    

    我们来试试报错的情况,查找一个不存在的键

    print(dictionary['key666'])
    
    ---------------------------------------------------------------------------
    
    KeyError                                  Traceback (most recent call last)
    
    <ipython-input-8-3e8f34e21792> in <module>()
    ----> 1 print(dictionary['key666'])
    
    
    KeyError: 'key666'
    

    在使用中括号进行检索时,一个常用的办法是通过条件语句来处理键是否能被找到的问题。或者你也可以使用get()函数来为找不到的键生成一个默认值。

    if 'key1' in dictionary:
        print("item found: ", dictionary['key1'])  # 输出 key1 对应的值为:0
    else:
        print('key1 is not defined')
    
    print("item found: ", dictionary.get('key1', -1)) # 同上,若 key1 没有对应值才会输出 -1 
    
    item found:  0
    item found:  0
    
    if 'key7' in dictionary:
        print(dictionary['key7'])
    else:
        print('key does not exists') # 字典中没有 key7 因此会输出这一行
    
    print(dictionary.get('key7', -1)) # 字典中没有 key7 所以会直接给 key7 一个默认值为 -1
    print(dictionary['key7']) # 最后的报错意味着上一步get()的执行并没有给字典赋值
    
    key does not exists
    -1
    
    
    
    ---------------------------------------------------------------------------
    
    KeyError                                  Traceback (most recent call last)
    
    <ipython-input-10-ff9ae431bf94> in <module>()
          5 
          6 print(dictionary.get('key7', -1)) # 字典中没有 key7 所以会直接给 key7 一个默认值为 -1
    ----> 7 print(dictionary['key7']) # 最后的报错意味着上一步get()的执行并没有给字典赋值
    
    
    KeyError: 'key7'
    

    词频统计

    下面我们一起来看看 build_freqs() 函数是如何实现的

    def build_freqs(tweets, ys):
        """Build frequencies.
        Input:
            tweets: a list of tweets
            ys: an m x 1 array with the sentiment label of each tweet
                (either 0 or 1)
        Output:
            freqs: a dictionary mapping each (word, sentiment) pair to its
            frequency
        """
        # Convert np array to list since zip needs an iterable.
        # The squeeze is necessary or the list ends up with one element.
        # Also note that this is just a NOP if ys is already a list.
        yslist = np.squeeze(ys).tolist()
    
        # Start with an empty dictionary and populate it by looping over all tweets
        # and over all processed words in each tweet.
        freqs = {}
        for y, tweet in zip(yslist, tweets):
            for word in process_tweet(tweet):
                pair = (word, y)
                if pair in freqs:
                    freqs[pair] += 1
                else:
                    freqs[pair] = 1
        
        return freqs
    

    如前所述,你也可以使用get()函数处理键值匹配问题,如:

        for y, tweet in zip(yslist, tweets):
            for word in process_tweet(tweet):
                pair = (word, y)
                freqs[pair] = freqs.get(pair, 0) + 1
    

    如上所示,(word, y) 是一对键-值。word是被处理后的推特数据,而y则是对应正向/负向的标记,即1或0。例如:

        # "folowfriday" 在正向推特中出现了 25 次
        ('followfriday', 1.0): 25
    
        # "shame" 在负向推特中出现了 19 次
        ('shame', 0.0): 19 
    

    到这里,或者你就能够理解自然语言为何如此难,因为人类表达中独有的诸如先抑后扬,用负面词汇表达正向情感等。
    例如,一款好玩的游戏,我们常常会说“有毒”,但“有毒”这一词在通常情况下又是负面的。
    人类语言(特别是中文)这样的特性让机器“理解”语言变得尤为困难。

    下面,我们就来看看build_freqs()函数返回的字典长什么样子

    freqs = build_freqs(tweets, labels)
    
    print(f'type(freqs) = {type(freqs)}')  # print的一种用法,把大括号执行语句的输出,跟前面的字符串合并起来
    
    print(f'len(freqs) = {len(freqs)}')
    
    type(freqs) = <class 'dict'>
    len(freqs) = 13076
    

    再把所有词的词频print出来看看

    print(freqs)
    
    {('followfriday', 1.0): 25, ......('misser', 0.0): 1}
    

    然而,这样的结果对于理解数据并没有带来太多帮助。更好的办法是对数据进行可视化。

    词频表格

    在可视化之后,把我们感兴趣的那部分数据放进一张临时表(table)是更好的办法。

    keys = ['happi', 'merri', 'nice', 'good', 'bad', 'sad', 'mad', 'best', 'pretti',
            '❤', ':)', ':(', '😒', '😬', '😄', '😍', '♛',
            'song', 'idea', 'power', 'play', 'magnific']
    
    data = []
    
    for word in keys:
    
        pos = 0
        neg = 0
    
        if (word, 1) in freqs:
            pos = freqs[(word, 1)]
        
        if (word, 0) in freqs:
            neg = freqs[(word, 0)]
        
        data.append([word, pos, neg])
    
    data
    
    [['happi', 211, 25],
     ['merri', 1, 0],
     ['nice', 98, 19],
     ['good', 238, 101],
     ['bad', 18, 73],
     ['sad', 5, 123],
     ['mad', 4, 11],
     ['best', 65, 22],
     ['pretti', 20, 15],
     ['❤', 29, 21],
     [':)', 3568, 2],
     [':(', 1, 4571],
     ['😒', 1, 3],
     ['😬', 0, 2],
     ['😄', 5, 1],
     ['😍', 2, 1],
     ['♛', 0, 210],
     ['song', 22, 27],
     ['idea', 26, 10],
     ['power', 7, 6],
     ['play', 46, 48],
     ['magnific', 2, 0]]
    

    这张表格看起来就清晰多了,更进一步,我们可以使用散点图来表示这些数据。
    我们不用原始数值来绘制,因为那会导致图样范围太大,取而代之我们在对数尺度上绘制,这样所有的计数更能够在一个维度上看清。

    例如,“:)” 有3568个计数为正,只有2个为负,对数取值后变为8.17和0.69。(想通过计算器验证的同学要用 ln 以自然对数e为底,而不是一般的以10为底的 log)

    我们还要在图上添加一条红线,标志正区域和负区域的边界。靠近红线的词可被归类为中性词。

    fig, ax = plt.subplots(figsize = (8,8))
    
    x = np.log([x[1] + 1 for x in data])
    
    y = np.log([x[2] + 1 for x in data])
    
    ax.scatter(x, y)
    
    plt.xlabel("Log Positive count")
    plt.ylabel("Log Negative count")
    
    for i in range(0, len(data)):
        ax.annotate(data[i][0], (x[i], y[i]), fontsize = 12)
    
    ax.plot([0,9], [0,9], color = 'red')
    plt.show()
    

    这张图很容易理解,特别是表情符号:(和:)在情感分析中似乎很重要。因此,在进行数据预处理时不能去掉这些符号。

    此外我们还看到,皇冠所表示的意义似乎还蛮消极的。

    感兴趣的同学建议可以试试把所有数据都放到图上来回发生什么。

    ChangeLog

    • 2021/2/2 09:59:22 完成1-2步骤
    • 2021/2/2 17:11:14 完成剩余步骤及理解

    相关文章

      网友评论

          本文标题:NLP笔记Day2:词频统计及可视化

          本文链接:https://www.haomeiwen.com/subject/lviytltx.html