前言
本文采用的是BCDI2018汽车行业用户观点主题及情感识别任务中的语料集链接,这些语料集的格式如下:
字段名称 | 类型 | 描述 | 说明 |
---|---|---|---|
content_id | Int | 数据ID | / |
content | String | 文本内容 | / |
subject | String | 主题 | 提取或依据上下文归纳出来的主题 |
sentiment_value | Int | 情感分析 | 分析出的情感 |
sentiment_word | String | 情感词 | 情感词 |
其中训练集数据中主题被分为10类,包括:动力、价格、内饰、配置、安全性、外观、操控、油耗、空间、舒适性,情感分为3类,分别用数字0、1、-1表示中立、正向、负向。
思路
文本预处理
1、将文本分成一个个单词,并去掉停用词、标点符号,用jieba分词工具,对中文比较友好,可以将一个文本变成: 我爱网易 – > 我,爱,网易
2、将主题换成数字标签,将主题:动力、价格、内饰、配置、安全性等数值化,变成数字:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
动力 | 价格 | 内饰 | 配置 | 安全性 | 外观 | 操控 | 油耗 | 空间 | 舒适性 |
文本向量化
利用TfidfVectorizer工具对文本提取特征,这里因为有参数需要设置,其中有一个参数ngram_range=(1,2)
,这个参数跟提取出的特征有关,其中1代表最小连续单词数,2代表最大连续单词数,解释就上下面的例子:
我爱网易食堂 – > 我,爱,网易,食堂 – > 我,爱,我爱,网易,爱网易,网易,网易食堂
分词后的单词可以连续的再组成一个新的单词作为特征,在利用TfidfVectorizer计算这个新单词的TF-IDF值,这样就可以作为特征值使用,把所有的数据处理后就是如下的矩阵:
R
m
∗
(
n
+
1
)
=
a
11
a
12
⋯
a
1
n
b
1
a
21
a
22
⋯
a
2
n
b
2
⋮
⋯
⋱
⋮
⋮
a
m
1
a
m
2
⋯
a
m
n
b
m
\begin{aligned} \mathbb{R}^{m*(n+1)}=\begin{array} {|ccccc|} a_{11}&a_{12}&\cdots&a_{1n}&b_1\\ a_{21}&a_{22}&\cdots&a_{2n}&b_2\\ \vdots&\cdots&\ddots&\vdots&\vdots\\ a_{m1}&a_{m2}&\cdots&a_{mn}&b_m\\ \end{array} \end{aligned}
Rm∗(n+1)=a11a21⋮am1a12a22⋯am2⋯⋯⋱⋯a1na2n⋮amnb1b2⋮bm
其中
m
=
9947
,
n
=
15547
m=9947,n=15547
m=9947,n=15547。
模型预测
拿训练的数据集来预测,训练好了模型之后开始用模型来预测训练集,了解预测的情况、准确率等等。
代码
import pandas as pd
import numpy as np
import jieba
import jieba.analyse
from sklearn.feature_extraction.text import TfidfTransformer,TfidfVectorizer
from sklearn.metrics import mean_squared_error
from scipy.sparse import csr_matrix, hstack
from sklearn.metrics import f1_score,accuracy_score,classification_report
import sklearn.metrics as metrics
from sklearn.preprocessing import LabelEncoder
from collections import Counter
import pickle as pk
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.cross_validation import cross_val_score
# 数据路径
testFile="D:\\Data\\opinion_analyse\\test_public\\test_public.csv"
trainFile="D:\\Data\\opinion_analyse\\train\\train.csv"
subjectList=["动力","价格","内饰","配置","安全性","外观","操控","油耗","空间","舒适性"]
def micro_avg_f1(y_true, y_pred):
return metrics.f1_score(y_true, y_pred, average='micro')
punct = set(u''':!),.:;?]}¢'"、。〉》」』】〕〗〞︰︱︳﹐、﹒
﹔﹕﹖﹗﹚﹜﹞!),.:;?|}︴︶︸︺︼︾﹀﹂﹄﹏、~¢
々‖•·ˇˉ―--′’”([{£¥'"‵〈《「『【〔〖([{£¥〝︵︷︹︻
︽︿﹁﹃﹙﹛﹝({“‘-—_…''')
def processing_data(data):
wordList = jieba.cut(data)
resultOne = [word for word in list(wordList) if word not in punct]
return ' '.join(resultOne)
def get_data():
train = pd.read_csv(trainFile)
test = pd.read_csv(testFile)
content = test['content'] # 测试数据集的正文
lbl = LabelEncoder() # 用来将数据数值化
# lbl.fit(train['subject']) # 获取所有的subject
lbl.fit(subjectList)
nb_classes = len(list(lbl.classes_)) # 将subject 归并
pk.dump(lbl, open('label_encoder.sav','wb')) # 将数据序列化到磁盘中
subject = lbl.transform(train['subject']) # 数值化后的数字 输出给 subject,已经转化为class,然后把 替换为数值
sentiment_value = [] # 情感值
for i in list(train['sentiment_value']):
sentiment_value.append(i)
subject_num= [] # 主题
for i in subject:
subject_num.append(i)
#print(np.array(sentiment_value).reshape(-1,1)[:,0])
data = pd.concat([train, test]) # 数据结果合并在一起,这个合并,两者有共同的列名就叠加在一起,不同的列名都算作不同列,没有数据的填NAN
return data,train.shape[0],np.array(sentiment_value).reshape(-1,1)[:,0],test['content_id'],test['content'],np.array(subject_num).reshape(-1,1)[:,0]
# .shape[0] 取行数
def pre_process():
data,train_row_num,y,content_id,content,subject_value = get_data()
print('train_row_num=',train_row_num)
print("-------------")
data['cut_comment'] = data['content'].map(processing_data) # 分词
print('TfidfVectorizer')
tf = TfidfVectorizer(min_df=3,max_df= 0.001,max_features=None,ngram_range=(1,2),analyzer='word') # 按照字符来做特征,最大范围是两个字符,最小是一个字符
discuss_tf = tf.fit_transform(data['cut_comment'])
return discuss_tf[:train_row_num],discuss_tf[train_row_num:],y,content_id,content,subject_value
# nrw_train : 表示 训练集的行数,也就是记录个数
#预处理
train,test,sentiment_value,content_id,content,subject_value= pre_process()
xtrain, xvalid, ytrain, yvalid = train_test_split(train, subject_value, stratify=subject_value, random_state=42,test_size=0.3, shuffle=True)
print('xtrain.shape=',xtrain.shape)
model_NB = MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
model_NB.fit(xtrain, ytrain) #特征数据直接灌进来
result = model_NB.predict(xtrain)
num=0
for i in range(result.shape[0]):
if result[i] == ytrain[i]:
num+=1
print('num=',num,'rowNum=',len(result),"pre=",(num/len(result)))
print(res[:2])
print(ytrain[:2])
#print("多项式贝叶斯分类器20折交叉验证得分: ", np.mean(cross_val_score(model_NB, xtrain, ytrain, cv=20, scoring='roc_auc')))
参考博客
BCDI2018-汽车行业用户观点主题及情感识别
数据集
scikit-learn 朴素贝叶斯类库使用小结
朴素贝叶斯的三个常用模型:高斯、多项式、伯努利
数据集也可以去官网下,官网就是第一个链接。