概念理解

词性标注:
给定句子中判定每个词的语法范畴,确定其词性并加以标注的过程。这样说比较抽象,我们用一个简单的例子来说明

这儿是个非常漂亮的公园

对其词性标注结果如下

这儿/代词 是/动词 个/量词 非常/副词 漂亮/形容词 的/结构助词 公园/名词

给已经分好的词做词性标注,中文里多义的,也就是不同场景下表示的语法属性完全不同。好在大多数的词,尤其是“实词”一般只有一到两个词性,并且其中一个词性使用频次远远高于另外一个。
词性标注最简单的方法是从”语料库“中统计每个词所对应的高频词性,将其作为默认词性。同时使用”隐含马尔可夫模型“、”条件随机场模型”能提高标记准确性。

使用Jieba分词进行词性标注

对文本 “ 水是人类赖以生存的基本物质” 进行词性标注

#!/usr/bin/env python
# -- coding: utf-8 --
# @File  : jieba_psg.py
# @Author: evenvi
# @Date  : 19-4-28
# @Desc  :
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import jieba.posseg as psg
sent = '水是人类赖以生存的基本物质'

seg_list = psg.cut(sent)
print(u' '.join(['{0}/{1}'.format(w, t) for w, t in seg_list]))

标注结果如下

水/n 是/v 人类/n 赖以生存/l 的/uj 基本/n 物质/n

命名实体识别

一句话来讲,实体命名识别就是识别语料中人名、地名、组织机构名、时间、日期、货币等命名实体。
中文命名实体识别存在的难题

  • 各类命名实体数量众多
    人名、地名、新生名称层出不穷
  • 嵌套情况复杂
    各种实体名称相互嵌套
  • 长度不确定
    和分词一样命名实体识别也分为三种类型
  • 基于规则的命名实体识别
  • 基于统计的命名实体识别
  • 混合方法

使用Jieba对文本内日期识别

非结构化的文本中经常夹杂非规范日期,比如:我明天要去济南看趵突泉。30号去济南的机票还有吗?我们从这个句子中识别出两个非规范的日期“明天”和“30号”并输出为类似xxxx-xx-xx格式时间。

  • 实现思路:

通过Jieba将带有时间信息的词切分,记录连续时间信息的词,提取其中”m(数字)"和“t(时间)”词性的词。
对“m"和”t“词性的词进行解析,并通过正则匹配数值
将匹配的数值转换为阿拉伯数字
输出标准格式数据
具体代码示例:

#!/usr/bin/env python
# -- coding: utf-8 --
# @File  : jieba_date.py
# @Author: evenvi
# @Date  : 19-5-15
# @Desc  : 使用Python的中文自然语言处理包Jieba分词识别日期


import re
from datetime import datetime, timedelta
from dateutil.parser import parse
import jieba.posseg as psg


def time_extract(text):
    time_res = []
    word = ''
    keyDate = {'今天': 0, '明天': 1, '后天': 2}
    for k, v in psg.cut(text):
        if k in keyDate:
            if word != '':
                time_res.append(word)
                word = (datetime.today() + timedelta(days=keyDate.get(k, 0))).strftime('%Y年%m月%d日')
        elif word != '':
            if v in ['m', 't']:
                word = word + k
            else:
                time_res.append(word)
                word = ''
        elif v in ['m', 'k']:
            word = k
    if word != '':
        time_res.append(word)
    result = list(filter(lambda x: x is not None, [check_time_valid(w) for w in time_res]))
    final_res = [parse_datetime(w) for w in result]

    return [x for x in final_res if x is not None]


def check_time_valid(word):
    """
    日期串有效性判断
    :param word:
    :return:
    """
    m = re.match("d+$", word)
    if m:
        if len(word) <= 6:
            return None
    wordl = re.sub('[号|日]d+$', '日', word)
    if wordl != word:
        return check_time_valid(wordl)
    else:
        return wordl


def parse_datetime(msg):
    """
    对日期串进行时间转换
    :param msg:
    :return:
    """
    if msg is None or len(msg) == 0:
        return None

    try:
        dt = parse(msg, fuzzy=True)
        return dt.strftime('%Y-%m-%d %H:%M:%S')
    except Exception as e:
        m = re.search(
            r"([0-9零一二两三四五六七八九十]+年)?([0-9一二两三四五六七八九十]+月)?([0-9一二两三四五六七八九十]+[号日])?([上中下午晚早]+)?([0-9零一二两三四五六七八九十百]+[点:\.时])?([0-9零一二三四五六七八九十百]+分?)?([0-9零一二三四五六七八九十百]+秒)?",
            msg
        )
    if m.group(0) is not None:
        res = {
            "year": m.group(1),
            "month": m.group(2),
            "day": m.group(3),
            "hour": m.group(5) if m.group(5) is not None else '00',
            "minute": m.group(6) if m.group(6) is not None else '00',
            "second": m.group(7) if m.group(7) is not None else '00',
        }
        params = {}

        print res

        for name in res:
            if res[name] is not None and len(res[name]) != 0:
                tmp = None
                if name == "year":
                    tmp = year2dig(resname)
                else:
                    tmp = cn2dig(resname)

                if tmp is not None:
                    params[name] = int(tmp)

        target_data = datetime.today().replace(**params)
        is_pm = m.group(4)
        if is_pm is not None:
            if is_pm == u'下午' or is_pm == u'晚上' or is_pm == u'中午':
                hour = target_data.time().hour
                if hour < 12:
                    target_data = target_data.replace(hour=hour+12)
        return target_data.strftime('%Y-%m-%d %H:%M:%S')
    else:
        return None


UTIL_CN_NUM = {
    '零': 0,
    '一': 1,
    '二': 2,
    '三': 3,
    '四': 4,
    '五': 5,
    '六': 6,
    '七': 7,
    '八': 8,
    '九': 9,
    '0': 0,
    '1': 1,
    '2': 2,
    '3': 3,
    '4': 4,
    '5': 5,
    '6': 6,
    '7': 7,
    '8': 8,
    '9': 9
}
UTIL_CN_UNIT = {'十': 10, '百': 100, '千': 1000, '万': 10000}


def cn2dig(src):
    """
    解析
    :param src:
    :return:
    """
    if src == "":
        return None
    m = re.match("d+", src)
    if m:
        return int(m.group(0))
    rsl = 0
    unit = 1
    for item in src[::-1]:
        if item in UTIL_CN_UNIT.keys():
            unit = UTIL_CN_UNIT[item]
        elif item in UTIL_CN_NUM.keys():
            num = UTIL_CN_NUM[item]
            rsl += num * unit
        else:
            return None
    if rsl < unit:
        rsl += unit

    return rsl


def year2dig(year):
    """
    解析年
    :param year:
    :return:
    """
    res = ''
    for item in year:
        if item in UTIL_CN_NUM.keys():
            res = res + str(UTIL_CN_NUM[item])
        else:
            res = res + item

    m = re.match("d+", res)
    if m:
        if len(m.group(0)) == 2:
            return int(datetime.today().year/100)*100 + int(m.group(0))
        else:
            return int(m.group(0))

    else:
        return None


text1 = '我要住到明天下午三点'
text2 = '预定28号2点房间'
text3 = '我要从21号下午4点住到11月2号'
print(text1, time_extract(text1))
print(text2, time_extract(text2))
print(text3, time_extract(text3))

Tags: none

Related Posts:
  • [尚无相关文章]

Leave a Comment