Извлечение текста из набора данных - PullRequest
3 голосов
/ 07 ноября 2019

Я работаю над набором данных, в котором мне нужно извлечь все доступные даты. Даты могут быть в следующем формате:

04/20/2009; 04/20/09; 4/20/09; 4/3/09
Mar-20-2009; Mar 20, 2009; March 20, 2009; Mar. 20, 2009; Mar 20 2009;
20 Mar 2009; 20 March 2009; 20 Mar. 2009; 20 March, 2009
Mar 20th, 2009; Mar 21st, 2009; Mar 22nd, 2009
Feb 2009; Sep 2009; Oct 2010
6/2008; 12/2009
2009; 2010

Я написал следующий код:

df['dates'] = df['text'].str.extract(r'((?:\d{1,2}[/ ])?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec[a-z.,]*[- ])?(?:\d{1,2}[a-z-, /]{1,4})?(?:\d{2,4}))')

Это дает мне правильный результат, за исключением некоторого текста, такого как:

ВЫХОД ТЕКСТА

Лаборатория: B12 969 2007 \ n 12 969 # должен дать 2007

в течение 35 лет, продано в 1985 году \ n 35 # должен дать 1985

x 14 лет, которые умерли, я ... 14 # не следует считать

Я пытался изменить код извлечения на

r'((?:\d{1,2}[/ ])?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec[a-z.,]*[- ])?(?:\d{1,2}[a-z-, ]{1,4})?(?:[/]\d{2})?(?:\d{4})?)' 

Но с этим весь результат стал плохим

Ответы [ 3 ]

2 голосов
/ 07 ноября 2019

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

И это непросто: в выборке вводятся разные типы дат. Для этих входов я бы порекомендовал:

(?<!\d)((?<!\d[ \t])(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)(?:-\d{1,2}-\d{4}|(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?\s*\d{4})|\d{1,2}\s+(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)\.?,?\s*\d{4}|(?:\d{1,2}/)?\d{1,2}/\d{2}(?:\d{2})?|(?:19|20)\d{2})(?!\d)

См. Демоверсию regex . Соответствует:

  • (?<!\d) - отрицательный взгляд сзади: слева от текущего местоположения не допускается никакая цифра
  • ( - запуск внешней группы захвата (необходимодля .str.extract)
    • (?<!\d[ \t]) - не допускается ни цифра с пробелом или табуляцией непосредственно слева от текущего местоположения
    • (?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?) - названия месяцев с их сокращениями
    • (?:-\d{1,2}-\d{4}|(?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)?\s*\d{4}) - любой из двух вариантов:
      • -\d{1,2}-\d{4} - -, 1 или 2 цифры, -, а затем 4 цифры
      • | -или
      • (?:\.?\s*\d{1,2}(?:st|[rn]d|th)?,?)? - необязательная группа без захвата, которая соответствует 1 или 0 вхождениям:
      • \.? - необязательно .
      • \s* -0+ пробелы
      • \d{1,2} - 1 или 2 цифры
      • (?:st|[rn]d|th)? - необязательная последовательность символов: st, r или n, за которой следует d,или th
      • ,? - необязательная запятая
      • \s*\d{4} - 0+ пробелов и затем 4 цифры
  • | - или
    • \d{1,2}\s+ - 1 или 2 цифры, а затем 1+ пробелы
    • (?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?) - названия месяцев с их сокращениями (как указано выше)
    • \.? - необязательная точка
    • ,? - необязательная запятая
    • \s* - 0+ пробелов
    • \d{4} - четыре цифры
  • | - или
    • (?:\d{1,2}/)? - необязательная последовательность из 1 или 2 цифр, а затем /
    • \d{1,2} - 1 или 2 цифры
    • / -/
    • \d{2}(?:\d{2})? - 2 цифры и необязательная последовательность из 2 цифр (допускается 2 или 4 цифры, но не 3)
  • | - или
    • (?:19|20) - 19 или 20
    • \d{2} - две цифры
  • ) - конец захвата компьютераgroup
  • (?!\d) - отрицательный прогноз: справа от текущего местоположения не допускается никакая цифра.

В Python вы можете определить блоки для шаблона и построить егодинамически:

months = r'(?:A(?:pr(?:il)?|ug(?:ust)?)|Dec(?:ember)?|Feb(?:ruary)?|J(?:an(?:uary)?|u(?:ly|ne|[ln]))|Ma(?:rch|[ry])|Nov(?:ember)?|Oct(?:ober)?|Sep(?:tember)?)'
pattern = rf'(?<!\d)((?<!\d[ \t]){months}(?:-\d{{1,2}}-\d{{4}}|(?:\.?\s*\d{{1,2}}(?:st|[rn]d|th)?,?)?\s*\d{{4}})|\d{{1,2}}\s+{months}\.?,?\s*\d{{4}}|(?:\d{{1,2}}/)?\d{{1,2}}/\d{{2}}(?:\d{{2}})?|(?:19|20)\d{{2}})(?!\d)'
0 голосов
/ 07 ноября 2019

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

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

0 голосов
/ 07 ноября 2019

Попробуйте использовать pandas.to_datetime () , он преобразует наиболее распространенные форматы даты в объекты даты и времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...