Лучший способ определить и извлечь даты из текста Python?

В рамках более крупного личного проекта, над которым я работаю, я пытаюсь отделить встроенные даты от различных текстовых источников.

Например, у меня есть большой список строк (которые обычно принимают форму английских предложений или операторов), которые принимают различные формы:

Заседание центральной проектной комиссии Вторник 10/22 6:30 вечера

Th 9/19 LAB: последовательное кодирование (раздел 2.2)

15 декабря будет еще один для тех, кто неспособен сделать это сегодня.

Рабочая тетрадь 3 (минимальная заработная плата): срок Среда 9/18 23:59

Он будет летать 15 сентября.

Хотя эти даты совпадают с естественным текстом, ни одна из них сама по себе не является собственно естественными языковыми формами (например, нет "Встреча будет через две недели с завтрашнего дня" - все это явно).

Как у кого-то, у кого нет слишком большого опыта работы с такой обработкой, что было бы лучше всего начать? Я просмотрел такие вещи, как модуль dateutil.parser и parsedatetime, но, похоже, это происходит после того, как вы выделили дату.

Из-за этого есть ли хороший способ извлечь дату и посторонний текст

input:  Th 9/19 LAB: Serial encoding (Section 2.2)
output: ['Th 9/19', 'LAB: Serial encoding (Section 2.2)']

или что-то подобное? Похоже, что подобная обработка выполняется такими приложениями, как Gmail и Apple Mail, но возможно ли реализовать их на Python?

Ответы

Ответ 1

Я также искал решение этого и не мог найти ни одного, поэтому мы с другом создали инструмент для этого. Я думал, что вернусь и поделись тем, что другие считают полезным.

datefinder - найти и извлечь даты внутри текста

Ответ 2

Если вы можете определить сегменты, которые на самом деле содержат информацию о дате, их анализ может быть довольно простым с parsedatetime. Однако следует учитывать несколько моментов, а именно то, что у ваших дат нет лет, и вы должны выбрать локаль.

>>> import parsedatetime
>>> p = parsedatetime.Calendar()
>>> p.parse("December 15th")
((2013, 12, 15, 0, 13, 30, 4, 319, 0), 1)
>>> p.parse("9/18 11:59 pm")
((2014, 9, 18, 23, 59, 0, 4, 319, 0), 3)
>>> # It chooses 2014 since that the *next* occurence of 9/18

Это не всегда работает идеально, если у вас есть посторонний текст.

>>> p.parse("9/19 LAB: Serial encoding")
((2014, 9, 19, 0, 15, 30, 4, 319, 0), 1)
>>> p.parse("9/19 LAB: Serial encoding (Section 2.2)")
((2014, 2, 2, 0, 15, 32, 4, 319, 0), 1)

Честно говоря, это похоже на проблему, которая была бы достаточно простой, чтобы проанализировать определенные форматы и выбрать наиболее вероятное из каждого предложения. Кроме того, это была бы достойная проблема машинного обучения.

Ответ 3

import datefinder
string_with_dates = """
                    entries are due by January 4th, 2017 at 8:00pm
                    created 01/15/2005 by ACME Inc. and associates.
                    """
matches = datefinder.find_dates(string_with_dates)
for match in matches:
    print match

Ответ 4

Я удивлен отсутствием упоминания о методах SUTime и dateparser search_dates.

from sutime import SUTime
import os
import json
from dateparser.search import search_dates

str1 = "Let meet sometime next Thursday" 

# You'll get more information about these jar files from SUTime github page
jar_files = os.path.join(os.path.dirname(__file__), 'jars')
sutime = SUTime(jars=jar_files, mark_time_ranges=True)

print(json.dumps(sutime.parse(str1), sort_keys=True, indent=4))
"""output: 
[
    {
        "end": 33,
        "start": 20,
        "text": "next Thursday",
        "type": "DATE",
        "value": "2018-10-11"
    }
]
"""

print(search_dates(str1))
#output:
#[('Thursday', datetime.datetime(2018, 9, 27, 0, 0))]

Хотя я пробовал другие модули, такие как dateutil, datefinder и natty (не мог заставить утенка работать с python), эти два, похоже, дают наиболее многообещающие результаты.

Результаты от SUTime более надежны, и это видно из приведенного выше фрагмента кода. Тем не менее, SUTime не работает в некоторых основных сценариях, таких как анализ текста

"Я не буду доступен до 19 сентября"

или

"I won't be available between (September 18-September 20).

Это не дает результата для первого текста и только дает месяц и год для второго текста. Это, однако, обрабатывается довольно хорошо в методе search_dates. Метод search_dates более агрессивен и выдаст все возможные даты, связанные с любыми словами во входном тексте.

Я еще не нашел способ разобрать текст строго по датам в search_methods. Если бы я мог найти способ сделать это, это будет мой первый выбор по сравнению с SUTime, и я также обязательно обновлю этот ответ, если найду его.

Ответ 5

Привет, я не уверен, что подход - это машинное обучение, но вы можете попробовать:

  • добавить некоторый контекст из внешнего текста, например, время публикации текстового сообщения, проводки, теперь и т.д. (ваш текст ничего не сообщает о году)
  • извлеките все маркеры с пробелом разделителя и получите что-то вроде этого:

    ['Th','Wednesday','9:34pm','7:34','pm','am','9/18','9/','/18', '19','12']
    
  • обрабатывать их с помощью наборов правил, например, начиная с будних дней и/или вариантов компонентов, формирующих время и маркирующих их, например. '% d:% dpm', '% d am', '% d/% d', '% d/% d' и т.д. может означать время.  Следует отметить, что он может содержать композиции, например. "12/31" - 3грамма ( "12", "/", "31" ) - это один токен "12/31".

  • "см.", какие жетоны обозначены маркерами вроде "9:45 pm", например ( "Th", "9/19", "9:45 pm" ) составляет 3gram из "интересных" токенов и применяют правила об этом, который может определить смысл.

  • для более конкретного анализа, например, если есть 31/12, поэтому 31 > 12 означает d/m или наоборот, но если они имеют 12/12 м, d будут доступны только в контексте построения из текста и/или снаружи.

Приветствия

Ответ 6

Вы можете использовать метод модуля dateutilparse с опцией fuzzy.

>>> from dateutil.parser import parse
>>> parse("Central design committee session Tuesday 10/22 6:30 pm", fuzzy=True)
datetime.datetime(2018, 10, 22, 18, 30)
>>> parse("There will be another one on December 15th for those who are unable to make it today.", fuzzy=True)
datetime.datetime(2018, 12, 15, 0, 0)
>>> parse("Workbook 3 (Minimum Wage): due Wednesday 9/18 11:59pm", fuzzy=True)
datetime.datetime(2018, 3, 9, 23, 59)
>>> parse("He will be flying in Sept. 15th.", fuzzy=True)
datetime.datetime(2018, 9, 15, 0, 0)
>>> parse("Th 9/19 LAB: Serial encoding (Section 2.2)", fuzzy=True)
datetime.datetime(2002, 9, 19, 0, 0)

Ответ 7

Более новые версии parsedatetime lib предоставляют функции поиска.

Пример

from dateparser.search import search_dates

dates = search_dates('Central design committee session Tuesday 10/22 6:30 pm')