<jupyter_start><jupyter_text>令牌化

 概述

此模块可以定制化的将文本切分为令牌（token）序列，在此，将展示三种方式来进行令牌化：调用tokenize函数、调用sif4sci函数、调用封装好的tokenizer。  调用tokenize函数

 概述

为了方便后续向量化表征试题，本模块提供题目文本的令牌化解析（Tokenization），即将题目转换成令牌序列。    

根据构成题目的元素类型，解析功能分为 **“文本解析”** 和 **“公式解析”** 两部分。

 文本解析

根据题目文本切分粒度的大小，文本解析又分为 **“句解析”** 和 **“词解析”**。

（1） 句解析（sentence-tokenization）：将较长的文档切分成若干句子的过程称为“分句”。每个句子为一个“令牌”（token）。（待实现）    
  

（2） 词解析（text-tokenization）：一个句子（不含公式）是由若干“词”按顺序构成的，将一个句子切分为若干词的过程称为“词解析”。根据词的粒度大小，又可细分为“词组解析”和"单字解析"。
- 词组解析 (word-tokenization)：每一个词组为一个“令牌”（token）。
- 单字解析 (char-tokenization)：单个字符即为一个“令牌”（token）。

 公式解析

公式解析（formula-tokenization）：理科类文本中常常含有公式。将一个符合 latex 语法的公式切分为标记字符列表的过程称为“公式解析”。每个标记字符为一个“令牌”（token）。  
    文本解析  句解析

待实现...  词解析

词解析分为两个主要步骤：  

（1） 分词：  
- 词组解析：使用分词工具切分并提取题目文本中的词。  
    本项目目前支持的分词工具有：`jieba`   
- 单字解析：按字符划分。
    
      
（2） 筛选：过滤指定的停用词。   
- 本项目默认使用的停用词表：[stopwords](https://github.com/bigdata-ustc/EduNLP/blob/master/EduNLP/meta_data/sif_stopwords.txt)  
- 你也可以使用自己的停用词表，具体使用方法见下面的示例。<jupyter_code># 导入模块
from EduNLP.SIF.tokenization.text import tokenize 
# 输入
text = "三角函数是基本初等函数之一"<jupyter_output><empty_output><jupyter_text>词组解析

分词粒度参数选择 word： `granularity = "word"`<jupyter_code># 输出：默认使用 EduNLP 项目提供的停用词表
tokenize(text, granularity="word")<jupyter_output><empty_output><jupyter_text>单字解析

分词粒度参数选择 word： `granularity = "char"`<jupyter_code># 输出：默认使用 EduNLP 项目提供的停用词表
tokenize(text, granularity="char")<jupyter_output><empty_output><jupyter_text>停用词表<jupyter_code># 获取自己的停用词表
spath = "test_stopwords.txt"
from EduNLP.SIF.tokenization.text.stopwords import get_stopwords
stopwords = get_stopwords(spath)
stopwords
# 输出：传入停用词表（stopwords）
tokenize(text,granularity="word",stopwords=stopwords)<jupyter_output><empty_output><jupyter_text>公式解析
切分出 latex 公式的每个标记符号。针对本模块更加详细的解释参见 [formula](../formula/formula.ipynb)<jupyter_code># 导入模块
from EduNLP.SIF.tokenization.formula import tokenize<jupyter_output><empty_output><jupyter_text>- 输入<jupyter_code>formula = "\\frac{\\pi}{x + y} + 1 = x"<jupyter_output><empty_output><jupyter_text>- 输出 （1）如果您想按 latex 语法标记拆分公式的各个部分，并得到顺序序列结果，输出方法可以选择：`linear`<jupyter_code>tokenize(formula, method="linear")<jupyter_output><empty_output><jupyter_text>（2） 如果您想得到公式解析出的语法分析树序列，输出方法可以选择：`ast`> 抽象语法分析树，简称语法树（Syntax tree），是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构，树上的每个节点都表示源代码中的一种结构。  > 因此，ast 可以看做是公式的语法结构表征。<jupyter_code>tokenize(formula, method="ast", return_type="list", ord2token=False)<jupyter_output><empty_output><jupyter_text>（3）如果您只是关心公式的结构和类型，并不关心变量具体是什么，比如二元二次方程 `x^2 + y = 1` ，它从公式结构和类型上来说，和 `w^2 + z = 1` 没有区别。  此时，您可以设置如下参数：`ord2token = True`，将公式变量名转换成 token<jupyter_code># 输出形式选择抽象语法分析树（ast）且将公式变量名转换成 token
tokenize(formula, method="ast", return_type="list", ord2token=True)<jupyter_output><empty_output><jupyter_text>（4） 如果您除了 （3） 中提供的功能之外，还需要区分不同的变量。此时可以另外设置参数：`var_numbering=True`<jupyter_code># 输出形式选择抽象语法分析树（ast）且将公式变量名转换成带编号的 token
tokenize(formula, method="ast", return_type="list", ord2token=True, var_numbering=True)<jupyter_output><empty_output><jupyter_text>综合解析

综合解析，即综合以上两种解析方式（标记解析 + 公式解析），提供对题目文本的全解析。另外，如遇到特殊符号将转换成常量，例如：
```python
FIGURE_SYMBOL = "[FIGURE]"  $\SIFChoice$
QUES_MARK_SYMBOL = "[MARK]"  $\FigureID{1}$
```<jupyter_code># 导入模块
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)<jupyter_output><empty_output><jupyter_text>调用sif4sci函数来进行令牌化

 概述

SIFSci 是一个提供试题切分和标注的模块。它可定制化的将文本切分为令牌（token）序列，为后续试题的向量化做准备。 本文将以下面这道题目（来源自 LUNA 题库）为例，展示 SIFSci 的使用方法。    ![Figure](../../asset/_static/item.png) - 符合 [SIF 格式](https://edunlp.readthedocs.io/en/docs_dev/tutorial/zh/sif.html) 的题目录入格式为：<jupyter_code>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"]<jupyter_output><empty_output><jupyter_text>- 加载图片：`$\\FigureID{1}$`<jupyter_code>from PIL import Image
img = Image.open("../../asset/_static/item_figure.png")
figures = {"1": img}
img<jupyter_output><empty_output><jupyter_text>导入模块<jupyter_code>from EduNLP.SIF import sif4sci, is_sif, to_sif<jupyter_output><empty_output><jupyter_text>验证题目格式<jupyter_code>is_sif(item['stem'])<jupyter_output><empty_output><jupyter_text>- 若发现题目因为公式没有包含在 `$$` 中而不符合 SIF 格式，则可以使用 `to_sif` 模块转成标准格式。示例如下：<jupyter_code>text = '某校一个课外学习小组为研究某作物的发芽率y和温度x（单位...'
is_sif(text)
text = '某校一个课外学习小组为研究某作物的发芽率y和温度x（单位...'
to_sif(text)<jupyter_output><empty_output><jupyter_text>题目切分及令牌化

现在我们得到了符合标准格式的题目文本，接下来可以对题目做进一步的预训练，例如：切分和令牌化。  题目切分  基本切分
分离文本、公式、图片和特殊符号。<jupyter_code>segments = sif4sci(item["stem"], figures=figures, tokenization=False)
segments<jupyter_output><empty_output><jupyter_text>- 文本部分<jupyter_code>segments.text_segments<jupyter_output><empty_output><jupyter_text>- 公式部分<jupyter_code>segments.formula_segments<jupyter_output><empty_output><jupyter_text>- 图片部分<jupyter_code>segments.figure_segments
segments.figure_segments[0].figure<jupyter_output><empty_output><jupyter_text>- 特殊符号<jupyter_code>segments.ques_mark_segments<jupyter_output><empty_output><jupyter_text>标记化切分  
如果您不注重题目文本和公式的具体内容，仅仅是对题目的整体（或部分）构成感兴趣，那么可以通过修改 `symbol` 参数来将不同的成分转化成特定标记，方便您的研究。  - symbol:    - "t": text    - "f": formula    - "g": figure    - "m": question mark<jupyter_code>sif4sci(item["stem"], figures=figures, tokenization=False, symbol="tfgm")<jupyter_output><empty_output><jupyter_text>令牌化

为了方便后续向量化表征试题，本模块提供题目文本的令牌化解析（Tokenization），即将题目转换成令牌序列。    

根据构成题目的元素类型，解析功能分为 **“文本解析”** 和 **“公式解析”** 两部分。更具体的过程解析参见 [令牌化](../Tokenizer/tokenizer.ipynb)。<jupyter_code>tokens = sif4sci(item["stem"], figures=figures, tokenization=True)<jupyter_output><empty_output><jupyter_text>- 文本解析结果<jupyter_code>tokens.text_tokens<jupyter_output><empty_output><jupyter_text>公式解析结果<jupyter_code>tokens.formula_tokens<jupyter_output><empty_output><jupyter_text>- 自定义参数，得到定制化解析结果 （1）如果您想按 latex 语法标记拆分公式的各个部分，并得到顺序序列结果，输出方法（`method`）可以选择：`linear`<jupyter_code>sif4sci(
    item["stem"],
    figures=figures,
    tokenization=True,
    tokenization_params={
        "formula_params": {
            "method": "linear",
        }
    }
).formula_tokens<jupyter_output><empty_output><jupyter_text>（2） 如果您想得到公式解析出的语法分析树序列，输出方法可以选择：`ast`> 抽象语法分析树，简称语法树（Syntax tree），是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构，树上的每个节点都表示源代码中的一种结构。  > 因此，ast 可以看做是公式的语法结构表征。<jupyter_code>sif4sci(
    item["stem"],
    figures=figures,
    tokenization=True,
    tokenization_params={
        "formula_params":{
            "method": "ast",
        }
    }
).formula_tokens<jupyter_output><empty_output><jupyter_text>- 语法树展示：<jupyter_code>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

for i in range(0, len(f)):
    ForestPlotter().export(
        f[i], root_list=[node for node in f[i]],
    )
# plt.show()<jupyter_output><empty_output><jupyter_text>（3）如果您只是关心公式的结构和类型，并不关心变量具体是什么，比如二元二次方程 `x^2 + y = 1` ，它从公式结构和类型上来说，和 `w^2 + z = 1` 没有区别。  此时，您可以设置如下参数：`ord2token = True`，将公式变量名转换成 token<jupyter_code>sif4sci(
    item["stem"],
    figures=figures,
    tokenization=True,
    tokenization_params={
        "formula_params":{
            "method": "ast",
            "return_type": "list",
            "ord2token": True,
        }
    }
).formula_tokens<jupyter_output><empty_output><jupyter_text>（4） 如果您除了 （3） 中提供的功能之外，还需要区分不同的变量。此时可以另外设置参数：`var_numbering=True`<jupyter_code>sif4sci(
    item["stem"],
    figures=figures,
    tokenization=True,
    tokenization_params={
        "formula_params":{
            "method": "ast",
            "ord2token": True,
            "return_type": "list",
            "var_numbering": True
        }
    }
).formula_tokens<jupyter_output><empty_output><jupyter_text>综合训练

综合上述方法，将题目转换成令牌序列，为后续向量化做准备。<jupyter_code>sif4sci(item["stem"], figures=figures, tokenization=True,
        symbol="fgm")<jupyter_output><empty_output><jupyter_text>Tokenizer<jupyter_code>from EduNLP.Tokenizer import PureTextTokenizer, TextTokenizer, get_tokenizer<jupyter_output>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)<jupyter_text>TextTokenizer<jupyter_code>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))
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<jupyter_output><empty_output><jupyter_text>PureTextTokenizer<jupyter_code>tokenizer = get_tokenizer("pure_text") # tokenizer = PureTextTokenizer()
tokens = [t for t in tokenizer(items)]
tokens<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15181284180676524, 'fraction_numerical': 0.008811018837350618, 'mean_word_length': 6.469742813918305, 'pattern_counts': {'":': 27, '<': 138, '<?xml version=': 0, '>': 141, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '34', 'dir': 'jupyter-structured-clean-dedup', 'id': '332350', 'license': 'Apache-2.0', 'n_tokens_mistral': 5379, 'n_tokens_neox': 5828, 'n_words': 431, 'path': 'examples/tokenizer/tokenizer.ipynb', 'repo_name': 'nnnyt/EduNLP', 'size': '9874'}