基于 Python 和 NLTK 的推特情感分析
作者:宋彤彤
1. 导读
NLTK 是 Python 的一个自然语言处理模块,其中实现了朴素贝叶斯分类算法。这次 Mo 来教大家如何通过 python 和 nltk 模块实现对推文按照正面情绪(positive)和负面情绪(negative)进行归类。
在项目内部有可运行的代码教程 naive_code.ipynb 和 经过整理方便进行部署的部署文件 Deploy.ipynb,大家可以结合之前发布的Mo平台部署介绍一文学习如何部署属于自己的应用。大家也可以打开下方项目地址,对部署好的应用进行一下测试,比如简单输入 ‘My house is great.’ 和 ‘My house is not great.’ 来判断它们分别是 positve 还是 nefative。
2. 准备工作
2.1 导入工具包
首先,导入我们用到的工具包 nltk。
import nltk
# 如果没有这个包,可以根据下面的代码进行操作
# pip install nltk
# import nltk
# nltk.download() # 对依赖资源进行下载,一般下载 nltk.download('popular') 即可
2.2 准备数据
训练模型需要大量的标记数据才能有比较好的效果。这里我们先用少量的数据来帮助我们了解整个的流程和原理,如果需要更好的实验结果,可以加大训练数据的数量。
因为该模型是一个二分类模型,我们需要两类数据,分别标记为 'positive' 和 'negative'。初步训练好的模型需要测试数据来检验效果。
# 标记为 positive 的数据
pos_tweets = [('I love this car', 'positive'),
('This view is amazing', 'positive'),
('I feel great this morning', 'positive'),
('I am so excited about the concert', 'positive'),
('He is my best friend', 'positive')]
# 标记为 negative 的数据
neg_tweets = [('I do not like this car', 'negative'),
('This view is horrible', 'negative'),
('I feel tired this morning', 'negative'),
('I am not looking forward to the concert', 'negative'),
('He is my enemy', 'negative')]
#测试数据,备用
test_tweets = [('I feel happy this morning', 'positive'),
('Larry is my friend', 'positive'),
('I do not like that man', 'negative'),
('My house is not great', 'negative'),
('Your song is annoying', 'negative')]
2.3 特征提取
我们需要从训练数据中提取有效的特征对模型进行训练。这里的特征是标签即其对应的推特中的有效单词。那么,怎么提取这些有效单词呢?
首先,分词并将所有单词变成小写,取长度大于 2 的单词,得到的列表代表一条 tweet;然后,将训练数据所有 tweet 包含的单词进行整合。
# 数据整合及划分成词,删除长度小于2的单词
tweets = []
for (words, sentiment) in pos_tweets + neg_tweets:
words_filtered = [e.lower() for e in words.split() if len(e) >= 3]
tweets.append((words_filtered, sentiment))
print(tweets)
# 提取训练数据中所有单词,单词特征列表从推特内容中提取出的单词来表示
def get_words_in_tweets(tweets):
all_words = []
for (words, sentiment) in tweets:
all_words.extend(words)
return all_words
words_in_tweets = get_words_in_tweets(tweets)
print(words_in_tweets)
为了训练分类器,我们需要一个统一的特征,那就是是否包含我们词库中的单词,下面的特征提取器可以对输入的 tweet 单词列表进行特征提取。
# 对一条 tweet 提取特征,得到的字典表示 tweet 包含哪几个单词
def extract_features(document):
document_words = set(document)
features = { }
for word in word_features:
features['contains({})'.format(word)] = (word in document_words)
return features
print(extract_features(['love', 'this', 'car']))
2.4 制作训练集并训练分类器
利用 nltk 的 classify 模块的 apply_features 方法制作训练集。
# 利用 apply_features 方法制作训练集
training_set = nltk.classify.apply_features(extract_features, tweets)
print(training_set)
训练朴素贝叶斯分类器。
# 训练朴素贝叶斯分类器
classifier = nltk.NaiveBayesClassifier.train(training_set)
到此,我们的分类器初步训练完成,可以使用了。
3. 测试工作
我们的分类器效果如何呢?先用我们事先准备好的测试集检验一下。可以得到 0.8 的正确率。
count = 0
for (tweet, sentiment) in test_tweets:
if classifier.classify(extract_features(tweet.split())) == sentiment:
print('Yes, it is '+sentiment+' - '+tweet)
count = count + 1
else:
print('No, it is '+sentiment+' - '+tweet)
rate = count/len(test_tweets)
print('Our correct rate is:', rate)
关于 'Your song is annoying' 这一句分类错误的原因,是我们的词库里没有关于 'annoying' 一词的任何信息。这也说明了数据集的重要性。
4. 分析总结
分类器的 _label_probdist 是标签的先验概率。 在我们的例子中,标记为 positive 和 negtive 标签的概率都是 0.5。
分类器的 _feature_probdist 是 特征/值概率词典。它与 _label_probdist 一起用于创建分类器。特征/值概率词典将预期似然估计与特征和标签相关联。我们可以看到,当输入包含 'best' 一词时,输入值被标记为 negative 的概率为 0.833。
我们可以通过 show_most_informative_features() 方法来显示分类器中最有信息价值的特征。我们可以看到,如果输入中不包含 'not',那么标记为 positive 的可能性是 negative 的 1.6 倍;不包含 'best',标记为 negative 的可能性是 positive 的1.2倍。
print(classifier._label_probdist.prob('positive'))
print(classifier._label_probdist.prob('negative'))
print(classifier._feature_probdist)
print(classifier._feature_probdist[('negative', 'contains(best)')].prob(True))
print(classifier.show_most_informative_features())
5. 参考资料
关于我们
Mo(网址:https://momodel.cn) 是一个支持 Python的人工智能在线建模平台,能帮助你快速开发、训练并部署模型。
近期 Mo 也在持续进行机器学习相关的入门课程和论文分享活动,欢迎大家关注我们的公众号获取最新资讯!