Text parsing - date recogniser

时间:2015-06-26 10:10:43

标签: python parsing nltk named-entity-recognition

Does anyone know if there's a Python text parser that recognises embedded dates? For instance, given a sentence

"bla bla bla bla 12 Jan 14 bla bla bla 01/04/15 bla bla bla"

the parser could pick out the two date occurrences. I know of some Java tools, but are there Python ones? Would NTLK be an overkill?

Thanks

1 个答案:

答案 0 :(得分:3)

这是尝试不确定性地(阅读:详尽地)解决了在标记化文本中查找日期的问题。它列举了分区句子的所有方式(作为标记列表),分区大小从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 at the token 3,4,5

     

发现日期2015-01-04 00:00:00 at tokens 9

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 at the token 3,4,5,6

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

另一个改进点是分区功能。如果您有一个句子中最多可以包含多少日期的先验信息,则可以大大减少对其进行分区的方式。