令牌化¶
概述¶
此模块可以定制化的将文本切分为令牌(token)序列,在此,将展示三种方式来进行令牌化:调用tokenize函数、调用sif4sci函数、调用封装好的tokenizer。
调用tokenize函数¶
概述¶
为了方便后续向量化表征试题,本模块提供题目文本的令牌化解析(Tokenization),即将题目转换成令牌序列。
根据构成题目的元素类型,解析功能分为 “文本解析” 和 “公式解析” 两部分。
文本解析¶
根据题目文本切分粒度的大小,文本解析又分为 “句解析” 和 “词解析”。
(1) 句解析(sentence-tokenization):将较长的文档切分成若干句子的过程称为“分句”。每个句子为一个“令牌”(token)。(待实现)
(2) 词解析(text-tokenization):一个句子(不含公式)是由若干“词”按顺序构成的,将一个句子切分为若干词的过程称为“词解析”。根据词的粒度大小,又可细分为“词组解析”和”单字解析”。 - 词组解析 (word-tokenization):每一个词组为一个“令牌”(token)。 - 单字解析 (char-tokenization):单个字符即为一个“令牌”(token)。
公式解析¶
公式解析(formula-tokenization):理科类文本中常常含有公式。将一个符合 latex 语法的公式切分为标记字符列表的过程称为“公式解析”。每个标记字符为一个“令牌”(token)。
文本解析¶
句解析¶
待实现…
词解析¶
词解析分为两个主要步骤:
jieba[1]:
# 导入模块
from EduNLP.SIF.tokenization.text import tokenize
[2]:
# 输入
text = "三角函数是基本初等函数之一"
词组解析¶
分词粒度参数选择 word: granularity = "word"
[3]:
# 输出:默认使用 EduNLP 项目提供的停用词表
tokenize(text, granularity="word")
[3]:
['三角函数', '初等', '函数']
单字解析¶
分词粒度参数选择 word: granularity = "char"
[4]:
# 输出:默认使用 EduNLP 项目提供的停用词表
tokenize(text, granularity="char")
[4]:
['三', '角', '函', '数', '基', '初', '函', '数']
停用词表¶
[5]:
# 获取自己的停用词表
spath = "test_stopwords.txt"
from EduNLP.SIF.tokenization.text.stopwords import get_stopwords
stopwords = get_stopwords(spath)
stopwords
[5]:
{'一旦', '一时', '一来', '一样', '一次', '一片', '一番', '一直', '一致'}
[6]:
# 输出:传入停用词表(stopwords)
tokenize(text,granularity="word",stopwords=stopwords)
[6]:
['三角函数', '是', '基本', '初等', '函数', '之一']
公式解析¶
切分出 latex 公式的每个标记符号。针对本模块更加详细的解释参见 formula
[7]:
# 导入模块
from EduNLP.SIF.tokenization.formula import tokenize
输入
[8]:
formula = "\\frac{\\pi}{x + y} + 1 = x"
输出
(1)如果您想按 latex 语法标记拆分公式的各个部分,并得到顺序序列结果,输出方法可以选择:linear
[9]:
tokenize(formula, method="linear")
[9]:
['\\frac', '{', '\\pi', '}', '{', 'x', '+', 'y', '}', '+', '1', '=', 'x']
ast > 抽象语法分析树,简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。[10]:
tokenize(formula, method="ast", return_type="list", ord2token=False)
[10]:
['\\pi', '{ }', 'x', '+', 'y', '{ }', '\\frac', '+', '1', '=', 'x']
x^2 + y = 1 ,它从公式结构和类型上来说,和 w^2 + z = 1 没有区别。ord2token = True,将公式变量名转换成 token[11]:
# 输出形式选择抽象语法分析树(ast)且将公式变量名转换成 token
tokenize(formula, method="ast", return_type="list", ord2token=True)
[11]:
['mathord',
'{ }',
'mathord',
'+',
'mathord',
'{ }',
'\\frac',
'+',
'textord',
'=',
'mathord']
(4) 如果您除了 (3) 中提供的功能之外,还需要区分不同的变量。此时可以另外设置参数:var_numbering=True
[12]:
# 输出形式选择抽象语法分析树(ast)且将公式变量名转换成带编号的 token
tokenize(formula, method="ast", return_type="list", ord2token=True, var_numbering=True)
[12]:
['mathord_con',
'{ }',
'mathord_0',
'+',
'mathord_1',
'{ }',
'\\frac',
'+',
'textord',
'=',
'mathord_0']
综合解析¶
综合解析,即综合以上两种解析方式(标记解析 + 公式解析),提供对题目文本的全解析。另外,如遇到特殊符号将转换成常量,例如:
FIGURE_SYMBOL = "[FIGURE]" # $\SIFChoice$
QUES_MARK_SYMBOL = "[MARK]" # $\FigureID{1}$
[39]:
# 导入模块
from EduNLP.Tokenizer import get_tokenizer
# 输入
item = {
"如图来自古希腊数学家希波克拉底所研究的几何图形.此图由三个半圆构成,三个半圆的直径分别为直角三角形$ABC$的斜边$BC$, 直角边$AB$, $AC$.$\bigtriangleup ABC$的三边所围成的区域记为$I$,黑色部分记为$II$, 其余部分记为$III$.在整个图形中随机取一点,此点取自$I,II,III$的概率分别记为$p_1,p_2,p_3$,则$\SIFChoice$$\FigureID{1}$"
}
# 输出
tokenizer = get_tokenizer("text")
tokens = tokenizer(item)
next(tokens)
[39]:
['如图',
'古希腊',
'数学家',
'希波',
'克拉底',
'研究',
'几何图形',
'此图',
'三个',
'半圆',
'三个',
'半圆',
'直径',
'直角三角形',
'ABC',
'斜边',
'BC',
'直角',
'AB',
'AC',
'\x08',
'igtriangleupABC',
'三边',
'围成',
'区域',
'记',
'I',
'黑色',
'记',
'II',
'其余部分',
'记',
'III',
'图形',
'中',
'随机',
'取',
'一点',
'此点',
'取自',
'I',
',',
'II',
',',
'III',
'概率',
'记',
'p',
'_',
'1',
',',
'p',
'_',
'2',
',',
'p',
'_',
'3',
'[MARK]',
'[FIGURE]']
调用sif4sci函数来进行令牌化¶
概述¶
SIFSci 是一个提供试题切分和标注的模块。它可定制化的将文本切分为令牌(token)序列,为后续试题的向量化做准备。
本文将以下面这道题目(来源自 LUNA 题库)为例,展示 SIFSci 的使用方法。

符合 SIF 格式 的题目录入格式为:
[ ]:
item = {
"stem": r"如图来自古希腊数学家希波克拉底所研究的几何图形.此图由三个半圆构成,三个半圆的直径分别为直角三角形$ABC$的斜边$BC$, 直角边$AB$, $AC$.$\bigtriangleup ABC$的三边所围成的区域记为$I$,黑色部分记为$II$, 其余部分记为$III$.在整个图形中随机取一点,此点取自$I,II,III$的概率分别记为$p_1,p_2,p_3$,则$\SIFChoice$$\FigureID{1}$",
"options": ["$p_1=p_2$", "$p_1=p_3$", "$p_2=p_3$", "$p_1=p_2+p_3$"]
}
item["stem"]
'如图来自古希腊数学家希波克拉底所研究的几何图形.此图由三个半圆构成,三个半圆的直径分别为直角三角形$ABC$的斜边$BC$, 直角边$AB$, $AC$.$\\bigtriangleup ABC$的三边所围成的区域记为$I$,黑色部分记为$II$, 其余部分记为$III$.在整个图形中随机取一点,此点取自$I,II,III$的概率分别记为$p_1,p_2,p_3$,则$\\SIFChoice$$\\FigureID{1}$'
加载图片:
$\\FigureID{1}$
[ ]:
from PIL import Image
img = Image.open("../../asset/_static/item_figure.png")
figures = {"1": img}
img
导入模块¶
[ ]:
from EduNLP.SIF import sif4sci, is_sif, to_sif
验证题目格式¶
[ ]:
is_sif(item['stem'])
True
若发现题目因为公式没有包含在
$$中而不符合 SIF 格式,则可以使用to_sif模块转成标准格式。示例如下:
[ ]:
text = '某校一个课外学习小组为研究某作物的发芽率y和温度x(单位...'
is_sif(text)
False
[ ]:
text = '某校一个课外学习小组为研究某作物的发芽率y和温度x(单位...'
to_sif(text)
'某校一个课外学习小组为研究某作物的发芽率$y$和温度$x$(单位...'
题目切分及令牌化¶
现在我们得到了符合标准格式的题目文本,接下来可以对题目做进一步的预训练,例如:切分和令牌化。
题目切分¶
基本切分¶
分离文本、公式、图片和特殊符号。
[ ]:
segments = sif4sci(item["stem"], figures=figures, tokenization=False)
segments
['如图来自古希腊数学家希波克拉底所研究的几何图形.此图由三个半圆构成,三个半圆的直径分别为直角三角形', 'ABC', '的斜边', 'BC', ', 直角边', 'AB', ', ', 'AC', '.', '\\bigtriangleup ABC', '的三边所围成的区域记为', 'I', ',黑色部分记为', 'II', ', 其余部分记为', 'III', '.在整个图形中随机取一点,此点取自', 'I,II,III', '的概率分别记为', 'p_1,p_2,p_3', ',则', '\\SIFChoice', \FigureID{1}]
文本部分
[ ]:
segments.text_segments
['如图来自古希腊数学家希波克拉底所研究的几何图形.此图由三个半圆构成,三个半圆的直径分别为直角三角形',
'的斜边',
', 直角边',
', ',
'.',
'的三边所围成的区域记为',
',黑色部分记为',
', 其余部分记为',
'.在整个图形中随机取一点,此点取自',
'的概率分别记为',
',则']
公式部分
[ ]:
segments.formula_segments
['ABC',
'BC',
'AB',
'AC',
'\\bigtriangleup ABC',
'I',
'II',
'III',
'I,II,III',
'p_1,p_2,p_3']
图片部分
[ ]:
segments.figure_segments
[\FigureID{1}]
[ ]:
segments.figure_segments[0].figure
特殊符号
[ ]:
segments.ques_mark_segments
['\\SIFChoice']
标记化切分¶
如果您不注重题目文本和公式的具体内容,仅仅是对题目的整体(或部分)构成感兴趣,那么可以通过修改 symbol 参数来将不同的成分转化成特定标记,方便您的研究。
symbol:
“t”: text
“f”: formula
“g”: figure
“m”: question mark
[ ]:
sif4sci(item["stem"], figures=figures, tokenization=False, symbol="tfgm")
['[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[FORMULA]', '[TEXT]', '[MARK]', '[FIGURE]']
令牌化¶
为了方便后续向量化表征试题,本模块提供题目文本的令牌化解析(Tokenization),即将题目转换成令牌序列。
根据构成题目的元素类型,解析功能分为 “文本解析” 和 “公式解析” 两部分。更具体的过程解析参见 令牌化。
[ ]:
tokens = sif4sci(item["stem"], figures=figures, tokenization=True)
文本解析结果
[ ]:
tokens.text_tokens
['如图',
'古希腊',
'数学家',
'希波',
'克拉底',
'研究',
'几何图形',
'此图',
'三个',
'半圆',
'三个',
'半圆',
'直径',
'直角三角形',
'斜边',
'直角',
'三边',
'围成',
'区域',
'记',
'黑色',
'记',
'其余部分',
'记',
'图形',
'中',
'随机',
'取',
'一点',
'此点',
'取自',
'概率',
'记']
公式解析结果¶
[ ]:
tokens.formula_tokens
['ABC',
'BC',
'AB',
'AC',
'\\bigtriangleup',
'ABC',
'I',
'II',
'III',
'I',
',',
'II',
',',
'III',
'p',
'_',
'1',
',',
'p',
'_',
'2',
',',
'p',
'_',
'3']
自定义参数,得到定制化解析结果
(1)如果您想按 latex 语法标记拆分公式的各个部分,并得到顺序序列结果,输出方法(method)可以选择:linear
[ ]:
sif4sci(
item["stem"],
figures=figures,
tokenization=True,
tokenization_params={
"formula_params": {
"method": "linear",
}
}
).formula_tokens
['ABC',
'BC',
'AB',
'AC',
'\\bigtriangleup',
'ABC',
'I',
'II',
'III',
'I',
',',
'II',
',',
'III',
'p',
'_',
'1',
',',
'p',
'_',
'2',
',',
'p',
'_',
'3']
ast > 抽象语法分析树,简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。[ ]:
sif4sci(
item["stem"],
figures=figures,
tokenization=True,
tokenization_params={
"formula_params":{
"method": "ast",
}
}
).formula_tokens
[<Formula: ABC>,
<Formula: BC>,
<Formula: AB>,
<Formula: AC>,
<Formula: \bigtriangleup ABC>,
<Formula: I>,
<Formula: II>,
<Formula: III>,
<Formula: I,II,III>,
<Formula: p_1,p_2,p_3>]
语法树展示:
[ ]:
f = sif4sci(
item["stem"],
figures=figures,
tokenization=True,
tokenization_params={
"formula_params":{
"method": "ast",
"return_type": "ast",
"ord2token": True,
"var_numbering": True,
}
}
).formula_tokens
f
[<networkx.classes.digraph.DiGraph at 0x7f6d28ca3940>,
<networkx.classes.digraph.DiGraph at 0x7f6d28cb5a60>,
<networkx.classes.digraph.DiGraph at 0x7f6d28caba30>,
<networkx.classes.digraph.DiGraph at 0x7f6d26b28fd0>,
<networkx.classes.digraph.DiGraph at 0x7f6d28cd4490>,
<networkx.classes.digraph.DiGraph at 0x7f6d28cd4d90>,
<networkx.classes.digraph.DiGraph at 0x7f6d28c843a0>,
<networkx.classes.digraph.DiGraph at 0x7f6d28c84ee0>,
<networkx.classes.digraph.DiGraph at 0x7f6d28c84610>,
<networkx.classes.digraph.DiGraph at 0x7f6d28c84b50>]
[ ]:
for i in range(0, len(f)):
ForestPlotter().export(
f[i], root_list=[node for node in f[i]],
)
# plt.show()
x^2 + y = 1 ,它从公式结构和类型上来说,和 w^2 + z = 1 没有区别。ord2token = True,将公式变量名转换成 token[ ]:
sif4sci(
item["stem"],
figures=figures,
tokenization=True,
tokenization_params={
"formula_params":{
"method": "ast",
"return_type": "list",
"ord2token": True,
}
}
).formula_tokens
['mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'\\bigtriangleup',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
'mathord',
',',
'mathord',
'mathord',
',',
'mathord',
'mathord',
'mathord',
'mathord',
'textord',
'\\supsub',
',',
'mathord',
'textord',
'\\supsub',
',',
'mathord',
'textord',
'\\supsub']
(4) 如果您除了 (3) 中提供的功能之外,还需要区分不同的变量。此时可以另外设置参数:var_numbering=True
[ ]:
sif4sci(
item["stem"],
figures=figures,
tokenization=True,
tokenization_params={
"formula_params":{
"method": "ast",
"ord2token": True,
"return_type": "list",
"var_numbering": True
}
}
).formula_tokens
['mathord_0',
'mathord_1',
'mathord_2',
'mathord_1',
'mathord_2',
'mathord_0',
'mathord_1',
'mathord_0',
'mathord_2',
'\\bigtriangleup',
'mathord_0',
'mathord_1',
'mathord_2',
'mathord_3',
'mathord_3',
'mathord_3',
'mathord_3',
'mathord_3',
'mathord_3',
'mathord_3',
',',
'mathord_3',
'mathord_3',
',',
'mathord_3',
'mathord_3',
'mathord_3',
'mathord_4',
'textord',
'\\supsub',
',',
'mathord_4',
'textord',
'\\supsub',
',',
'mathord_4',
'textord',
'\\supsub']
综合训练¶
综合上述方法,将题目转换成令牌序列,为后续向量化做准备。
[ ]:
sif4sci(item["stem"], figures=figures, tokenization=True,
symbol="fgm")
['如图', '古希腊', '数学家', '希波', '克拉底', '研究', '几何图形', '此图', '三个', '半圆', '三个', '半圆', '直径', '直角三角形', '[FORMULA]', '斜边', '[FORMULA]', '直角', '[FORMULA]', '[FORMULA]', '[FORMULA]', '三边', '围成', '区域', '记', '[FORMULA]', '黑色', '记', '[FORMULA]', '其余部分', '记', '[FORMULA]', '图形', '中', '随机', '取', '一点', '此点', '取自', '[FORMULA]', '概率', '记', '[FORMULA]', '[MARK]', '[FIGURE]']
Tokenizer¶
[ ]:
from EduNLP.Tokenizer import PureTextTokenizer, TextTokenizer, get_tokenizer
D:\MySoftwares\Anaconda\envs\data\lib\site-packages\gensim\similarities\__init__.py:15: UserWarning: The gensim.similarities.levenshtein submodule is disabled, because the optional Levenshtein package <https://pypi.org/project/python-Levenshtein/> is unavailable. Install Levenhstein (e.g. `pip install python-Levenshtein`) to suppress this warning.
warnings.warn(msg)
TextTokenizer¶
[ ]:
items = [{
"stem": "已知集合$A=\\left\\{x \\mid x^{2}-3 x-4<0\\right\\}, \\quad B=\\{-4,1,3,5\\}, \\quad$ 则 $A \\cap B=$",
"options": ["1", "2"]
}]
tokenizer = get_tokenizer("text") # tokenizer = TextTokenizer()
tokens = tokenizer(items, key=lambda x: x["stem"])
print(next(tokens))
['已知', '集合', 'A', '=', '\\left', '\\{', 'x', '\\mid', 'x', '^', '{', '2', '}', '-', '3', 'x', '-', '4', '<', '0', '\\right', '\\}', ',', '\\quad', 'B', '=', '\\{', '-', '4', ',', '1', ',', '3', ',', '5', '\\}', ',', '\\quad', 'A', '\\cap', 'B', '=']
[ ]:
items = ["有公式$\\FormFigureID{wrong1?}$,如图$\\FigureID{088f15ea-xxx}$,若$x,y$满足约束条件公式$\\FormFigureBase64{wrong2?}$,$\\SIFSep$,则$z=x+7 y$的最大值为$\\SIFBlank$"]
[ ]:
tokenizer = get_tokenizer("text") # tokenizer = TextTokenizer()
tokens = [t for t in tokenizer(items)]
tokens
[['公式',
'[FORMULA]',
'如图',
'[FIGURE]',
'x',
',',
'y',
'约束条件',
'公式',
'[FORMULA]',
'[SEP]',
'z',
'=',
'x',
'+',
'7',
'y',
'最大值',
'[MARK]']]
PureTextTokenizer¶
[ ]:
tokenizer = get_tokenizer("pure_text") # tokenizer = PureTextTokenizer()
tokens = [t for t in tokenizer(items)]
tokens
[['公式',
'如图',
'[FIGURE]',
'x',
',',
'y',
'约束条件',
'公式',
'[SEP]',
'z',
'=',
'x',
'+',
'7',
'y',
'最大值',
'[MARK]']]