想用裁判文书数据集,逐年训练词向量的同学,可以好好看本文,能节省你几十个小时时间。



一、检查数据

裁判文书数据集,每个月份存储到一个csv, 每个年份有一个对应的文件夹。下图是 2021 年的文件夹截图


csv字段格式是一致的,我们只需要找一个文件,尝试着读取前5行,查看数据中有哪些字段。

import pandas as pd

df = pd.read_csv('2013/2013-01.csv', nrows=5)
df.dropna(subset=['文书内容'], inplace=True)
df.head(1)



二、构造语料

我们只从csv中选取 “文书内容” ,并将其存储到语料txt文件中。

考虑到电脑性能, 预料不要太大, 1G左右是比较适中,在电脑内存为8G的情况下,应该能跑通。

2010/2011/2013这三个年度的数据只有几百M, 数据全部保留。 剩下的年份,设置不同的抽样比例,尽可能将生成的语料txt文件控制在1G左右。下面是经过粗略计算设定的比例,实际最终数据控制在800M左右。

裁判文书数据量高达300G, 读取、抽样、存储,全部过程耗时大概6小时。

年份 解压后文件大小 抽样比例 语料txt大小
2010 761M 100% 684M
2011 452M 100% 396M
2012 757M 100% 665M
2013 5.13G 20% 984M
2014 23.7G 4% 905M
2015 33.6G 3% 968M
2016 39.9G 2.4% 914M
2017 44.6G 2.2% 882M
2018 24.8G 4% 875M
2019 48.3G 2% 833M
2020 91.2G 1% 779M
2021 32.3G 3% 816M
import os
import pandas as pd

# 年份、抽样比例
year_fracs = [
    ('2010', 1), ('2011', 1), ('2012', 1), 
    ('2013', 0.2), ('2014', 0.04), ('2015', 0.03),
    ('2016', 0.024), ('2017', 0.022), ('2018', 0.04),
    ('2019', 0.02), ('2020', 0.01), ('2021', 0.03)
    ]


 for year, frac in year_fracs:
    print(f'正在构造 {year} 年的语料txt文件')
    with open('裁判文书{}.txt'.format(year), 'w', encoding='utf-8') as yf:
        # 
        csvfs = [f'{year}/{csvf}' for csvf in os.listdir(year) if '.csv' in csvf]
        for csvf in csvfs:
            # 为节省内存开销, 
            # 只读 csv 中的 “文书内容” 一个字段,
            # 且设置 chunksize 分批次读取
            chunk_dfs = pd.read_csv(csvf, usecols=['文书内容'], chunksize=10000)
            for chunk_df in chunk_dfs:
                chunk_df.dropna(subset=['文书内容'], inplace=True)
                mdf = chunk_df.sample(frac=frac)
                text = ''.join(mdf['文书内容'].values)
                yf.write(text)



三、训练word2vec

使用data内的语料txt,每个txt训练出一个对应的word2vec,结果自动存储到output/Word2Vec

使用cntext2.0.0, 代码如下

import cntext as ct
txtfs = [f for f in os.listdir('data') if '.txt' in f]
for txtf in txtfs:
    print(txtf)
    w2v_model = ct.W2VModel(corpus_file=txtf, lang='chinese')
    w2v_model.train(vector_size=100, window_size=6)

裁判文书年份、语料txt大小及训练时间长度汇总如下表


年份 语料txt大小 训练word2vec耗时
2010 684M 2127s
2011 396M 1225s
2012 665M 2105s
2013 984M 2967s
2014 905M 2810s
2015 968M 3032s
2016 914M 2880s
2017 882M 2882s
2018 875M 2852s
2019 833M 2765s
2020 779M 2539s
2021 816M 2609s



三、使用word2vec

训练结果如下图


3.1 导入模型

output/Word2Vec中有多个年份的模型, 模型文件不大, 如果内存允许,可以同时导入。首先要获取模型文件路径

import os

w2v_fs = [f'output/Word2Vec/{f}' for f in os.listdir('output/Word2Vec') if '.npy' not in f]
w2v_fs

Run

['output/Word2Vec/裁判文书2010.100.6.bin',
 'output/Word2Vec/裁判文书2011.100.6.bin',
 'output/Word2Vec/裁判文书2012.100.6.bin',
 'output/Word2Vec/裁判文书2013.100.6.bin',
 'output/Word2Vec/裁判文书2014.100.6.bin',
 'output/Word2Vec/裁判文书2015.100.6.bin',
 'output/Word2Vec/裁判文书2016.100.6.bin',
 'output/Word2Vec/裁判文书2017.100.6.bin',
 'output/Word2Vec/裁判文书2018.100.6.bin',
 'output/Word2Vec/裁判文书2019.100.6.bin',
 'output/Word2Vec/裁判文书2020.100.6.bin',
 'output/Word2Vec/裁判文书2021.100.6.bin']

import cntext as ct
import re

w2v_models = []
years = [re.findall('\d{4}', f)[0] for f in w2v_fs]
for year, w2v_f in zip(years, w2v_fs):
    print('{year}')
    w2v_models.append(ct.load_w2v(w2v_f))
    print('\n\n')

Run

2010
Loading word2vec model...

2011
Loading word2vec model...

2012
Loading word2vec model...

......


2021
Loading word2vec model...

3.2 模型词汇量

查看不同年份模型的词汇量

import re

for year, w2v_model in zip(years, w2v_models):
    wordnum = len(w2v_model.wv)
    print(f'{year}词汇量: {wordnum}')

Run

2010词汇量: 374105
2011词汇量: 312039
2012词汇量: 490673
2013词汇量: 675057
2014词汇量: 634497
2015词汇量: 667753
2016词汇量: 638568
2017词汇量: 656776
2018词汇量: 667265
2019词汇量: 629285
2020词汇量: 582988
2021词汇量: 571346

3.3 语义检查

先查看2020年的, 以 “犯罪” 为例

# 最相似的10个词
w2v_models[0].wv.most_similar(['犯罪'], topn=10)

Run

[('认真接受', 0.9499362707138062),
 ('民事诉讼法', 0.9497376084327698),
 ('建设工程有限公司', 0.9491338729858398),
 ('望春监狱', 0.9488678574562073),
 ('人身损害赔偿', 0.9487593173980713),
 ('判决发生', 0.9485785365104675),
 ('本案受理费', 0.9484607577323914),
 ('裁定准许', 0.9480699896812439),
 ('现在宁波市', 0.9479051828384399),
 ('温州银行', 0.9478054046630859)]

同时检查2010-2021, 分别返回前5个最相似的词

print('与“犯罪”最相似5个词', end='\n')
print()
for year, w2v_model in zip(years, w2v_models):
    wordtuples = w2v_model.wv.most_similar(['犯罪'], topn=5)
    words = ' '.join([w for w,v in wordtuples])
    print(f'{year}模型: {words}')

Run

2010模型: 认真接受 民事诉讼法 建设工程有限公司 望春监狱 人身损害赔偿
2011模型: 欲证明 辩护意见 被告中铁 应承担 蔡某甲
2012模型: �� 判处有期徒刑 盒 执行 黄某乙
2013模型: 雇员受害 AFT8 箐 牛鲁敬 被告金析航
2014模型: 齐立权 永川支公司 徐正青 万给 鲁子双
2015模型: 蒋明良 19KM 二百一十八条 一定独创性 类型主要
2016模型: 钧益公司 王乌旦 未予缴纳 之后离开 元系金
2017模型: 巫山县振兴 工程承揽 立奥 会展 皖1004
2018模型: 浙湖 公路东向西 雷德佑 福建省长汀县 辽宁成工
2019模型: 6.2475% 郑善 陈能颂 招某 14726.91
2020模型: 促进法 流传 四川省米易县 有奴 共有产权
2021模型: 柳凯 张鲁 几张照片 挪走 耿正会

额, 每个模型不能说跟“犯罪”毫无关系,只能说是一毛钱关系都没有!难道是我选的词有问题,错怪模型,那再试试“婚姻”


print('与“婚姻”最相似5个词', end='\n')
print()
for year, w2v_model in zip(years, w2v_models):
    wordtuples = w2v_model.wv.most_similar(['婚姻'], topn=5)
    words = ' '.join([w for w,v in wordtuples])
    print(f'{year}模型: {words}')

Run

与“婚姻”最相似5个词

2010模型: 签收 相关 姜明 20107 依法
2011模型: 下列条件 连带责任保证 债务 举证质证 申请撤诉
2012模型: 竹乐 程志街 7808292.65 乐至刑初 衢江
2013模型: 分歧双方 孙明霞〇 裁明 孙林 多派
2014模型: 山林土地 道成 被告肖小健 董锐 梓民初
2015模型: 秀洲 永乐街道 此笔费用 上特阀业 唐厚洪
2016模型: 其于2007 故予认定 千荣公司 工程验收报告 邢子
2017模型: 拆排栅 53612 初字252 被告彭国强 鸿恒昌公司
2018模型: 淄博分中心 三厅 临街门市 20200 科健
2019模型: 新岗位 2006) 风险稳控 主要树种 重量价格
2020模型: 模板款 生活用房 从轻处理建议 张春林 刘俊平
2021模型: 时二乐 对童 黄青书 一经通知 电话问

哎! 依然是彼此毫无语义关系, 种种迹象表明,这些训练出的模型就真不咋地!



四、原因分析

如果说数据没有清洗,去停用词,可能会干扰训练效果。但是我经过去停词等数据清洗,训练得到的模型表现与之前没啥变化,依然是捕捉不到语义关系信息。

至于数据量大小的问题, 大邓之前分享的

两个推文中使用的语料都是好几个G的语料txt, 基本上语义捕捉的都很完美。但前几天 词向量 | 使用1亿B站用户签名训练word2vec词向量 中语料只有302M, 但语义信息捕捉的很好。



广而告之