自然语言处理--朴素贝叶斯-情感分析

朴素贝叶斯模型试图从一系列文档集合中寻找对目标(输出)变量有预测作用的关键词。当目标变量是要预测的情感时,模型将寻找那些能预测该情感的词。朴素贝叶斯模型的一个好处是,其内部的系数会将词或词条映射为类似于 VADER 中的情感得分。只有这时,我们才不必受限于让人来决定这些分数应该是多少,机器将寻找任何其认为的“最佳”得分。

from nlpia.data.loaders import get_data
import pandas as pd
from nltk.tokenize import casual_tokenize
from collections import Counter
from sklearn.naive_bayes import MultinomialNB

# 加载数据
movies = get_data('hutto_movies')
print(movies.head().round(2))
# 电影的评分区间在−4 到+4 之间
print(movies.describe().round(2))
# 使用分词器对所有电影评论文本进行切分,从而得到每篇评论文本的词袋,然后放入 Pandas DataFrame 中。
# 横向最多显示多少个字符,用于帮助在控制台更美观地显示较宽的 DataFrame
pd.set_option('display.width', 75)
bags_of_words = []
# NLTK 的casual_tokenize 可以更好地处理表情符号、不寻常的标点符号以及行业术语
# Python 内置的 Counter 的输入是一系列对象,然后对这些对象进行计数,并返回一
# 部字典,其中键是对象本身(这里是词条),值是这些对象计数后得到的整数值
for text in movies.text:
    bags_of_words.append(Counter(casual_tokenize(text)))
# DataFrame构造器from_records()的输入是一个字典的序列,它为所有键构建列,值被加入合适的列对应的表格中,
# 而缺失值用 NaN 进行填充
df_bows = pd.DataFrame.from_records(bags_of_words)
# Numpy 和 Pandas 只能用浮点对象来表示 NaN,因此一旦将所有 NaN 填充为 0,可以将 DataFrame 转换为整
# 数,这样在内存存储和显示上可以紧凑得多
df_bows = df_bows.fillna(0).astype(int)
# 词袋表格可能会快速增长到很大的规模,特别是在没有使用大小写归一
# 化、停用词过滤、词干还原和词形归并过程时更是如此。
print(df_bows.shape)
print(df_bows.head())
print(df_bows.head()[list(bags_of_words[0].keys())])

nb = MultinomialNB()
# 朴素贝叶斯是分类器,因此需要将输出的变量(代表情感的浮点数)转换成离散的
# 标签(整数、字符串或者布尔值)
nb = nb.fit(df_bows, movies.sentiment > 0)
# 将二值的分类结果变量(0 或 1)转换到−4 到+4 之间,从而能够和标准情感得分进行比较。
movies['predicted_sentiment'] = nb.predict(df_bows).astype(int) * 8 - 4
movies['error'] = (movies.predicted_sentiment - movies.sentiment).abs()
# MAE:平均预测错误绝对值
print(movies.error.mean().round(1))
movies['sentiment_ispositive'] = (movies.sentiment > 0).astype(int)
movies['predicted_ispositive'] = (movies.predicted_sentiment > 0).astype(int)
movies['''sentiment predicted_sentiment sentiment_ispositive predicted_ispositive'''.split()].head(8)
# 点赞评级的正确率是 93%
print((movies.predicted_ispositive == movies.sentiment_ispositive).sum() / len(movies))

# 外加上商品评论数据
# 加载数据
products = get_data('hutto_products')
bags_of_words = []
for text in products.text:
    bags_of_words.append(Counter(casual_tokenize(text)))
df_product_bows = pd.DataFrame.from_records(bags_of_words)
df_product_bows = df_product_bows.fillna(0).astype(int)
df_all_bows = df_bows.append(df_product_bows)
print(df_all_bows.columns)

df_product_bows = df_all_bows.iloc[len(movies):][df_bows.columns]
df_product_bows = df_product_bows.fillna(0).astype(int)
print(df_product_bows.shape)
print(df_bows.shape)
products['ispos'] = (products.sentiment > 0).astype(int)
products['pred'] = nb.predict(df_product_bows).astype(int)
print(products.head())
'''
上述朴素贝叶斯模型在预测商品评论是否正向(即点赞)时表现得很糟糕
1.一个原因是,利用 casual_tokenize 从商品文本中得到的词汇表中有 2546 个词条
不在电影评论中。这个数目大概是原来电影评论分词结果的 10%,也就是说这些词在朴素贝叶斯
模型中不会有任何权重或者得分
2.朴素贝叶斯模型没有像 VADER 一样处理否定词如‘not good’
必须要将 n-gram 放到分词器中才能够将否定词(如“not”或“never”)与其修饰的可能要用的正
向词关联起来。
'''
print((products.pred == products.ispos).sum() / len(products))

你可能感兴趣的:(自然语言处理,python,自然语言处理,情感分析,算法)