【问题标题】:Text parsing - date recogniser文本解析 - 日期识别器
【发布时间】:2015-06-26 10:10:43
【问题描述】:

有谁知道是否有识别嵌入日期的 Python 文本解析器?例如,给定一个句子

“bla bla bla bla 12 Jan 14 bla bla bla 01/04/15 bla bla bla”

解析器可以挑选出两个日期出现。我知道一些 Java 工具,但是有 Python 工具吗? NTLK 会不会是矫枉过正?

谢谢

【问题讨论】:

  • Natural language time parser 的可能重复项
  • @danihp 我不这么认为。我正在寻找一个解析器,它可以提取嵌入在任意字符串中的日期,而不是将日期字符串解析为对象。
  • @Kar 在所有情况下他们都会像 14 岁而不是 2014 年一样吗?
  • @Ajay 不幸的是,没有。格式可以是任意的。

标签: python parsing nltk named-entity-recognition


【解决方案1】:

这是一种非确定性(阅读:详尽地)解决在标记化文本中查找日期位置的问题的尝试。它列举了划分句子的所有方式(作为标记列表),分区大小从minpsmaxps

每个分区都运行到解析器中,解析器输出一个已解析日期的列表,以及解析它的标记范围。

每个解析器输出都使用令牌范围的平方和进行评分(因此更喜欢从 4 个令牌解析的日期,而不是每个从 2 个令牌解析的 2 个日期)。

最后,它找到并输出得分最高的解析。

算法的三个组成部分:

from dateutil.parser import parse as parsedate

def partition(lst, minps, maxps, i=0):
    if lst == []:
        yield []
    else:
        try:
            for l in range(minps, maxps+1):
                if l > len(lst): continue
                for z in partition(lst[l:], minps, maxps, i+l):
                    yield [(i, lst[:l])] + z
        except:
            pass

def parsedates(p):
    for x in p:
        i, pi = x
        try:
            d = parsedate(' '.join(pi))
            # output: (startIndex, endIndex, parsedDate)
            if d: yield i, i+len(pi), d
        except: pass

def score(p):
    score = 0
    for pi in p:
        score += (pi[1]-pi[0])**2
    return score

找到得分最高的解析:

def bestparse(toks, maxps=3):
    bestscore = 0
    bestparse = None
    for ps in partition(toks, 1, maxps):
        l = list(parsedates(ps))
        s = score(l)
        if s > bestscore:
            bestscore = s
            bestparse = l
    return bestparse

一些测试:

l=['bla', 'bla', 'bla', '12', 'Jan', '14', 'bla', 'bla', 'bla', '01/04/15', 'bla', 'bla']
for bpi in bestparse(l):
    print('found date %s at tokens %s' % (bpi[2], ','.join(map(str, range(*bpi[:2])))))

发现日期 2014-01-12 00:00:00 在令牌 3,4,5

在令牌 9 处发现日期 2015-01-04 00:00:00

l=['Fred', 'was', 'born', 'on', '23/1/99', 'at', '23:30']
for bpi in bestparse(l, 5):
    print('found date %s at tokens %s' % (bpi[2], ','.join(map(str, range(*bpi[:2])))))

发现日期 1999-01-23 23:30:00 在令牌 3,4,5,6

请注意,这可能在计算上非常昂贵,因此您可能希望在单个短语上运行它,而不是在整个文档上运行。您甚至可能希望将长短语分成几块。

还有一点需要改进的是分区功能。如果你有先验信息,比如一个句子最多可以有多少个日期,那么它的划分方式可以大大减少。

【讨论】:

  • 我不太确定依靠dateutil.parser 进行日期识别有多可靠。 parsedate('1') 给出 2015-06-01,parsedate('1 1') 给出 2015-01-01。这似乎有点做作,不是吗?
  • @kar: 看来你还没有理解算法的工作原理
  • 鉴于'bla 1 2 bla 1/14' 它会出现两次。我不认为 '1 2' 应该被视为日期出现。
  • 1/14 也可能不是日期(例如小数)。唉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-23
  • 2011-06-04
  • 1970-01-01
  • 2021-04-27
相关资源
最近更新 更多