裁判文书上诉理由分类统计
一、统计结果
对这12927份裁判文书进行清洗后,有效文书数量约为10858份,有效率约为84%。
二、实现方法
(一)裁判文书上诉理由提取
1、分类标准
不认罪、罪名异议、量刑过重,量刑异议、程序瑕疵、其它。
这一上诉理由分类的依据为罪名、量刑、程序。即犯罪嫌疑人被告人的上诉理由为一审事实不清、证据不足,不构成该罪的即为不认罪;犯罪嫌疑人被告人的上诉理由为构成它罪而不构成一审裁判罪名的即为罪名异议;犯罪嫌疑人被告人的上诉理由仅为量刑过重,没有提出相关理由的即为量刑过重;犯罪嫌疑人被告人的上诉理由为量刑过重并提出理由的为量刑异议,如提出“自首、初犯、偶犯”等;犯罪嫌疑人被告人的上诉理由为一审程序出错如需要进行非法证据排除等涉及程序违法的理由时即为程序瑕疵:犯罪嫌疑人被告人的上诉理由不明(这一不明既有源自其上诉理由本身不明也是对上诉理由提取程序出现问题导致的不明)即无法归为前面几类的内容;
2、裁判文书内容提取方式
首先将裁判文书按照句号进行切片并抛弃前两句和后两句,因为这几句大多是与上诉理由无关的内容。其次裁判文书中上诉理由的表述模式为上诉人加"关于上诉人", “对上述人”, “上诉称:”, “上诉理由”, “上诉提出”, “辩护人提出”, “辩护人发表意见”, “辩护意见”, “为由,提出上诉”, “辩护提出”, “辩称”, “提出”, "辩护认为"等动作词,因而上诉理由的提取就是依据词规则对上诉理由进行提取的.
3、实现代码
docx读取
import docx2txt、
def docx_read_simple(path):
if "~$" in path:
pass
else:
text = docx2txt.process(path)
return text
句号分句
def period_cutword(self,path):
# 上诉
"""简单句号分词"""
content = []
if read(path) == None:
pass
else:
text = read(path).replace("\n", "").replace("\u3000", "").replace(" ", "").strip()
#print(text,type(text))#str
for i in text.split("。"):
#for i2 in i.split(";"):
content.append(i)
if len(content) <=2:
return content
else:
return content[4:-2]
人工贴标签
class Get_message():
def __init__(self,index):
self.file = os.path.dirname(__file__)
self.index = index
def get_name(self, file):
names = []
path, file = os.path.split(file)
#hanlp
res = HanLP.segment(file)
for t in res:
if str(t.nature) == "nr":
names.append(str(t.word))
#jieba
jieba.load_userdict(r"J:\PyCharm项目\项目\中国裁判文书网\selenium路线\文书分类标签\jieba_dic.txt")
for x in psg.lcut(file.strip()):
if x.flag is "nr":
names.append(x.word)
#jiagu
words = jiagu.seg(file) # 分词
pos = jiagu.pos(words) # 词性标注
for index, word in enumerate(pos):
if word == "nh":
names.append(words[index])
# 名字清洗
if len(names) <= 1:
pass
else:
names = sorted(names)
for index_, name in enumerate(names):
clear_name = names.copy()
clear_name.remove(clear_name[index_])
for i in clear_name:
if name in i:
return clear_name
else:
continue
return names
def get_text_from_wenshu(self, file,change=1):
global words, names, content, tag
words,txt = [],[]
texts = sy().period_cutword(file)
#print(texts)
if texts is None:
print("内容为:",texts)
else:
for name in list(set(self.get_name(file))):
""""""
if texts == [] or len(texts)<=10:
txt.append(str(texts)+"文书无内容")
for text in texts:
if name in text or "上诉单位" in text or "哎拉" in text:
tags = ["关于上诉人", "对上述人" ,"上诉称:" , "上诉理由" , "上诉提出","对于上诉","辩护人提出",
"辩护人发表意见","辩护意见","提出上诉","辩护提出","辩称","提出","辩护认为"]
for tag in tags:
if tag in text:
txt.append(text)
if self.get_name(file) == []:
for text in texts:
tags = ["关于上诉人", "对上述人", "上诉称:", "上诉理由", "上诉提出","辩护人提出","辩护人发表意见"
,"辩护意见","为由,提出上诉","辩护提出","辩称","提出","辩护认为"]
for tag in tags:
if tag in text:
txt.append(text)
#print(self.get_name(file),txt)
#去重
txt = sorted(list(set(txt)),key=lambda x:len(x),reverse=True)
del_ = ["经查","不开庭审理","综上"]
clear_content = txt.copy()
for i in txt:
for i_ in del_:
if i_ in i:
clear_content.remove(i)
# 对某些要素进行针对去重
if clear_content != []:
if len(clear_content) >=2:
content = clear_content[0]
else:
content = clear_content
else:
content = clear_content
if int(change) == 2:
content = "\n".join(txt).strip()
# 清除掉方位词
res = HanLP.segment(str(content))
for t in res:
drop_pos_set = ['xu', 'xx', 'y', 'yg', 'wh', 'wky', 'wkz', 'wp', 'ws', 'wyy', 'wyz', 'wb', 'u',
'ud', 'ude1', 'ude2', 'ude3', 'udeng', 'udh', 'p', 'rr', 'f', 'nis', 'nic',
'nnd', 'ns']
if not str(t.nature) in drop_pos_set:
words.append(str(t.word))
#去掉停用词
with open(r"J:\PyCharm项目\项目\中国裁判文书网\selenium路线\文书分类标签\stop_words.txt","r",encoding="utf-8")as f:
stop = f.readlines()
for i in stop:
for a in words:
if i.strip("\n") in a:
words.remove(a)
content = pprint.pformat("".join(words))
number = input(f"{content},\n 1:不认罪; 2:罪名异议; 3:量刑过重; 4:量刑异议; 5:程序瑕疵; 6:输出文件; 7:其它 ;"
f"8:重来 \n 请输入标签:")
number = int(number)
if number == 1:
tag = "不认罪"
elif number == 2:
tag = "罪名异议"
elif number == 3:
tag = "量刑过重"
elif number == 4:
tag = "量刑异议"
elif number == 5:
tag = "程序瑕疵"
elif number == 6:
print(file)
sys.exit()
elif number == 8:
os.system("taskkill /F /IM wps.exe")
change = 2
self.get_text_from_wenshu(file,change)
else:
tag = "其它"
path = os.path.dirname(__file__)+"\\"+tag
if not os.path.exists(path):
os.makedirs(path)
"""删除姓名"""
res = HanLP.segment(str(content))
for t in res:
drop_pos_set = ['nr', 'm',"w",'q']
if not str(t.nature) in drop_pos_set:
words.append(str(t.word))
write = "".join(words)
#上诉理由预测
#cnn().predict(write)
# 写入txt文档
with open(path+f"\\{os.path.split(file)[-1]}.txt", "a+", encoding="utf-8")as f:
f.write(write)
with open("记录.txt", "a+",encoding="utf-8")as f:
f.write(file+"\n")
sys.exit()
def docx_clear(self,file):
global words, names, content, tag
words, txt = [], []
texts = sy().period_cutword(file)
# print(texts)
if texts is None:
print("内容为:", texts)
else:
for name in list(set(self.get_name(file))):
""""""
if texts == [] or len(texts) <= 10:
txt.append(str(texts) + "文书无内容")
for text in texts:
if name in text or "上诉单位" in text or "哎拉" in text:
tags = ["关于上诉人", "对上述人", "上诉称:", "上诉理由", "上诉提出", "对于上诉", "辩护人提出",
"辩护人发表意见", "辩护意见", "提出上诉", "辩护提出", "辩称", "提出", "辩护认为"]
for tag in tags:
if tag in text:
txt.append(text)
if self.get_name(file) == []:
for text in texts:
tags = ["关于上诉人", "对上述人", "上诉称:", "上诉理由", "上诉提出", "辩护人提出", "辩护人发表意见"
, "辩护意见", "为由,提出上诉", "辩护提出", "辩称", "提出", "辩护认为"]
for tag in tags:
if tag in text:
txt.append(text)
# print(self.get_name(file),txt)
# 去重
txt = sorted(list(set(txt)), key=lambda x: len(x), reverse=True)
del_ = ["经查", "不开庭审理"]
clear_content = txt.copy()
for i in txt:
for i_ in del_:
if i_ in i:
try:
clear_content.remove(i)
except:
print(file)
# 对某些要素进行针对去重
if clear_content != []:
if len(clear_content) >= 2:
content = clear_content[0]
else:
content = clear_content
else:
content = clear_content
# 清除掉方位词
res = HanLP.segment(str(content))
for t in res:
drop_pos_set = ['xu', 'xx', 'y', 'yg', 'wh', 'wky', 'wkz', 'wp', 'ws', 'wyy', 'wyz', 'wb', 'u',
'ud', 'ude1', 'ude2', 'ude3', 'udeng', 'udh', 'p', 'rr', 'f', 'nis', 'nic',
'nnd', 'ns',"nr","w","m","q"]
if not str(t.nature) in drop_pos_set:
words.append(str(t.word))
# 去掉停用词
with open(r"J:\PyCharm项目\项目\中国裁判文书网\selenium路线\文书分类标签\stop_words.txt", "r", encoding="utf-8")as f:
stop = f.readlines()
for i in stop:
for a in words:
if i.strip("\n") in a:
words.remove(a)
content = pprint.pformat("".join(words))
return content
def main(self,files):
for i in tqdm(glob.glob(os.path.join(files,"*.docx"))):
with open("J:\记录.txt", "r+")as f:
past = f.readlines()
if i+"\n" in past:
pass
else:
self.docx_clear(i.strip('\u2022'))
if __name__ == "__main__":
index = str(random.randint(1, 50)) + random.choice('abcdefghijklmnopqrstuvwxyz!@#$%^&())')
files = "E:\Firefox\docx"
Get_message(index).main(files)
其中
get_text_from_wenshu()
是为了贴上标签作为cnn分类的基础
docx_clear()
是为了在训练好的文本分类模型上进行数据传递
4、标签贴好后
最终都是一条上诉理由为主,同时去掉了名字、一些数值、标点符号、停用词、助动词、副词等对于分类关系不大的内容。
贴标签是一个比较繁琐的事情,为了实现尽可能少的数据而尽可能高的准确率,自行去掉无关因素是一种较好的方法,因此,在自行贴标签时仅贴上了201份裁判文书的类别而且每个txt文本只有一个上诉理由。
虽然裁判文书的上诉理由不止一个,但是为了分类便利只能采取内容最为充分的那一个,否者不仅机器无法分类,人工也做不到。
三、文本分类
(一)文本分类源码来源
文本分类使用的是gaussic的text-classification-cnn-rnn,地址:链接: https://github.com/gaussic/text-classification-cnn-rnn.
其原本分类的任务是:
10个分类,每个分类6500条数据。
类别如下:
体育, 财经, 房产, 家居, 教育, 科技, 时尚, 时政, 游戏, 娱乐
他的结果还是较好的
所以,相应的参数没有进行大的调整
(二)数据结构和修改的地方
提取后的数据结构即输入的数据结构
对预测的那个文件predict.py进行了修改,为了能够看见准确率
原:
#return self.categories[y_pred_cls[0]]注释掉
改为
max_key = max([key for value in max_predict for key in value.keys()])#无法直接由值找键
#print(max_key)
for value in max_predict:
for key in value.keys():
if key == max_key:
#print("最佳预测类别为:{},最佳预测率为{:.5%}".format(value[max_key],max_key))
if max_key < 0.5:
with open("预测不准.txt","a+",encoding="utf-8")as f:
f.write(str(value[max_key]+"\n"))
return value[max_key]
其实在
print("最佳预测类别为:{},最佳预测率为{:.5%}".format(value[max_key],max_key))
处可以对单个文本分类的结果以及准确率进行输出,此处为了找出预测准确率在50%y以下的而做了这样的调整
(三)预测过程
四、结语
从最后的结果来看,预测的概率与自行贴标签的概率极为接近;
而预测准确率在50%以下的不到1000份(总份数12000左右即失误率在10%以下),应该来说还可以接受