Text-Opinion-Mining
比赛说明:
-
本数据集为化妆品品类的评论数据。为保护品牌隐私,数据已做脱敏,相关品牌名等用**代替;
-
id字段作为唯一标识对应Train_reviews.csv中的评论原文和Train_labels.csv中的四元组标签。 一条评论可能对应多个四元组标签;
-
Train_labels.csv中的A_start和A_end表示AspectTerm在评论原文中的起始位置; O_start和O_end表示OpinionTerm在评论原文中的起始位置。 若AspectTerm为"_",则A_start和A_end为空,OpinionTerm同理; (注:预测结果不需要位置信息,仅考察四元组的预测情况)
-
AspectTerm和OpinionTerm字段抽取自评论原文,与原文表述保持一致。 若AspectTerm或OpinionTerm为空,则用“_”表示;
-
Category字段的结果属于以下集合(具体以训练集为准): { 包装,成分,尺寸,服务,功效,价格,气味,使用体验,物流,新鲜度,真伪,整体,其他 }
-
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 原始训练数据
使用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]
-
解决标注后的关系
-
使用代码把预测结果文件处理成格式化结果
-
使用代码把整个工作串接起来,实现从样本到提交结果;
分类模型预测结果格式化都是一样的,只要把预测结果中每行中的最大值索引取出,对应到标签即可; 标签字典统一存放为: 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
在评估模型时,思路是“把预测结果的每一个数据与正确结果对比,如果存在则正确数加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
提取:
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
得分并没有提高 ,还是用原来的模型吧。
目前仅支持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