GithubHelp home page GithubHelp logo

text-opinion-mining's Introduction

之江杯2019-电商评论观点挖掘 参赛日志

Text-Opinion-Mining


比赛说明:

  1. 本数据集为化妆品品类的评论数据。为保护品牌隐私,数据已做脱敏,相关品牌名等用**代替;

  2. id字段作为唯一标识对应Train_reviews.csv中的评论原文和Train_labels.csv中的四元组标签。 一条评论可能对应多个四元组标签;

  3. Train_labels.csv中的A_start和A_end表示AspectTerm在评论原文中的起始位置; O_start和O_end表示OpinionTerm在评论原文中的起始位置。 若AspectTerm为"_",则A_start和A_end为空,OpinionTerm同理; (注:预测结果不需要位置信息,仅考察四元组的预测情况)

  4. AspectTerm和OpinionTerm字段抽取自评论原文,与原文表述保持一致。 若AspectTerm或OpinionTerm为空,则用“_”表示;

  5. Category字段的结果属于以下集合(具体以训练集为准): { 包装,成分,尺寸,服务,功效,价格,气味,使用体验,物流,新鲜度,真伪,整体,其他 }

  6. Polarity字段的结果属于以下集合(具体以训练集为准): { 正面、中性、负面 }


2、字段说明: (1)评论ID(ID):ID是每一条用户评论的唯一标识。 (2)用户评论(Reviews):用户对商品的评论原文。 (3)属性特征词(AspectTerms):评论原文中的商品属性特征词。 例如“价格很便宜”中的“价格”。该字段结果须与评论原文中的表述保持一致。 (4)观点词(OpinionTerms):评论原文中,用户对商品某一属性所持有的观点。 例如“价格很便宜”中的“很便宜”。该字段结果须与评论原文中的表述保持一致。 (5)观点极性(Polarity):用户对某一属性特征的观点所蕴含的情感极性,即负面、中性或正面三类。 (6)属性种类(Category):相似或同类的属性特征词构成的属性种类。 例如“快递”和“物流”两个属性特征词都可归入“物流”这一属性种类。 我们规定了属性种类集合(详见训练数据README.md),该字段结果应属于该集合。


四、评分标准 1、相同ID内逐一匹配各四元组,若AspectTerm,OpinionTerm,Category,Polarity四个字段均正确,则该四元组正确; 2、预测的四元组总个数记为P;真实标注的四元组总个数记为G;正确的四元组个数记为S: (1)精确率: Precision=S/P (2)召回率: Recall=S/G (3)F值:F1-score=(2PrecisionRecall)/(Precision+Recall)


目录结构说明

最后更新: 2019/8/28 14:26

Text-Opinion-Mining
├─Category	属性分类模型	
│  ├─data		分类数据目录
│  └─output		分类输出目录
├─data		标注模型数据目录
├─log		日志目录(未使用)
├─output	标注模型输出目录
│  ├─testdat	标注模型,测试文件输出目录
│  └─traindat	标注模型,训练数据输出目录
├─Polarity	观点分类模型
│  ├─data		数据目录
│  ├─data_0
│  ├─data_1
│  ├─output		输出目录与数据目录对应
│  ├─output_0
│  ├─output_1
│  └─output_2
├─TEST		原始测试数据
└─TRAIN		原始训练数据

最新结构见tree.txt

序列标注思路 2019/8/26 xmxoxo

使用BIO数据标注模式,总共标注两个实体:AspectTerms,OpinionTerms 编码方式为:"B-ASP", "I-ASP", "B-OPI", "I-OPI" 句子之间用空行分隔。

根据提供的训练数据如下(数据做了合并):

,id,AspectTerms,A_start,A_end,OpinionTerms,O_start,O_end,Categories,Polarities,text
0,1,_, , ,很好,0,2,整体,正面,很好,超值,很好用
1,1,_, , ,超值,3,5,价格,正面,很好,超值,很好用
2,1,_, , ,很好用,6,9,整体,正面,很好,超值,很好用
3,2,_, , ,很好,0,2,整体,正面,很好,遮暇功能差一些,总体还不错
4,2,遮暇功能,3,7,差一些,7,10,功效,负面,很好,遮暇功能差一些,总体还不错
5,2,_, , ,还不错,13,16,整体,正面,很好,遮暇功能差一些,总体还不错

标注后的训练样本例子如下:

很 B-OPI
好 I-OPI
, O
超 B-OPI
值 I-OPI
, O
很 B-OPI
好 I-OPI
用 I-OPI

很 B-OPI
好 I-OPI
, O
遮 B-ASP
暇 I-ASP
功 I-ASP
能 I-ASP
差 B-OPI
一 I-OPI
些 I-OPI
, O
总 O
体 O
还 B-OPI
不 I-OPI
错 I-OPI

训练模型:

sudo python BERT_NER.py \
	--do_train=true \
	--do_eval=true \
	--do_predict=true \
	--data_dir=./data/ \
	--bert_config_file=../bert/chinese_L-12_H-768_A-12/bert_config.json \
	--init_checkpoint=../bert/chinese_L-12_H-768_A-12/bert_model.ckpt \
	--vocab_file=../bert/chinese_L-12_H-768_A-12/vocab.txt \
	--output_dir=./output/

预测数据(测试数据):

sudo python BERT_NER.py \
	--do_train=False \
	--do_predict=true \
	--data_dir=./data/ \
	--bert_config_file=../bert/chinese_L-12_H-768_A-12/bert_config.json \
	--init_checkpoint=../bert/chinese_L-12_H-768_A-12/bert_model.ckpt \
	--vocab_file=../bert/chinese_L-12_H-768_A-12/vocab.txt \
	--output_dir=./output/

预测完后数据的处理

sudo python labelpick.py

会在output目录下生成合并结果文件(merge_test.txt) 和提取结果文件 (picklabel_test.txt)

在输出文件(picklabel_test.txt)中增加对应的记录ID号,样例如下:

id,index,txt,label
1,1,很好,OPI
1,4,超值,OPI
1,7,很好用,OPI
2,12,很好,OPI
2,15,遮暇功能,ASP
2,19,差一些,OPI
2,25,还不错,OPI
3,30,包装,ASP
3,32,太随便了,OPI
3,39,包装盒,ASP
3,43,没有,OPI
3,50,很不好,OPI

观点分类模型

使用BERT情感分类模型,样本数据直接用训练数据中的 AspectTerms和 OpinionTerms 字段;

训练数据样例:

Polarities,AspectTerms,OpinionTerms
正面,,很好
正面,,超值
正面,,很好用
正面,,很好
负面,遮暇功能,差一些
正面,,还不错
负面,包装,太随便了
负面,包装盒,没有
负面,,很不好
负面,,非常的不好
负面,,垃圾
正面,,很是划算

训练集与验证集比例为8:2 样本数量为: 5306:1327 全数据:6633

预测数据暂时使用全部训练数据。

*** 训练模型并预测 ***

已在代码中直接指定了模型目录等参数,省去命令行带参数

cd Polarity
sudo python run_Polarity.py --do_train=true --do_eval=true

训练结果:

eval_accuracy = 0.9389601
eval_f1 = 0.74708176
eval_loss = 0.19356915
eval_precision = 0.78688526
eval_recall = 0.7111111
global_step = 497
loss = 0.19369926

recall得分比较低,查看数据发现比较多重复的数据,由于文本内容比较少,有很多行完全相同。 把重复行删除,同时把两列合并为一列,重复训练。

训练结果:

\Polarity\output_2\eval_results.txt

eval_accuracy = 0.89719623
eval_f1 = 0.8186528
eval_loss = 0.3654422
eval_precision = 0.8061224
eval_recall = 0.83157897
global_step = 160
loss = 0.36228746

虽然acc了,但是由于 recall提升了,整体的F1值得到了提升。


属性分类模型

由于数据相同,使用同一个训练数据;

分类labels: ['整体','使用体验','功效','价格','物流','气味','包装','真伪','服务','其他','成分','尺寸','新鲜度']

数据: 同样使用 pre_Proecess.py 来生成

Categories,text
使用体验,滋润度很好
使用体验,粉液一般般
价格,价位
气味,味道很好
物流,物流好快
功效,白的不自然
使用体验,起痘

数据目录: ./Category/data

开始训练模型:

cd Category
sudo python run_Category.py

训练结果:

eval_accuracy = 0.8640553
eval_f1 = 0.95714283
eval_loss = 0.55876833
eval_precision = 0.95988536
eval_recall = 0.954416
global_step = 162
loss = 0.5517428

得分还可以。


##接下来的问题 [2019/8/28 13:47]

  • 解决标注后的关系

  • 使用代码把预测结果文件处理成格式化结果

  • 使用代码把整个工作串接起来,实现从样本到提交结果;


预测结果格式化 [2019/8/28 14:07]

分类模型预测结果格式化都是一样的,只要把预测结果中每行中的最大值索引取出,对应到标签即可; 标签字典统一存放为: label2id.pkl

需要的参数: 测试文件 ./data/test.tsv; 标签字典, ./output/label2id.pkl 预测结果, ./output/test_results.tsv (注意:编码是936) 输出结果文件:./output/predict.csv

程序命令行规划: predictResult.py 目录名 在指定的目录下自动寻找相应的文件。 结果文件输出列为: label,内容为标签中文值

处理命令行:

predictResult.py ./Category/
predictResult.py ./Polarity/

处理完后有两个文件生成:

/Category/output/predict.csv
/Polarity/output/predict.csv

分别是属性分类和观点分类结果


解决标注后的关系

序列只标出实体,但没有提取关系 比如样本1标注结果:

1,a,ASP
1,b,OPI
1,c,OPI

但结果应该是

1 a,b
1 _,c

需要把a,b连接起来;

这个关系需要按照语义来划分,感觉比较复杂。 看了下数据,基本上属性和观点都在一个短句里面,那就先简单的按标点符号来吧。 写下思路:

原句子, 直接从原始文件中读出来(Train_reviews.csv):

6,使用一段时间才来评价,淡淡的香味,喜欢!

序列化输出的结果是:

id,index,txt,label
6,128,淡淡的,OPI
6,131,香味,ASP
6,134,喜欢,OPI

先把原句按标点符号分开下,标点符号包括:[',' , ';' , '。' , '!'] 原句分成三个小句:

使用一段时间才来评价,
淡淡的香味,
喜欢!

然后根据序列化输出的位置,看下各个结果在哪个小句中:

输出的三句:
使用一段时间才来评价,   《==没有
淡淡的香味,             《==淡淡的,OPI    香味,ASP
喜欢!                   《== 喜欢,OPI

于是组合出来两个结果:

id, ASP, OPI 
6,香味,淡淡的
6,_,喜欢

整合全流程(预测)

使用代码把整个工作串接起来,实现从样本到最后的提交结果。

流程步骤整理:

#STEP 1: 原始数据文件,生成序列标注数据文件
#/TEST/Test_reviews.csv  ==> /data/test.txt

#STEP 2: 调用标注模型进行标注预测,得到结果
#==>/output/(多个文件)

#STEP 3: 调用标注结果处理程序,把提取结果格式化<---[结果1]
#==>/output/picklabel_test.txt

#STEP 4: 把提取结果复制到属性模型和观点模型目录中
#/output/picklabel_test.txt ==> /Category/data/test.tsv; /Polarity/data/test.tsv

#STEP 5: 调用属性模型和观点模型进行预测

#STEP 6: 调用处理工具把分类模型预测结果格式化
#得到两个结果文件<---[结果2]
#==> /Category/output/predict.csv
#==> /Polarity/output/predict.csv

#STEP 7: 把“结果1”和“结果2”合并成最后的输出结果
#==>/output/Result.csv

把整个流程整理到一个文件:run_Predict.py

使用命令行:
python run_Predict.py rebuild IsDebug
参数:  
    rebuild 强制生成数据,默认0
    IsDebug 调试模式,每步都等确认;默认0

快速预测:python run_Predict.py
重生成数据并预测:python run_Predict.py 1
调试模式预测:python run_Predict.py 1 1

模型评估

模型评价工具 modelscore.py

四、评分标准
1、相同ID内逐一匹配各四元组,若AspectTerm,OpinionTerm,Category,Polarity四个字段均正确,则该四元组正确;
2、预测的四元组总个数记为P;真实标注的四元组总个数记为G;正确的四元组个数记为S:
(1)精确率: Precision=S/P
(2)召回率: Recall=S/G
(3)F值:F1-score=(2*Precision*Recall)/(Precision+Recall)

根据上面的说明,整理出一个评估工具

命令行格式: python modelscore.py -h python modelscore.py 原始数据文件 预测结果文件

参数说明: 原始数据文件: 原始数据文件或者训练数据文件,默认为 ./TRAIN/Train_labels.csv 预测结果文件:模型预测输出的结果文件,默认值为 ./output/Result.csv

快速进行评价:python modelscore.py 指定文件评价:python modelscore.py ./data/labels.csv ./output1/Result.csv


模型优化

2019/8/30

昨天提交的结果在官方的得分是 0.6740

使用模型评估工具,在训练集上的评估得分情况:

===========抽取模型评估得分===========
P:7686 G:6633 S:4574
精确率: 0.595
召回率: 0.690
F1得分: 0.639
===========完整模型评估得分===========
P:7686 G:6633 S:4250
精确率: 0.553
召回率: 0.641
F1得分: 0.594

抽取结果的得分中,精确率比较低。需要做一些优化。

分句方式 查看了一下分句的处理方式,是用标点符号来分隔的,查看了一下训练数据,有很多是用空格来分隔的。 于是在分句处理上加上了空格处理。 处理前提取结果: 7663条 处理后提取结果: 7683条

多了20条记录,继续完成分类与情感的预测,评估最后的结果:

===========抽取模型评估得分===========
P:7708 G:6633 S:4596
精确率: 0.596
召回率: 0.693
F1得分: 0.641
===========完整模型评估得分===========
P:7708 G:6633 S:4270
精确率: 0.554
召回率: 0.644
F1得分: 0.595

还是有了一点点的提高,这个修改保留。

精确度优化

从模型评估数据中可以看到精确率比较差,主要是固定抽取出来的结果P太大, 也就是抽取了太多的结果出来,这个比例是: 6633/7708 = 86.05%

查看数据情况,有些标注的结果没有正确组合到一起,导致了抽取结果太多: 原句:

3215,挺超值的,补水效果不错,还会来买。

标注完的结果为:

id,index,txt,label,index_new,subPos
3215,76164,挺超值的,OPI,33,
3215,76169,补水效果,ASP,38,
3215,76173,不错,OPI,42,

最后组合后的结果为:

3215,_,不错,整体,正面
3215,补水效果,_,功效,正面
3215,_,挺超值的,价格,正面

而正确的结果应该是:

3215,补水效果,5,9,不错,9,11,功效,正面
3215,_, , ,挺超值的,0,4,价格,正面

可以看出,"补水效果" 和 "不错" 应该组合在一起的,没有正确组合。

标注提取问题,有些标注结果并不是连续的,跨了句子 原数据:

145,已经用的第三瓶了,以前一直用的绿色,这次换了紫色,不过还是一如既往的好用啊。美白还可以遮暇,大大的赞
146,之前用的瓶装紫色的,不太适合我,这个很好用,喜欢,好评

标注结果第3706行开始的数据:

美	B-OPI
白	I-OPI
还	O
可	O
以	O
遮	B-OPI
暇	I-OPI
,	O
大	O
大	I-OPI
的	I-OPI
赞	B-OPI
[SEP]	[SEP]
[CLS]	[CLS]
之	O
前	O
用	O
的	O
瓶	O
装	O
紫	O
色	O
的	O
,	O
不	O
太	I-OPI
适	O
合	I-OPI
我	O
,	O
这	O
个	O

重新调整标注结果的提取过程,解决以下三个问题: 句子起始索引号错误; 标注结果跨句子; 标注结果不连续;

解决后提取的结果为:6938行;

继续进行属性分类和观点分类的预测,形成最终结果,模型评估结果为:

===========抽取模型评估得分===========
P:6938 G:6633 S:5897
精确率: 0.850
召回率: 0.889
F1得分: 0.869
===========完整模型评估得分===========
P:6938 G:6633 S:5489
精确率: 0.791
召回率: 0.828
F1得分: 0.809

模型评估bug

在评估模型时,思路是“把预测结果的每一个数据与正确结果对比,如果存在则正确数加1” 这样可能会有重复出现的同一个预测结果重复计算了次数, 改正的方法是反过来:“把正确结果中的每个数据与预测结果对比,如果存在则正确数加1”。 但这样就不知道重复了多少次,于是还是用原来的思路, 但是增加了setRet集合来保存记录的结果,最后计算setRet集合的大小就是唯一正确数, 而累加数就是正确的个数,包含了重复的数据。

===========抽取模型评估得分===========
唯一正确:5889, 正确个数:5897
P:6938 G:6633 S:5889
精确率: 0.849
召回率: 0.888
F1得分: 0.868
===========完整模型评估得分===========
唯一正确:5482, 正确个数:5489
P:6938 G:6633 S:5482
精确率: 0.790
召回率: 0.826
F1得分: 0.808

生成测试数据的标注文件:

python pre_Process.py -predictfile ./TEST/Test_reviews.csv

CRF-NER模型:

提取:

   id   ASP    OPI
0   1     _     很好
1   1     _     超值
2   1     _    很好用
3   2     _     很好
4   2  遮暇功能    差一些
5   2     _    还不错
6   3    包装   太随便了
7   3   包装盒     没有
8   3     _    很不好
9   4     _  非常的不好
提取记录数: 6953
提取结果保存完成: ./output/picklabel_test.txt

预测完后进行评估:

===========抽取模型评估得分===========
唯一正确:5802, 正确个数:5802
P:6953 G:6633 S:5802
精确率: 0.834
召回率: 0.875
F1得分: 0.854
===========完整模型评估得分===========
唯一正确:5400, 正确个数:5400
P:6953 G:6633 S:5400
精确率: 0.777
召回率: 0.814
F1得分: 0.795

得分并没有提高 ,还是用原来的模型吧。


一键执行 [2019/8/30 18:45]

目前仅支持linux下运行。

一键完成测试数据的全流程预测处理,生成最后的提交文件:

sudo python run_Predict.py -predict 0 -rebuild 1

一键完成训练数据的全流程预测处理,生成最后的提交文件:

sudo python run_Predict.py -predict 1 -rebuild 1

分类模型优化

对观点分类模型进行优化,修改训练数据,使用提取结果词所在的分句作为训练样本。

跑完的结果:

eval_accuracy = 0.9603624
eval_f1 = 0.88429755
eval_loss = 0.14791998
eval_precision = 0.89166665
eval_recall = 0.8770492
global_step = 331
loss = 0.1482842

数据检查

问题:

data_merge.csv 中,203行,“好”字的索引应该是7,而不是8

201,94,_,好用,,0.0,好用,服务态度好
202,94,服务态度,_,3.0,,好用,服务态度好
203,94,_,好,,8.0,好用,服务态度好

查源头: picklabel_test.txt 文件中提取的O_start就是8而不是7

94,_,好用,,0
94,服务态度,_,3,
94,_,好,,8

再往前查: seg_test.txt 中,2279内容行 索引应该是7而不是8; 所在分句应该是3,而不是0;

94,2272,好用,OPI,2271,0,1
94,2275,服务态度,ASP,2271,3,2
94,2279,好,OPI,2271,8,0

原因是:在循环提以标注结果时,标注内容在哪一句原来是自动累加的, 遇到某一句没有任何标注(例如219句只有一个字),则会出错。 改成: 使用getid(index)方法,按索引位置来计算句子号就不会出错了。

修改后的结果:seg_test.txt

94,2272,好用,OPI,2271,0,1
94,2275,服务态度,ASP,2271,3,2
94,2279,好,OPI,2271,7,2

再往后:picklabel_test.txt

94,_,好用,,0
94,服务态度,好,3,7

提取数据: 6940行

合并后的数据: data_merge.csv

202,94,服务态度,好,3.0,7.0,好用,服务态度好

数据正确了

调整后模型评估

===========抽取模型评估得分===========
唯一正确:5910, 正确个数:5918
P:6921 G:6633 S:5910
精确率: 0.854
召回率: 0.891
F1得分: 0.872
===========完整模型评估得分===========
唯一正确:5559, 正确个数:5566
P:6921 G:6633 S:5559
精确率: 0.803
召回率: 0.838
F1得分: 0.820

使用最新模型生成提交数据

[2019/8/31 15:50] 虽然截止时间已经过掉了,但既然优化了模型,还是把测试数据跑一遍提交上去。

一键预测命令:

sudo python run_Predict.py -predict 0 -rebuild 1 -debug 1

得到的结果:

   id AspectTerms OpinionTerms Categories Polarities
0   1           _          是正品         真伪         正面
1   1           _           白嫩       使用体验         正面
2   1           _           不错         整体         正面
3   2           _        不是我喜欢         整体         负面
4   2          颜色           明显         功效         正面
5   3           _         挺细腻的       使用体验         正面
6   4           _          还行吧         整体         正面
7   5           _           不错         整体         正面
8   6           _          很细腻       使用体验         正面
9   6           _         贴合肤色       使用体验         正面
------------------------------
总条数:4854, 最大ID:2237, 缺失ID数:0
最终结果已经保存:./output/Result.csv

初赛最终得分:

电商评论观点挖掘:82 /0.725
日期:2019-08-30 17:36:00
排名: 40
score:0.7254

text-opinion-mining's People

Contributors

fanruifeng avatar xmxoxo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.