2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Python基于机器学习的文本情感分析详细步骤[附代码和文字解释]

Python基于机器学习的文本情感分析详细步骤[附代码和文字解释]

时间:2019-12-05 14:50:59

相关推荐

Python基于机器学习的文本情感分析详细步骤[附代码和文字解释]

最近在研究情感分析,感谢CSDN上很多博主的文章,让我受益匪浅。因此在跑出准确率高达88%的分类结果后,写下自己的代码和总结,希望对大家有所帮助~

目录

一、文本数据预处理1、读取json并转化为列表2、文本清洗与处理1)去除网页链接2)判断字符串是否全是英文3)分词、识别英文单词、去除标点符号4)词性标注、词形还原、停用词过滤 3、处理数据集B完整代码及主函数4、处理数据集A的完整代码与主函数 二、训练算法模型1、文本特征表示2、训练算法模型1)随机划分数据集和训练集2)导入算法模型3)训练算法模型4)预测测试集中的文本情感5)评估分类效果 3、保存及调用训练好的算法模型1)保存训练好的模型2)调用之前保存的模型 4、词袋模型和贝叶斯模型串联的完整代码5、TF-IDF和支持向量机串联预测的完整代码

一、文本数据预处理

情感分析主要涉及两个数据集,一个是人工标注好的数据集,即包含了情感标签和文本的数据集A,另一个是用于情感分析的原始数据集,即只包含文本的数据集B。数据集A用于训练和测试,数据集B用于得到想要的情感分析结果。

本文数据集A为斯坦福大学的Sentiment140数据集,包含了160万条标注情感极性的推文。数据集B为我从TwitterAPI上爬取的两个月推文。

预处理主要是处理数据集B中的原始数据和数据集A中的文本,目的是将包含网页链接、标点符号及无意义单词的杂乱数据转化为干净的由有意义单词组成的字符串,并使用pandas dataframe存储。

1、读取json并转化为列表

初始爬取到的推文为json格式,因此需要读取json文件,并将其中的每条推文存储到列表中,目标格式为 [‘今天天气真好’,‘This is my bag’]

import jsondef get_tweets(filepath):tweets = []file = open(filepath, 'r')for line in file.readlines():#由于json为多层嵌套,所以分行读取dic = json.loads(line) #将json转化为字典text = str(dic.get('text', '!')) #如果字典中'text'键为空,则返回'!',不处理会返回Nonetweets.append(text)return tweets

2、文本清洗与处理

1)去除网页链接

使用正则表达式去除http,https网页链接

import redef remove_urls(vTEXT):vTEXT = re.sub(r'(https|http)?:\/\/(\w|\.|\/|\?|\=|\&|\%)*\b', '', vTEXT, flags=re.MULTILINE)return (vTEXT)

2)判断字符串是否全是英文

使用ASCII字符串的取值范围判断是否是英文字符串

def judge_english(text):return all(ord(c) < 128 for c in text) #包括英文文本、英文标点符号

3)分词、识别英文单词、去除标点符号

这里使用nltk的TweetTokenizer进行英文分词,strip_handles参数表示删除句柄,即@Justin这种格式的短语,如果没有删除句柄的需求可以使用nltk的tokenize,将字符串分词为列表

使用enchant检查字符串是否是英文单词,这是比nltk更全面的英文词典库,但是enchant将 They’re 这种缩略词也判定为英文单词,因此使用 isalpha() 函数加一层过滤,筛选掉含有标点符号的字符串,只保留纯英文字符串

import enchantfrom nltk.tokenize import TweetTokenizerdef get_word(text):USdict = enchant.Dict("en_US") #英语词典text = text.replace('.', ' ') #将句号替换为空格tknzr = TweetTokenizer(strip_handles=True, reduce_len=True) #删除句柄rawwords = tknzr.tokenize(text) #分词words = [word.lower() for word in rawwords if USdict.check(word) and word.isalpha() and len(word) > 2] #判断是否是长度大于2的英文单词并转化为小写字母return words

4)词性标注、词形还原、停用词过滤

相较于词干提取,词形还原的结果更具有可读性,词干提取把词的后缀删减掉,比如luckily缩减为lucki,而lucki并不是单词,词形还原则是将ate还原为eat,将luckily还原为lucky,还原结果仍是英文单词。词形还原依赖于对词性进行准确的标注,不进行标注的话函数默认词性为名词进行还原,还原结果并不好,如wnl.lemmatize(‘ate’)结果仍是‘ate’,标注动词词性后wnl.lemmatize(‘ate’,‘V’)还原为‘eat’停用词过滤使用nltk的英文停用词词典

from nltk.corpus import stopwordsfrom nltk.stem import WordNetLemmatizerfrom nltk import pos_tagfrom nltk.corpus import wordnetstoplist = set(stopwords.words('english'))#停用词词典def get_pos_word(words):# def get_wordnet_pos(tag):if tag.startswith('J'):return wordnet.ADJelif tag.startswith('V'):return wordnet.VERBelif tag.startswith('N'):return wordnet.NOUNelif tag.startswith('R'):return wordnet.ADVelse:return Nonewords = pos_tag(words) #词性标注pos_word = [wnl.lemmatize(tag[0], pos=get_wordnet_pos(tag[1]) or wordnet.NOUN) for tag in words] #词形还原# 停用词过滤cleanwords = [word for word in pos_word if word not in stoplist]return cleanwords

3、处理数据集B完整代码及主函数

使用pandas dataframe存储处理后的文本数据并保存为csv格式文件

import jsonimport reimport enchantfrom nltk.corpus import stopwordsfrom nltk.stem import WordNetLemmatizerimport pandas as pdfrom nltk import pos_tagfrom nltk.corpus import wordnetfrom nltk.tokenize import TweetTokenizerwnl = WordNetLemmatizer()USdict = enchant.Dict("en_US")stoplist = set(stopwords.words('english'))# 获取处理后的英文推特def get_tweets(filepath):tweets = []file = open(filepath, 'r')# 去除链接def remove_urls(vTEXT):vTEXT = re.sub(r'(https|http)?:\/\/(\w|\.|\/|\?|\=|\&|\%)*\b', '', vTEXT, flags=re.MULTILINE)return (vTEXT)# 筛选英文def judge_english(text):return all(ord(c) < 128 for c in text)# 获取文本for line in file.readlines():dic = json.loads(line)text = str(dic.get('text', '!'))if judge_english(text):tweets.append(remove_urls(text))return tweetsdef get_word(text):text = text.replace('.', ' ')tknzr = TweetTokenizer(strip_handles=True, reduce_len=True)rawwords = tknzr.tokenize(text)words = [word.lower() for word in rawwords if USdict.check(word) and word.isalpha() and len(word) > 2]return words# 词性还原def get_pos_word(words):def get_wordnet_pos(tag):if tag.startswith('J'):return wordnet.ADJelif tag.startswith('V'):return wordnet.VERBelif tag.startswith('N'):return wordnet.NOUNelif tag.startswith('R'):return wordnet.ADVelse:return Nonewords = pos_tag(words)pos_word = [wnl.lemmatize(tag[0], pos=get_wordnet_pos(tag[1]) or wordnet.NOUN) for tag in words]# 停用词过滤cleanwords = [word for word in pos_word if word not in stoplist]return cleanwordsif __name__ == '__main__':filepath='D:/data/test.json' storename = 'D:/data/test.csv' tweets = get_tweets(filepath)df = pd.DataFrame()df['tweets'] = tweets# 分词df['tweets'] = df['tweets'].apply(get_word)# 词形还原df['tweets'] = df['tweets'].apply(get_pos_word)# 删除tweets中的空列表df = df[~(df['tweets'].str.len() == 0)]# 将列表转换为字符串df['tweets'] = df['tweets'].apply(lambda x: ' '.join(x))# 保存文本df.to_csv(storename, encoding='utf-8')

4、处理数据集A的完整代码与主函数

不同于处理数据集B,数据集A为行列数据整齐的英文文本,但是没有列名,且有几列多余数据,因此主要加入了对csv格式文件的读取和处理,注意本文使用的数据集A编码格式为 ISO-8859-1,大家读取csv文件 读取csv文件 encoding=‘ISO-8859-1’ 报错时改成 encoding=‘utf-8’

import enchantfrom nltk.corpus import stopwordsfrom nltk.stem import WordNetLemmatizerfrom nltk import pos_tagfrom nltk.corpus import wordnetfrom nltk.tokenize import TweetTokenizerimport pandas as pdimport rewnl = WordNetLemmatizer()USdict = enchant.Dict("en_US")stoplist = set(stopwords.words('english'))def remove_urls(vTEXT):vTEXT = re.sub(r'(https|http)?:\/\/(\w|\.|\/|\?|\=|\&|\%)*\b', '', vTEXT, flags=re.MULTILINE)return (vTEXT)def get_word(text):text = text.replace('.', ' ')tknzr = TweetTokenizer(strip_handles=True, reduce_len=True)rawwords = tknzr.tokenize(text)words = [word.lower() for word in rawwords if USdict.check(word) and not str.isdigit(word) and len(word) > 2]return wordsdef get_pos_word(words):def get_wordnet_pos(tag):if tag.startswith('J'):return wordnet.ADJelif tag.startswith('V'):return wordnet.VERBelif tag.startswith('N'):return wordnet.NOUNelif tag.startswith('R'):return wordnet.ADVelse:return Nonewords = pos_tag(words)pos_word = [wnl.lemmatize(tag[0], pos=get_wordnet_pos(tag[1]) or wordnet.NOUN) for tag in words]# 停用词过滤cleanwords = [word for word in pos_word if word not in stoplist]return cleanwordsif __name__ == '__main__':file = pd.read_csv('D:/data/Train.csv', encoding='ISO-8859-1',header=None, names=['label', 'id', 'day', 'query', 'user', 'tweets']) #pandas dataframe自定义列表名file = file.drop(file.columns[1:5], axis=1) #删除多余列#去除链接df['tweets'] = df['tweets'].apply(remove_urls)# 分词df['tweets'] = df['tweets'].apply(get_word)# 文本处理结果df['tweets'] = df['tweets'].apply(get_pos_word)# 删除tweets中的空列表df = df[~(df['tweets'].str.len() == 0)]# 转换字符串df['tweets'] = df['tweets'].apply(lambda x: ' '.join(x))# 打乱顺序df = df.sample(frac=1.0).reset_index(drop=True)#保存文本df.to_csv("D:\data\Test5000.csv", encoding='utf-8',index=None)

二、训练算法模型

本文主要使用sklearn中封装的模型进行训练

1、文本特征表示

分别使用词袋模型和TF-IDF进行文本特征表示,max_features参数是指选取的特征数最大值,大家根据各自的数据情况和需要制定最大值

from sklearn.feature_extraction.text import CountVectorizerfrom sklearn.feature_extraction.text import TfidfVectorizer#词袋模型bow_vectorizer = CountVectorizer(max_df=0.80, min_df=2, max_features=5000)# TF-IDF featuretfidf_vectorizer = TfidfVectorizer(max_df=0.80, min_df=2, max_features=5000)

2、训练算法模型

1)随机划分数据集和训练集

将数据集A中人工标注的标签和文本分别作为因变量y和自变量x,并使用sklearn中的train_test_split进行随机划分,test_size参数为测试集比例,一般选择0.2,即80%训练集,20%测试集

from sklearn.model_selection import train_test_splitdf = pd.read_csv("D:\data\Train.csv", encoding='utf-8')x=df['tweets'] #自变量y=df['label'] #因变量x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=1) #划分测试集和训练集

2)导入算法模型

本文选取五种算法模型:K近邻、逻辑回归、随机森林、支持向量机、朴素贝叶斯进行模型训练

from sklearn.linear_model import LogisticRegressionfrom sklearn.naive_bayes import MultinomialNBfrom sklearn.linear_model import SGDClassifierfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.ensemble import RandomForestClassifier# KNN Classifier K近邻算法Knn = KNeighborsClassifier()# Logistic Regression Classifier 逻辑回归Lr = LogisticRegression()# Random Forest Classifier 随机森林Rf = RandomForestClassifier()# SVM Classifier 支持向量机Svm = SGDClassifier()# Naive Bayes 朴素贝叶斯Nb = MultinomialNB()

3)训练算法模型

为了防止出错和精简代码,本文使用pipe管道封装文本特征表示和算法模型两个步骤,后续直接使用pipe拟合即可,这里以串联词袋模型和朴素贝叶斯为例,也可以串联词袋模型和随机森林等等,根据需要串联即可。

from sklearn.pipeline import make_pipelinepipe = make_pipeline(bow_vectorizer, Nb) #词袋模型串联朴素贝叶斯算法pipe.fit(x_train, y_train)

4)预测测试集中的文本情感

y_pred = pipe.predict(x_test) #进行预测df['pred']=y_pred #将预测结果保存到dataframe中

5)评估分类效果

常用的分类算法评估指标包括:准确率(Accuracy)、精准度(Precision)、召回率(Recall)和F1值(F1-score),使用sklearn自带的metrics即可得到包含上面几个指标的分类效果评估报告。

from sklearn import metricsprint(metrics.classification_report(y_test, y_pred))

3、保存及调用训练好的算法模型

1)保存训练好的模型

为了防止以后每次进行数据时都要进行拟合,直接使用sklearn自带的joblib即可保存训练好的模型。

from sklearn.externals import joblibjoblib.dump(pipe, 'D:/data/Bayes.pkl')

2)调用之前保存的模型

Bayes=joblib.load('D:/data/Bayes.pkl') #加载模型y_pred = Bayes.predict(x_test) #预测结果和pipe一致df['pred02']=y_pred #将预测结果保存到dataframe中

4、词袋模型和贝叶斯模型串联的完整代码

import pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.feature_extraction.text import CountVectorizerfrom sklearn.naive_bayes import MultinomialNBfrom sklearn.pipeline import make_pipelinefrom sklearn.externals import joblibdf = pd.read_csv("D:\data\Train.csv", encoding='utf-8')df = df.sample(frac=1.0).reset_index(drop=True)x=df['tweets'] #自变量y=df['label'] #因变量x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=1) #划分测试集和训练集# 词袋模型bow_vectorizer = CountVectorizer(max_df=0.80, min_df=2)#贝叶斯模型Nb = MultinomialNB()pipe = make_pipeline(bow_vectorizer, Nb)pipe.fit(x_train, y_train)y_pred = pipe.predict(x_test) #预测df['pred']=y_pred #保存预测结果到dataframe中print(metrics.classification_report(y_test, y_pred)) #评估joblib.dump(pipe, 'D:/data/Bayes.pkl') #保存模型

5、TF-IDF和支持向量机串联预测的完整代码

import pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.feature_extraction.text import TfidfVectorizerfrom sklearn.linear_model import SGDClassifierfrom sklearn.pipeline import make_pipelinefrom sklearn.externals import joblibdf = pd.read_csv("D:\data\Train.csv", encoding='utf-8')df = df.sample(frac=1.0).reset_index(drop=True)x=df['tweets'] #自变量y=df['label'] #因变量x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=1) #划分测试集和训练集# TF-IDFtfidf_vectorizer = TfidfVectorizer(max_df=0.80, min_df=2)# SVM ClassifierSvm = SGDClassifier()pipe = make_pipeline(tfidf_vectorizer, Svm)pipe.fit(x_train, y_train)y_pred = pipe.predict(x_test) #预测df['pred']=y_pred #保存预测结果到dataframe中print(metrics.classification_report(y_test, y_pred)) #评估joblib.dump(pipe, 'D:/data/SVM.pkl') #保存模型

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。