logo

NLP-情感分析

王哲峰 / 2022-04-05


目录

情感分析简介

情感分析介绍

随着互联网的飞速发展, 越来越多的互联网用户从单纯的信息受众, 变为互联网信息制造的参与者。互联网中的博客、微博、论坛、 评论等这些主观性文本可以是用户对某个产品或服务的评价, 或者是公众对某个新闻事件或者政策的观点。

潜在的消费者在购买某个产品或者服务时获取相关的评论可以作为决策参考, 政府部门也可以浏览公众对新闻事件或政策的看法了解舆情。 这些主观性的文本对于决策者制定商业策略或者决策都非常重要, 而以往仅靠人工监控分析的方式不仅耗费大量人工成本, 而且有很强的滞后性。 因此采用计算机自动化情感分析称为目前学术界和工业界的大趋势。 目前, 情感分析在实际生产场景中得到越来越多的应用。

情感分析技术要点

情感分析应用

情感分析的基本方法

根据分析载体的不同, 情感分析会涉及到很多主题, 包括电影评论、商品评论, 以及新闻和博客等的情感分析。 大多数情感分析研究都使用机器学习方法。

词法分析

词法分析运用了由预标记词汇组成的字典, 使用词法分析器将输入文本转换为单词序列。 将每一个新的单词与字典中的词汇进行匹配。如果有一个积极的匹配, 分数加到输入文本的分数总池中。 相反, 如果有一个消极的匹配, 输入文本的总分会减少。虽然这项技术感觉有些业余, 但已被证明是有价值的。 词法分析技术的工作方式如下图:

img

文本的分类取决于文本的总得分。目前有大量的工作致力于度量词法信息的有效性。对于单个短语, 通过手动标记词汇(仅包含形容词)的方式, 大概能达到 85% 的准确性。这是由评价文本的主观性所决定的。

词法分析也存在一个不足:其性能(时间复杂度和准确率)会随着字典大小(词汇的数量)的增加而迅速下降。

机器学习方法

在情感分析中, 主要使用的是监督学习方法。在训练过程中, 需要提供一个标记语料库作为训练数据。 分类器使用一系列特征向量对目标数据进行分类。

通常来说, unigram(单个短语)、bigrams(两个连续的短语)、trigrams(三个连续的短语)都可以被选为特征向量。 当然还有其他一些特征, 如积极词汇的数量、消极词汇的数量、文档的长度等。

支持向量机(SVM)、朴素贝叶斯(NB)算法、卷积神经网络(CNN)等都可以作为分类器使用。

机器学习技术面临很多挑战:分类器的设计、训练数据的获取、对一些未见过的短语的正确解释。 相比词汇分析方法, 它在字典大小呈指数增长的时候依然工作得很好。

混合分析

情感分析研究的进步吸引大量研究者开始探讨将两中方法进行组合的可能性, 即可以利用机器学习方法的高准确性, 又可以利用词法分析快速的特点。

情感分析示例

载入数据

IMDB 情感分析数据

评价标签阈值表

标签 分数
负面评价 $\leq 4
正面评价 $\geq 7

示例:

import os
from os.path import isfile, join
import re
import numpy as np
from random import randint
import tensorflow as tf
import config


batch_size = 24
lstm_units = 64
num_labels = 2
iterations = 100
lr = 0.001


def load_wordsList():
    """
    载入词典, 该词典包含 400000 个词汇
    """
    wordsList = np.load(os.path.join(config.root_dir, 'wordsList.npy'))
    print("-" * 20)
    print('载入word列表...')
    print("-" * 20)
    wordsList = wordsList.tolist()
    wordsList = [word.decode('UTF-8') for word in wordsList]

    return wordsList


def load_wordVectors():
    """
    载入已经训练好的词典向量模型, 该矩阵包含了的文本向量, 维度: (400000, 50)
    """
    wordVectors = np.load(os.path.join(config.root_dir, 'wordVectors.npy'))
    print("-" * 20)
    print('载入文本向量...')
    print("-" * 20)

    return wordVectors


def load_idsMatrix():
    """
    
    """
    ids = np.load(os.path.join(config.root_dir, 'idsMatrix.npy'))

    return ids


def postive_analysis():
    """
    载入正面数据集
    """
    pos_files = [config.pos_data_dir + f for f in os.listdir(config.pos_data_dir) if isfile(join(config.pos_data_dir, f))]
    num_words = []
    for pf in pos_files:
        with open(pf, "r", encoding='utf-8') as f:
            line = f.readline()
            counter = len(line.split())
            num_words.append(counter)
    print("-" * 20)
    print('正面评价数据加载完结...')
    print("-" * 20)
    num_files = len(num_words)
    print('正面评价数据文件总数', num_files)
    print('正面评价数据所有的词的数量', sum(num_words))
    print('正面评价数据平均文件词的长度', sum(num_words) / len(num_words))
    
    return pos_files


def negtive_analysis():
    """
    载入负面数据集
    """
    neg_files = [config.neg_data_dir + f for f in os.listdir(config.neg_data_dir) if isfile(join(config.neg_data_dir, f))]
    num_words = []
    for nf in neg_files:
        with open(nf, "r", encoding='utf-8') as f:
            line = f.readline()
            counter = len(line.split())
            num_words.append(counter)
    print("-" * 20)
    print('负面评价数据加载完结...')
    print("-" * 20)
    num_files = len(num_words)
    print('负面评价数据文件总数', num_files)
    print('负面评价数据所有的词的数量', sum(num_words))
    print('负面评价数据平均文件词的长度', sum(num_words) / len(num_words))

    return neg_files


if __name__ == "__main__":
    # 词典
    wordsList = load_wordsList()
    print("词典中词汇数量:", len(wordsList))
    home_index = wordsList.index("home")
    print("'home' 单词在词典中的索引:", home_index)
    
    # 词典向量模型矩阵
    wordVectors = load_wordVectors()
    print("词典向量模型矩阵:", wordVectors.shape)
    print("'home' 在词典向量模型矩阵中的向量表示:", wordVectors[home_index])

    # 正面、负面文本数据
    pos_files = postive_analysis()
    neg_files = negtive_analysis()
def data_visual(num_words):
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    # mpl.use("qt4agg")
    # 指定默认字体
    mpl.rcParams["font.sans-serif"] = ["SimHei"]
    mpl.rcParams["font.family"] = "sans-serif"
    # %matplotlib inline
    plt.hist(num_words, 50, facecolor = "g")
    plt.xlabel("文本长度")
    plt.ylabel("频次")
    plt.axis([0, 1200, 0, 8000])
    plt.show()

if __name__ == "__main__":
    # 正面、负面文本数据
    pos_files, pos_num_words = postive_analysis()
    neg_files, neg_num_words = negtive_analysis()

    # 文本数据可视化
    num_total_words = pos_num_words + neg_num_words
    data_visual(num_total_words)

img

辅助函数

模型设置

调参配置

训练模型

$ tensorflow --logdir=tensorboard