python训练自己中文语料库_中文语料库构建过程详细教程

article/2025/10/13 12:55:53

简介

今天我想简单记录一下自己构建语料库的过程, 方便自己查看和方便协作. 在工作中我们经常遇到一个问题就是每个研究者都有自己的语料库, 存储格式不同, 有用mysql这种结构化数据库的, 也有mogodb这种文档型数据库, 还有更多的是使用文本文件, 不管哪种形式, 都会导致数据交换出现困难. 他人使用这个语料库的时候需要自己写语料库的预处理函数, 否则语料库是不能进入计算的. 为了减少这种不必要的重复劳动, 我们就使用gensim.corpora.textcorpus.TextDirectoryCorpus类来管理语料. 也就是说, 我们的语料保存在文件夹中, 设置lines_are_documents=False来保证每个文件是一篇文档. 如果我们都以相同的方式管理语料库, 那么我们的协作就更顺畅.

目录结构

因为TextDirectoryCorpus可以支持嵌套的文件夹, 只要指定max_depth和min_depth两个参数就能控制文件夹深度. 我通常是使用一个文件夹放所有文本文件. 比如我有这样一个目录作为语料库:

1

2

3

4

5

6

7

8

9

10

11

12└─test-corpus # 根目录

│ dictionary.model # 字典数据

│ meta.csv # 元信息

└─corpus # 存放文档

01.txt

02.txt

03.txt

04.txt

05.txt

06.txt

07.txt

1

2

3import re

re.compile('.*\.txt')

输出:

re.compile(r'.*\.txt', re.UNICODE)

TextDirectoryCorpus简单使用

先看以下基本用法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38# 引入用到的库

from gensim.corpora.textcorpus import TextDirectoryCorpus

import locale

locale.setlocale(locale.LC_ALL, 'en_US.utf-8')

# 数据所在路径

dpath = r'D:\mysites\notebooks\data\test-corpus'

class MyTextDirCorpus(TextDirectoryCorpus):

# 为了强制使用'utf8'编码, 我们复写了这个方法

def getstream(self):

"""Yield documents from the underlying plain text collection (of one or more files).

Each item yielded from this method will be considered a document by subsequent

preprocessing methods.

If `lines_are_documents` was set to True, items will be lines from files. Otherwise

there will be one item per file, containing the entire contents of the file.

"""

num_texts = 0

for path in self.iter_filepaths():

with open(path, 'rt', encoding='utf8') as f:

if self.lines_are_documents:

for line in f:

yield line.strip()

num_texts += 1

else:

content = f.read().strip()

yield content

num_texts += 1

self.length = num_texts

# 实例化一个语料库,

# 遍历的最小深度是1

# 设置lines_are_documents为False

# 后缀为txt的文件才会被当作是一个文档

corpus = MyTextDirCorpus(dpath, min_depth=1, pattern='.*\.txt', lines_are_documents=False)

print('语料库计数:', len(corpus))

print('第一条:',next(corpus.get_texts()))

输出:

语料库计数: 7

第一条: ['树中路径的交集图']

分词和词典生成

为了让同事之间的工作更有一致性, 我们通常要预先对语料库进行分词, 使得不同的人具有相同的分词结果. 我们就用最简单的方法, 使用pyltp模块进行分词, 然后生成一个词典.

我们先来看看pyltp是如何进行分词的:

1

2

3

4

5

6

7

8

9# 分词测试

from pyltp import Segmentor

new_doc = '实验室中测量无序响应中时间'

model_path = r'D:\mysites\text-characters\tcharacters\ltp\ltp_data\cws.model'

segmentor = Segmentor() # 初始化实例

segmentor.load(model_path)

new_tokens = segmentor.segment(new_doc)

print('Tokens:', '\t'.join(new_tokens))

segmentor.release() # 释放模型

输出:

Tokens: 实验室中测量无序响应中时间

实现一个分词器:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61class MyTextDirCorpus(TextDirectoryCorpus):

def __init__(self, input, **kwargs):

kwargs['tokenizer'] = self.tokenizer

super().__init__(input, **kwargs)

def tokenizer(self, text):

if not hasattr(self, '_segmentor'):

model_path = r'D:\mysites\text-characters\tcharacters\ltp\ltp_data\cws.model'

segmentor = Segmentor() # 初始化实例

segmentor.load(model_path)

self._segmentor = segmentor

segmentor = self._segmentor

return segmentor.segment(text)

def __del__(self):

'''释放资源'''

if hasattr(self, '_segmentor'):

self._segmentor.release()

try:

super().__del__()

except AttributeError:

pass

# 为了强制使用'utf8'编码, 我们复写了这个方法

def getstream(self):

"""Yield documents from the underlying plain text collection (of one or more files).

Each item yielded from this method will be considered a document by subsequent

preprocessing methods.

If `lines_are_documents` was set to True, items will be lines from files. Otherwise

there will be one item per file, containing the entire contents of the file.

"""

num_texts = 0

for path in self.iter_filepaths():

with open(path, 'rt', encoding='utf8') as f:

if self.lines_are_documents:

for line in f:

yield line.strip()

num_texts += 1

else:

content = f.read().strip()

yield content

num_texts += 1

self.length = num_texts

# 实例化一个语料库

# 注意我们传入了一个token_filters参数, 实际上是一个空列表, 意思是, 不要过滤词, 所有词都要

# 当然在有需要的情况下, 我们需要定义自己的token_filters

corpus = MyTextDirCorpus(dpath, min_depth=1,

pattern='.*\.txt',

lines_are_documents=False,

tokenizer=tokenizer,

token_filters=[])

# 保存词典到本地硬盘

dict_path = r'D:\mysites\notebooks\data\test-corpus\dictionary.model'

corpus.dictionary.save_as_text(fname=dict_path)

# 查看词典内容

corpus.dictionary.token2id

输出:

{'中': 0,

'交集图': 1,

'树': 2,

'的': 3,

'路径': 4,

'\ufeff': 5,

'无序': 6,

'生成': 7,

'随机二进制': 8,

'与': 9,

'关系': 10,

'响应': 11,

'感知': 12,

'时间': 13,

'测量': 14,

'用户': 15,

'误差': 16,

'eps': 17,

'人体': 18,

'和': 19,

'测试': 20,

'系统': 21,

'系统工程': 22,

'界面': 23,

'管理': 24,

'对': 25,

'看法': 26,

'计算机': 27,

'调查': 28,

'实验室': 29,

'应用': 30}

你可以在dict_path这个路径下看到我们的字典内容, 使用任意一个文本编辑器即可打开, 如下图, 三列数据分别表示id/词/计数.

dictionary-example.png

词典的使用

生成了词典以后, 我们以后再使用语料库的时候, 可以不必每次都重新计算词典, 这个过程非常耗费资源, 所以我们使用已经存储在硬盘的词典数据.

1from gensim.corpora.dictionary import Dictionary

1

2

3

4

5

6

7

8

9

10%%timeit

# 预加载字典

dic = Dictionary.load_from_text(dict_path)

MyTextDirCorpus(dpath,

dictionary=dic,

min_depth=1,

pattern='.*\.txt',

lines_are_documents=False,

tokenizer=tokenizer,

token_filters=[])

输出:

122 µs ± 435 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

1

2

3

4

5

6

7

8%%timeit

# 每次生成词典

MyTextDirCorpus(dpath,

min_depth=1,

pattern='.*\.txt',

lines_are_documents=False,

tokenizer=tokenizer,

token_filters=[])

输出:

190 ms ± 116 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

通过上面的测试, 我们发现两种方式的差别很大, 这还是在小语料库上测试的, 如果是大语料库, 这个差别就是几个数量级的差别了.

预先分词

其实, 很多人协作的情况下, 保证大家的分词结果的一致性是很有必要的, 不然很多结果都没有可比性. 与其每个人都分一遍词, 不如从一开始就分好词. 所以我们可以把词分好, 然后保存到硬盘.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18import pickle

from pathlib import Path

dic = Dictionary.load_from_text(dict_path)

corpus = MyTextDirCorpus(dpath,

dictionary=dic,

min_depth=1,

pattern='.*\.txt$',

lines_are_documents=False,

tokenizer=tokenizer,

token_filters=[])

for fpath in corpus.iter_filepaths():

fpath = Path(fpath)

token_path = fpath.parent / (fpath.name + '.cached_tokens')

txt = fpath.read_text(encoding='utf8').strip()

tokens = corpus.tokenizer(txt)

token_path.write_bytes(pickle.dumps(list(tokens)))

使用预先分好的词, 可以再给我们的MyTextDirCorpus添加一个方法get_texts_from_tokens

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51class MyTextDirCorpus(TextDirectoryCorpus):

def __init__(self, input, **kwargs):

kwargs['tokenizer'] = self.tokenizer

super().__init__(input, **kwargs)

def tokenizer(self, text):

if not hasattr(self, '_segmentor'):

model_path = r'D:\mysites\text-characters\tcharacters\ltp\ltp_data\cws.model'

segmentor = Segmentor() # 初始化实例

segmentor.load(model_path)

self._segmentor = segmentor

segmentor = self._segmentor

return segmentor.segment(text)

def __del__(self):

'''释放资源'''

if hasattr(self, '_segmentor'):

self._segmentor.release()

try:

super().__del__()

except AttributeError:

pass

# 为了强制使用'utf8'编码, 我们复写了这个方法

def getstream(self):

"""Yield documents from the underlying plain text collection (of one or more files).

Each item yielded from this method will be considered a document by subsequent

preprocessing methods.

If `lines_are_documents` was set to True, items will be lines from files. Otherwise

there will be one item per file, containing the entire contents of the file.

"""

num_texts = 0

for path in self.iter_filepaths():

with open(path, 'rt', encoding='utf8') as f:

if self.lines_are_documents:

for line in f:

yield line.strip()

num_texts += 1

else:

content = f.read().strip()

yield content

num_texts += 1

self.length = num_texts

def get_texts_from_tokens(self):

for fpath in self.iter_filepaths():

fpath = Path(fpath)

token_path = fpath.parent / (fpath.name + '.cached_tokens')

yield pickle.loads(token_path.read_bytes())

测试以下我们新的方法是不是更节省时间:

1

2

3

4

5

6

7

8

9

10

11

12

13%%timeit

dic = Dictionary.load_from_text(dict_path)

corpus = MyTextDirCorpus(dpath,

dictionary=dic,

min_depth=1,

pattern='.*\.txt$',

lines_are_documents=False,

tokenizer=tokenizer,

token_filters=[])

for i in corpus.get_texts():

pass

输出:

154 ms ± 2.82 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

1

2

3

4

5

6

7

8

9

10

11

12

13%%timeit

dic = Dictionary.load_from_text(dict_path)

corpus = MyTextDirCorpus(dpath,

dictionary=dic,

min_depth=1,

pattern='.*\.txt$',

lines_are_documents=False,

tokenizer=tokenizer,

token_filters=[])

for i in corpus.get_texts_from_tokens():

pass

输出:

969 µs ± 7.14 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

测试显示, 时间还是差了几个数量级, 而且第二种方法的好处是, 我们使用语料库时不必再依赖分词模块pyltp.

总结

现在我们基本上已经构建了一个标准统一的语料库, 而且预先进行了分词和词典生成. 现在我们把所有用到的代码都封装到MyTextDirCorpus类中. 看代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68# author: mlln.cn

# email: xxxspy@126.com

# qq: 675495787

class MyTextDirCorpus(TextDirectoryCorpus):

def __init__(self, input, **kwargs):

kwargs['tokenizer'] = self.tokenizer

super().__init__(input, **kwargs)

def tokenizer(self, text):

if not hasattr(self, '_segmentor'):

model_path = r'D:\mysites\text-characters\tcharacters\ltp\ltp_data\cws.model'

segmentor = Segmentor() # 初始化实例

segmentor.load(model_path)

self._segmentor = segmentor

segmentor = self._segmentor

return segmentor.segment(text)

def __del__(self):

'''释放资源'''

if hasattr(self, '_segmentor'):

self._segmentor.release()

try:

super().__del__()

except AttributeError:

pass

# 为了强制使用'utf8'编码, 我们复写了这个方法

def getstream(self):

"""Yield documents from the underlying plain text collection (of one or more files).

Each item yielded from this method will be considered a document by subsequent

preprocessing methods.

If `lines_are_documents` was set to True, items will be lines from files. Otherwise

there will be one item per file, containing the entire contents of the file.

"""

num_texts = 0

for path in self.iter_filepaths():

with open(path, 'rt', encoding='utf8') as f:

if self.lines_are_documents:

for line in f:

yield line.strip()

num_texts += 1

else:

content = f.read().strip()

yield content

num_texts += 1

self.length = num_texts

def get_texts_from_tokens(self):

for fpath in self.iter_filepaths():

fpath = Path(fpath)

token_path = fpath.parent / (fpath.name + '.cached_tokens')

yield pickle.loads(token_path.read_bytes())

def save_tokens(self):

'''保存tokens到硬盘, 只需要运行一次'''

for fpath in self.iter_filepaths():

fpath = Path(fpath)

token_path = fpath.parent / (fpath.name + '.cached_tokens')

txt = fpath.read_text(encoding='utf8').strip()

tokens = self.tokenizer(txt)

token_path.write_bytes(pickle.dumps(list(tokens)))

def save_dictionary(self, dpath):

'''把字典保存到硬盘'''

self.dictionary.save_as_text(fname=dpath)

本为由mlln.cn原创, 转载请注明出处(mlln.cn), 本站保留版权. 欢迎童鞋在下方留言反馈.

注意

本文由jupyter notebook转换而来, 您可以在这里下载notebook

有问题可以直接在下方留言

或者给我发邮件675495787[at]qq.com

请记住我的网址: mlln.cn 或者 jupyter.cn


http://chatgpt.dhexx.cn/article/jGKJtJow.shtml

相关文章

15个国内常用语料库

通用单语语料库 01. 国家语委现代汉语通用平衡语料库 http://www.aihanyu.org/cncorpus/index.aspx 该语料库是由国家语言文字工作委员会主持,面向语言文字信息处理、语言文字规范和标准的制定、语言文字的学术研究、语文教育以及语言文字的社会应用,…

latex中文简历,硕博士找工作实习用,顶级简约简历

*转载请注明出处,谢谢! *latex自制简历演示,前言本篇文章介绍一下如何利用,制作一份简单的个人简历。文章目的并不是给大家提供模板,而是希望大家通过本篇文章的介绍,对制作个人简历的过程有个简单的了解,有所启发。代…

分享一个Latex一页纸简历模板(中英文)

分享一个Latex一页纸简历模板(中英文) 近期鉴于需要想找一份中文版的latex简历模板。tex模板支持中文一直是新手的心头痛,笔者希望能找到一份无痛支持中文的模板,最终在GitHub上找到了billryan制作的模板,链接在全文的…

硕士博士简历latex模板

找工作找实习,技术类的,简洁版,简历模板 模板下载地址:https://download.csdn.net/download/qq_25379821/10799422 使用注意事项: 我使用的编辑器是 Texworks 注意把环境改成system,否则中文显示乱码

一个LaTeX论文模板

文章目录 $\LaTeX$源码模板效果图 LaTeX \LaTeX LATE​X源码 % -*- coding: UTF-8 -*- \documentclass[UTF8]{ctexart} \usepackage{multicol} %数学包,这里没用到 %\usepackage{amsmath} \usepackage{indentfirst} %添加作者信息 \usepackage{authblk} \usepackag…

安装R包的几种方法(汇总)

以下载ggplot包为例 1. 在R studio界面中直接输入函数: install.packages("ggplot") #直接输入R包的名字即可。 2. 找不到无法下载的包,可以上Github官网搜索,上面会提供下载方法: 3. 将包下载到本地后,进行…

R: R package安装的几种方式

R包安装方式 一、CRAN安装二、Bioconductor安装三、Github安装四、手动安装 一、CRAN安装 对于大多数R包或可以在R官网上查询到的包,都可以直接进行安装。 直接利用代码安装 install packages("R包的名称") 从R—packages界面搜索安装 在第3步中输入R包…

R安装与卸载、RStudio安装

R及RStudio安装、R卸载 R下载R安装Rstudio下载RStudio安装R卸载 RStudio只是辅助使用R进行编辑的工具,所以RStudio的正常使用需以R程序为基础,安装过R的可以跳过前两步 R下载 官网 点击download R。 点击选择清华大学的镜像地址 R安装 任意选择一个&…

RStudio的安装

安装RStudio教程 (如果下面的博客没有能解决你的问题或者你还有其他关于计算机方面的问题需要咨询可以加博主QQ:1732501467) 安装RStudio,总共分为三步: 一、安装R安装包 二、安装RStudio 三、测试RStudio是否安装…

R与RStudio的详细安装教程(有每一步的详细教程!!!!)

R与RStudio的详细安装教程 R是RStudio的前提,首先安装R,才能安装RStudio。 安装R教程总共分为三步: 一、下载R安装包 二、安装R 三、打开R 安装RStudio,总共分为两步: 一、安装RStudio 二、测试RStudio是否安装…

什么是mysql锁表

为何会锁表 首先我们了解一下数据库查询机制,首先我们用工具进行连接查询时,会创建一个connection,此时数据库会将查询语句解析成一棵“树”,各个引擎底层的结构不一样,mysql的话在innodb用的是b-tree,俗称…

MySQL-锁表和解锁

介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。锁保证数据并发访问的一致性、有效性;锁冲突也是影响数据库并发访问性能的一个重要因素。锁是Mysql在服务器层和存储引擎层的的并发控制。 加锁是消耗资源的,锁的各种操作,包括获…

MySQL锁表了怎么办?

发生表锁的一些原因 1、锁表发生在insert update 、delete 中 2、锁表的原理是 数据库使用独占式封锁机制,当执行上面的语句时,对表进行锁住,直到发生commite 或者 回滚 或者退出数据库用户 3、锁表的原因 第一、 A程序执行了对 tab…

MySQL的表锁

目录 共享锁与排它锁(读锁和写锁) 1、锁定读 2、写操作 1、表锁 表级别的读锁和写锁 意向锁(IS、Ik) 自增锁(TUTO-INC锁) 元数据锁(MDL锁) 共享锁与排它锁(读锁和写…

连接器插针插孔接触不良该如何检测呢?

随着科学技术的发展,电子设备越来越复杂,性能要求越来越高,对其所应用的电子元器件的要求也越来越严。而连接器的性能、可靠性则直接影响到电子设备的性能及可靠性。这就使得电连接器的结构设计、制造工艺、装配等过程环节技术难度加大,不可靠因素增多,且变得更加复杂。因此,对…

IPX 、 IPEX 、 UFL连接器

I-PEX原先是个做连接器的公司,后被第一精工合并。 IPX 、IPEX 、 UFL、HSC应该都是同一种连接器,一般叫为IPEX或IPX,不过不同的厂商有自己系列和名称,如第一精工DAI-ICHI SHIKO叫为IPEX,广濑机电HIROSE的UFL和WFL&…

PCB中 D-Subminiature(DB接口) 连接器系列分类及带有3D封装绘制

PCB中 D-Subminiature(DB接口) 连接器系列分类及带有3D封装绘制 连接器分类 连接器是一种连接电气端子以形成电路的耦合装置。 借助连接器可实现电线、电缆、印刷电路板和电子元件之间的连接。D-Subminiature(DB接口)主要有直角…

使用HiFlow场景连接器查看每天处于地区的疫情

目录 使用HiFlow场景连接器查看每天处于地区的疫情 HiFlow场景连接器是什么? HiFlow场景连接器(目前)免费的 简单创建了一个查看所处地区流程: 首先你需要进行一下登录,登录进去后内容如下(你可以先看的&#xff0…

APC型光纤活动连接器有何特点?适合使用在什么场景?

1 概述 光纤活动连接器的型号主要由两个部分组成,比如我们常用的SC/UPC型连接器,SC表示连接器的接口类型,UPC表示插针端面形状。 连接器的接口分SC、FC、LC、ST、MPO等多钟类型,我们在工程中常用的主要有LC、FC和SC。连接器插针…

ThingsBoard网关mqtt连接器案例及双向RPC的BUG修复

文章目录 说明过程演示文字展示视频操作过程修改网关配置MQTT连接器配置JS模拟网关子设备添加网关设备启动网关启动js模拟设备创建开关小部件ABCDE MQTT连接器双向RPC的BUG修复 说明 通过下面案例了解MQTT连接器的使用,包括遥测,属性,单向双…