Skip to content

Gadget 说明文档

冬日新雨 edited this page Jan 19, 2021 · 48 revisions

去除停用词

remove_stopwords

给定一串经过分词后的词汇组成的 list,去除其中的停用词。

>>> import pkuseg
>>> import jionlp as jio
>>> text = '2018年发行的《新华词典》,是一部以语文为主兼收百科的中型词典,适合中学师生及中等以上文化程度的读者使用。'
>>> pkuseg_obj = pkuseg.pkuseg()
>>> text_segs = pkuseg_obj.cut(text)
>>> res1 = jio.remove_stopwords(text_segs)
>>> res2 = jio.remove_stopwords(text_segs, remove_time=True)
>>> print(res1)
>>> print(res2)

# text_segs: ['2018年', '发行', '的', '《', '新华', '词典', '》', ',', '是', '一', '部', '以', '语文', 
#             '为主', '兼收百科', '的', '中型', '词典', ',', '适合', '中学', '师生', '及', '中等', '以上', 
#             '文化', '程度', '的', '读者', '使用', '。']
# res1: ['2018年', '发行', '新华', '词典', '一', '部', '语文', '兼收百科', '中型', '词典', '适合', '中学',
#        '师生', '中等', '文化', '程度', '读者', '使用']
# res2: ['发行', '新华', '词典', '一', '部', '语文', '兼收百科', '中型', '词典', '适合', '中学', '师生', 
#        '中等', '文化', '程度', '读者', '使用']

  • 若须调整词典,需要进入工具包的 jionlp/dictionary/stopwords.txt 文件直接修改。
  • 工具提供了删除时间词汇的参数remove_time(bool),可以将词汇列表中的年月日、季节、早中晚等词汇剔除。如上例所示。具体正则表达式可进入工具包的jionlp/rule/rule_pattern.py 文件查看修改。
    • 文本中,时间词汇分为两种语言功能,一种是作为名词性成分,另一种是作为时间状语成分。
    • 本工具依据此划分,保留名词性成分的模糊时间词汇,如“三十多年”、“六七个月”等。
    • 删除时间状语成分,如“2019年3月10日”、“第一季度”、“18:30:51”、“3~4月份”、“清晨”、“年前”等。
    • 该区分方法较为笼统,但核心目的是去除具体指示时间,保留虚指模糊时间。更详细信息在jionlp/gadget/remove_stopwords.py
  • 工具提供了删除地名词汇的参数remove_location,可以将词汇列表中的具体地名等词汇删除,如“宁夏”、“英国”、“沙溪镇”、“珊瑚海”、“艾斯卡丁郡”等。
  • 工具提供了删除纯数字词汇的参数remove_number,可以将词汇列表中的纯数字等词汇删除,如“12900”、“十万三千多”、“百分之六十七”、“0.0123”等。
  • 工具提供了删除非中文字符词汇的参数remove_non_chinese,可以将词汇列表中的非中文字符等词汇删除,如“-----”、“###”、“abs~”等。
  • 工具提供了保留否定词汇的参数save_negative_words,可以将词汇列表中的否定词汇保留,如“没有”、“不”、“非”等。

文本分句

split_sentence

给定一段文本,按照中文标点符号做分句

>>> import jionlp as jio
>>> text = '他说:“中华古汉语,泱泱大国,历史传承的瑰宝。。。”'
>>> res = jio.split_sentence(text, criterion='fine')
>>> print(res)

# ['他说:', '“中华古汉语,', '泱泱大国,', '历史传承的瑰宝。。。”']
  • 参数 criterion 分为 coarse粗粒度 和 fine细粒度 两种;
    • 粗粒度按照。!?“”等中文完整句子语义来确定;
    • 细粒度按照。!?,:;、“”‘’ 等中文短句来确定。
  • 引号的处理依照与前后文本结合紧密度来确定,如上例所示。

地址解析

parse_location

给定一个(地址)字符串,识别其中的省、市、县三级地名,指定参数town_village(bool),可获取乡镇、村、社区两级详细地名

# 例 1
>>> import jionlp as jio
>>> text = '武侯区红牌楼街道19号红星大厦9楼2号'
>>> res = jio.parse_location(text, town_village=True)
>>> print(res)

# {'province': '四川省',
#  'city': '成都市',
#  'county': '武侯区',
#  'town': '红牌楼街道',
#  'village': None,
#  'detail': '红牌楼街道19号红星大厦9楼2号',
#  'full_location': '四川省成都市武侯区红牌楼街19号红星大厦9楼2号',
#  'orig_location': '武侯区红牌楼街19号红星大厦9楼2号'}

# 例 2
>>> text = '四川金阳2019年易地扶贫搬迁工程'
>>> res = jio.parse_location(text)
>>> print(res)

# {'province': '四川省', 
#  'city': '凉山彝族自治州', 
#  'county': '金阳县', 
#  'detail': '2019年易地扶贫搬迁工程', 
#  'full_location': '四川省凉山彝族自治州金阳县2019年易地扶贫搬迁工程', 
#  'orig_location': '四川金阳2019年易地扶贫搬迁工程'}

  • 若字符串中缺少省市信息,可依据词典做自动补全,如上例1中,根据“武侯区” 补全 “四川、成都”。
  • 若字符串中仅有 “高新区”,无法做补全,则按原样返回结果。
  • 字符串不局限于地址,如上例2,若不包含任何地址,则返回为空。
  • 若地址名仅仅为简称,如上例2,会自动补全。
  • 词典位置:jionlp/dictionary/china_location.txt,该词典从 2020年国家统计局行政区划得到
  • 若地址中涉及多个省市县,则以最靠前的地址为准,仅匹配一个。
  • 该词典可返回省、市、县三级,再指定参数town_village(bool),可获取乡镇、村、社区两级详细地名,但是乡镇、村社两级地址必须使用全名匹配,不支持简称;同时必须在省、市、县指定完全清晰的情况下才生效。
  • 国内行政区划有变动,不支持旧地名的抽取。

新闻地名识别

recognize_location

给定一篇新闻,识别其中的国内省、市、县地名,国外国家、城市名,并以层级结构返回。该方法多用于舆情统计分析。

>>> import jionlp as jio
>>> text = '海洋一号D星。中新网北京6月11日电(郭超凯)记者从中国国家航天局获悉,6月11日2时31分,在牛家村,中国在太原卫星发射中心用长征二号丙运载火箭成功发射海洋一号D星。该星将与海洋一号C星组成中国首个海洋民用业务卫星星座。相比于美国,海洋一号D星是中国第四颗海洋水色系列卫星,是国家民用空间基础设施规划的首批海洋业务卫星之一。'
>>> res = jio.recognize_location(text)
>>> print(res)

# {
#     "domestic":[
#         [{"province":"北京市", "city":"北京市", "county":null}, 2],
#         [{"province":"山西省", "city":"太原市", "county":null}, 1]
#     ],
#     "foreign":[
#         [{"country":"中国", "city":"北京"}, 5],
#         [{"country":"美国", "city":null}, 1]
#     ],
#     "others":{"牛家村":1}
# }

  • 采用了北大分词器 pkuseg,词性为 ns 地名的词汇进行统计,计算效果和性能 80% 程度上受到分词器影响;
  • 当有多个地址返回时,排序靠后的地址往往可靠性低;
  • 国内地名未考虑乡镇级,国外地名未考虑洲、州、邦、县级;地名未考虑海、河、山、楼等,此类全部存入 others 字段;
  • 文本中,存在“中国”二字,往往为外交新闻,也可能出现在 foreign 字段中,如上例;
  • 词典位置:jionlp/dictionary/china_location.txt,该词典从 2020年中国行政区划,以及jionlp/dictionary/world_location.txt
  • TODO:如“北京时间”不能计入地名计算,往往分词器无法判断;“日美同盟”中需要分别考虑日本、美国;
  • 返回结果中,第一个地址属于文本的归属地的正确率为 93%。

身份证号码解析

parse_id_card

给定一个身份证号码,解析其对应的省、市、县、出生年月、性别、校验码

>>> text = '52010320171109002X'
>>> res = jio.parse_id_card(text)
>>> print(res)

# {'province': '贵州省',
#  'city': '贵阳市',
#  'county': '云岩区',
#  'birth_year': '2017',
#  'birth_month': '11',
#  'birth_day': '09',
#  'gender': '女',
#  'check_code': 'x'}

  • 若给定字符串不是身份证号,返回为 None
  • 某些行政区划码已被撤销,如 140402(原山西省长治市城区),但仍有此类身份证号,此时仅能解析部分(山西省长治市)

繁体转简体字

tra2sim

给定一段文本,将其中的繁体字转换为简体字,提供charword两种模式,区别如下:

>>> import jionlp as jio
>>> text = '今天天氣好晴朗,想喫速食麵。妳還在工作嗎?在太空梭上工作嗎?'
>>> res1 = jio.tra2sim(text, mode='char')
>>> res2 = jio.tra2sim(text, mode='word')
>>> print(res1)
>>> print(res2)

# 今天天气好晴朗,想吃速食面。你还在工作吗?在太空梭上工作吗?
# 今天天气好晴朗,想吃方便面。你还在工作吗?在航天飞机上工作吗?
  • char 模式是按照字符逐个替换为简体字
  • word 模式是将港台地区的词汇表述习惯,替换为符合大陆表述习惯的相应词汇
  • 采用前向最大匹配的方式执行

简体转繁体字

sim2tra

给定一段文本,将其中的简体字转换为繁体字,提供charword两种模式,区别如下:

>>> import jionlp as jio
>>> text = '今天天气好晴朗,想吃方便面。你还在工作吗?在航天飞机上工作吗?'
>>> res1 = jio.sim2tra(text, mode='char')
>>> res2 = jio.sim2tra(text, mode='word')
>>> print(res1)
>>> print(res2)

# 今天天氣好晴朗,想喫方便面。妳還在工作嗎?在航天飛機上工作嗎?
# 今天天氣好晴朗,想喫速食麵。妳還在工作嗎?在太空梭上工作嗎?
  • char 模式是按照字符逐个替换为繁体字
  • word 模式是将大陆的词汇表述习惯,替换为符合港台表述习惯的相应词汇
  • 采用前向最大匹配的方式执行

汉字转拼音

pinyin

给定一段文本,将其中的汉字标注汉语拼音,提供standard(zhòng)simple(zhong4)detail(声母、韵母、声调)三种模式:

>>> import jionlp as jio
>>> text = '中华人民共和国。'
>>> res1 = jio.pinyin(text)
>>> res2 = jio.pinyin(text, formater='simple')
>>> res3 = jio.pinyin('中国', formater='detail')
>>> print(res1)
>>> print(res2)
>>> print(res3)

# ['zhōng', 'huá', 'rén', 'mín', 'gòng', 'hé', 'guó', '<unk>']
# ['zhong1', 'hua2', 'ren2', 'min2', 'gong4', 'he2', 'guo2', '<unk>']
# [{'consonant': 'zh', 'vowel': 'ong', 'tone': '1'}, 
#  {'consonant': 'g', 'vowel': 'uo', 'tone': '2'}]
  • 对于非汉字字符,以及非常用汉字字符(如仅用于韩文和日文的汉字字符),该工具直接返回<py_unk>
  • standard 模式返回标准的汉语拼音。
  • simple 模式将字母和注音分离,更适合用于深度学习模型建模。
  • detail 模式返回声母(consonant)、韵母(vowel)、声调(tone)信息。其中声母共计23个,韵母共计34个,声调共计5个,轻声以数字5标记。
  • 采用正向最大匹配,优先匹配多音词汇和短语。

汉字转偏旁与字形

char_radical

给定一段文本,将其中的汉字标注偏旁部首字形结构。字形结构分为 9 种,使用jio.char_radical.get_structure_detail()查看。 同时给出四角编码拆字部件信息。

>>> import jionlp as jio
>>> text = '植树节是哪一天呢?'
>>> structures_dict = jio.char_radical.get_structure_detail()
>>> res = jio.char_radical(text)
>>> print(structures_dict)
>>> print(res)

# {0: '一体结构', 1: '左右结构', 2: '上下结构', 3: '左中右结构', 4: '上中下结构', 
#  5: '右上包围结构', 6: '左上包围结构', 7: '左下包围结构', 8: '全包围结构', 9: '半包围结构'}
# [['木', 1, '44912', '木直'],
#  ['木', 3, '44900', '木又寸'],
#  ['草', 2, '44227', '竹卩'],
#  ['日', 2, '60801', '日疋'],
#  ['口', 1, '67027', '口那'],
#  ['一', 0, '10000', '一'],
#  ['大', 2, '10804', '一大'],
#  ['口', 1, '67012', '口尼'],
#  ['<cr_unk>', 0, '00000', '?']]

  • 对于非汉字字符,以及非常用汉字字符(如仅用于韩文和日文的汉字字符),该工具直接返回<cr_unk>
  • 一些汉字有多个偏旁部首,如“岡”,既包括“山”,也包括“冂”,其字本意为“山脊”,因此在指定偏旁时,指定为“山”。
  • 一些变形偏旁,如“艹”、“氵”等,直接使用其原意汉字替代,如“草”、“水”等。方便直接使用对应汉字的 embedding
  • 四角编码信息是基于笔画、位置信息构造的,与部首、结构信息有重复冗余之处。
  • 拆字部件未转化为标准汉字,仍以偏旁形式存在。

关键短语抽取

extract_keyphrase

给定一段文本,返回其中的关键短语,默认为5个。

>>> import jionlp as jio
>>> text = '朝鲜确认金正恩出访俄罗斯 将与普京举行会谈...'
>>> key_phrases = jio.keyphrase.extract_keyphrase(text)
>>> print(key_phrases)
>>> print(jio.keyphrase.extract_keyphrase.__doc__)

# ['俄罗斯克里姆林宫', '邀请金正恩访俄', '举行会谈',
#  '朝方转交普京', '最高司令官金正恩']

  • 原理简述:在 tfidf 方法提取的碎片化的关键词(默认使用 pkuseg 的分词工具)基础上,将在文本中相邻的关键词合并,并根据权重进行调整,同时合并较为相似的短语,并结合 LDA 模型,寻找突出主题的词汇,增加权重,组合成结果进行返回。
  • 参数较多,可调节部分也较灵活,可以参考 print(jio.keyphrase.extract_keyphrase.__doc__)
  • 更细节的用法可以参考 CKPE

成语接龙

idiom_solitaire

给定一条成语,返回其尾字为首的成语。

idiom = input('input: ')
n = 0
while n < 10:
    idiom = jio.idiom_solitaire(idiom, same_pinyin=False, same_tone=True)
    print('A: ', idiom)
    idiom = jio.idiom_solitaire(idiom, same_pinyin=False, same_tone=True)
    print('B: ', idiom)
    n += 1

# 执行后,工具代码会以 A 和 B 两个角色无限把成语接龙玩下去
  • cur_idiom(str): 当前输入的成语,为其寻找下一个接龙成语
  • check_idiom(bool): 检查当前输入的 cur_idiom 是否是成语,默认为 False
  • same_pinyin(bool): 拼音一致即可接龙,否则必须同一个汉字才可接龙,默认 True
  • same_tone(bool): same_pinyin 为 True 时有效,即拼音的音调一致才可接龙,否则算错,默认为 True
  • with_prob(bool): 以成语的使用频率进行返回,即常见成语更容易返回,否则更易返回罕见成语
  • restart(bool): 重新开始新一轮成语接龙,即清空已使用成语列表,默认 False

抽取式文本摘要

extract_summary

给定一段文本,返回其抽取式的文本摘要,默认200字以内。

>>> import jionlp as jio
>>> text = '海外网11月10日电当地时间9日,美国总统特朗普在推特上发文表示,美国国防部长马克·埃斯珀已经被开除。...'
>>> res = jio.summary.extract_summary(text)
>>> print(res)

# 特朗普的推文写道:“马克 埃斯珀已经被开除。...
  • 原理简述:为每个文本中的句子分配权重,权重计算包括 tfidf 方法的权重,以及 LDA 主题权重,以及 lead-3 得到位置权重,同时将长度低于15,大于70的句子权重做削减。并在最后结合 MMR 模型对句子做筛选,得到抽取式摘要。(默认使用 pkuseg 的分词工具效果好)
  • 参数较多,可调节部分也较灵活,可以参考 print(jio.summary.extract_summary.__doc__)
  • 本工具仍有很大提升空间,此处作为 baseline 。

回译数据增强

BackTranslation、BaiduApi、XunfeiApi、GoogleApi、TecentApi、YoudaoApi、YoudaoFreeApi

给定一段文本,利用各类大厂公开的免费 api,对文本数据做增强。用户可在各大厂的云平台上自行申请密钥,填在接口的参数中。 各厂申请 API 地址如下:

>>> import jionlp as jio
>>> xunfei_api = jio.XunfeiApi(
        [{"appid": "5f5846b1",
          "api_key": "52465bb3de9a258379e6909c4b1f2b4b",
          "secret": "b21fdc62a7ed0e287f31cdc4bf4ab9a3"}])
>>> tencent_api = jio.TencentApi(
        [{"project_id": "0",
          "secret_id": "AKID5zGGuInJwmLehbyKyYXGS3NXOXYLE96o",
          "secret_key": "buwiGXXifLt888rKQLwGH3dsfsdmeCX"},  # 错误的 api
         {"project_id": "0",
          "secret_id": "AKID5zGGuInJwmLehbyKyYXGS3NXOXYLE",
          "secret_key": "buwiGXXifLt888rKQLwGH3asuhFbmeCX"}])  # 错误的 api
>>> youdao_free_api = jio.YoudaoFreeApi()
>>> youdao_api = jio.YoudaoApi(
        [{'appid': '39856bd56b482cfc',
          'app_secret': '87XpTE63nBVnrR0b6Hy0aTDWlkoq2l4A'}])
>>> google_api = jio.GoogleApi()
>>> baidu_api = jio.BaiduApi(
        [{'appid': '20200618000498778',
          'secretKey': 'raHalLakgYitNuzGOoB2'},  # 错误的密钥
         {'appid': '20200618000498778',
          'secretKey': 'raHalLakgYitNuzGdsoB2'},  # 错误的密钥
         {'appid': '20200618000498778',
          'secretKey': 'raHalLakgYitNuzGOoBZ'}], gap_time=0.5)

>>> print(baidu_api.__doc__)  # 查看接口说明
>>> apis = [baidu_api, youdao_api, google_api,
            youdao_free_api, tencent_api, xunfei_api]

>>> back_trans = jio.BackTranslation(mt_apis=apis)
>>> text = '饿了么凌晨发文将推出新功能,用户可选择是否愿意多等外卖员 5 分钟,你愿意多等这 5 分钟吗?'
>>> print(youdao_api(text))  # 使用接口做单次调用
>>> result = back_trans(text)
>>> print(result)

# ['饿了么将在凌晨推出一项新功能。用户可以选择是否愿意额外等待外卖人员5分钟。您想多等5分钟吗?', 
#  '《饿了么》将在凌晨推出一档新节目。用户可以选择是否愿意等待餐饮人员多花5分钟。您愿意再等五分钟吗?', 
#  'Ele.me将在早晨的最初几个小时启动一个新的功能。用户可以选择是否准备好再等5分钟。你不想再等五分钟吗?', 
#  'Eleme将在清晨推出新的功能。用户可以选择是否愿意再等5分钟工作人员。你想再等五分钟吗?']

  • 原理简述:利用公开的大厂 API 对文本数据做回译增强,即完成从 中文->外文->中文 的翻译过程。
  • 该框架考虑了对各 API 的语言种类支持问题;两次调用之间的等待时间问题;等待超时问题;支持在 API 接口中输入多个密钥(appkey_obj)。
  • 每一个 API 类提供了初始化 lang_pool 参数,用于指定翻译的语种。基于此种考虑:某些小语种的模型效果并不如英语理想,如上例“饿了么”句子的翻译,小语种的翻译质量不如英汉互译。
  • 该接口框架包括了常用的若干 API(BaiduApi、XunfeiApi、GoogleApi、TecentApi、YoudaoApi、YoudaoFreeApi),也支持自定义训练的模型 API 接口。具体见下。
    • 自定义 API 接口接收一个 str 格式文本输入,输出对应的 str 格式翻译文本;
    • 自定义 API 须指定文本的源语言和目标翻译语言,如(zh, en) 和 (en, zh);
    • 自定义 API 在请求调用报错后需要提供 raise Exeption 语句的异常抛出。
    • 自定义 API 接口可参考代码中的写法。
  • API 接口支持多个密钥,即申请若干个某一厂商的 API,混合在一起调用。框架接口自动选择可用密钥,忽略掉无效密钥。如上例中腾讯和百度的多个密钥,以列表形式传入。
  • 您可自己登录对应大厂的云平台,机器翻译服务页面,申请属于自己的 API 的密钥。使用更高效。
  • 若某些 API 接口效果不理想,可以随意选定若干或指定某个厂商的 API。

电话号码归属地、运营商解析

jio.phone_location

给定一个电话号码字符串,识别其中的省、市二级地名手机运营商

>>> import jionlp as jio
>>> text = '联系电话:13288568202. (021)32830431'
>>> num_list = jio.extract_phone_number(text)
>>> print(num_list)
>>> res = [jio.phone_location(item['text']) for item in num_list]
>>> print(res)

# [{'text': '13288568202', 'offset': (5, 16), 'type': 'cell_phone'},
   {'text': '(021)32830431', 'offset': (18, 31), 'type': 'landline_phone'}]

# {'number': '(021)32830431', 'province': '上海', 'city': '上海', 'type': 'landline_phone'}
# {'number': '13288568202', 'province': '广东', 'city': '揭阳',
   'type': 'cell_phone', 'operator': '中国联通'}
  • 要求输入的文本必须为电话号码字符串,若输入如 “3218177937821332”,很可能造成误识别,即,配合 jio.extract_phone_number 识别效果佳
  • 携号转网后,特定的手机号码会误识别
  • 词典定期更新

查找帮助

jio.help

若不知道 JioNLP 有哪些功能,可根据命令行提示键入若干关键词做搜索。

>>> import jionlp as jio
>>> jio.help()

> please enter keywords in Chinese separated by space:数据增强
> function name ==> jio.BackTranslation
> 回译接口,集成多个公开免费试用机器翻译接 ...