Извлеките 1 и, возможно, 2 даты из строки в Панд в новые собственные столбцы

#python #pandas

Вопрос:

Я пытаюсь извлечь даты в формате ДД/ММ/ГГГГ из столбца фрейма данных pandas, содержащего различный текст, касающийся аренды недвижимости. В тексте в каждой строке содержится до 3 элементов данных:-

  • Срок аренды
  • Дата Начала Аренды
  • Дата окончания аренды

Примеры Входящих Строк

75 лет с 25.12.1975

125 лет с 14/3/2019 по 13/3/2144

с 18/02/2011 по 24/03/2156

Желаемый Результат

Для каждой строки:-

Извлеките 1-ю дату в строке в новый столбец Lease_Startdate

Извлеките 2-ю дату в строке (если она есть) в новый столбец Lease_Enddate

Требуется Помощь

Я в порядке, создав регулярное выражение для выбора формата даты DD/ММ/ГГГГ, но я не знаю, как распределить 1-ю строку в столбце Lease_Startdate и 2-ю строку в столбце Lease_Enddate. т. е. иметь дело с номером события

Большинство примеров, которые я видел здесь, ссылаются только на одну строку даты.

Я буду благодарен за любой совет…Спасибо, Марк

Комментарии:

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

Ответ №1:

Вы можете попробовать .str.extract с regex :

 (r'(?P<Lease_Startdate>d{1,2}/d{1,2}/d{4})'            # match the 1st date
 r'(?:.*(?P<Lease_Enddate>d{1,2}/d{1,2}/d{4}))?')      # optionally match the 2nd date
 

ДЕМОНСТРАЦИЯ:

 df = pd.DataFrame({'text': ['75 years from 25/12/1975', '125 years from 14/3/2019 until 13/3/2144', 'from 18/02/2011 to 24/03/2156']})
df.text.str.extract(
  r'(?P<Lease_Startdate>d{1,2}/d{1,2}/d{4})'
  r'(?:.*(?P<Lease_Enddate>d{1,2}/d{1,2}/d{4}))?',
  expand=True)

#  Lease_Startdate Lease_Enddate
#0      25/12/1975           NaN
#1       14/3/2019      3/3/2144
#2      18/02/2011     4/03/2156
 

Комментарии:

1. Спасибо за ответ Псидом…очень признателен. К сожалению, с меньшим

2. @pekoz1 Всегда пожалуйста. Вы можете принять ответ, если он вам подходит 🙂

3. Привет @psidom Просто пытаюсь использовать ваш ответ сегодня…. для строк, в которых присутствуют 2 даты, 2-я дата «Lease_enddate» пропускает 1-ю цифру. Таким образом, в демо выше 3/3/2144 должно быть 13/3/2144, а 4/03/2156 должно быть 24/03/2156. У вас есть какие-либо мысли относительно того, почему 2 цифры не записываются? Спасибо, Марк пекоз1 37 минут назад Удалил

Ответ №2:

Используйте pd.Series.str.extractall для захвата всех 3 групп за один раз:

 df = pd.DataFrame({"Text":["75 years from 25/12/1975",
                           "125 years from 14/3/2019 until 13/3/2144",
                           "from 18/02/2011 to 24/03/2156"]})

print (df["Text"].str.extractall("(?P<Dur>d )?. ?(?=d)(?P<Start>d /d /d ). ?(?=d)(?P<End>d /d /d )?")
                 .reset_index(drop=True))

   Dur       Start         End
0   75    25/12/19         NaN
1  125   14/3/2019   13/3/2144
2  NaN  18/02/2011  24/03/2156
 

Обратите внимание, что вам необходимо настроить шаблон регулярного выражения, если у вас больше вариантов ввода данных.

Комментарии:

1. Спасибо за ответ, Генри… очень признателен. К сожалению, с меньшим

2. Просто пытаюсь использовать ваш ответ сегодня …. для 1-й примерной строки «75 лет с 25/12/1975» последние 2 цифры года не возвращаются. Таким образом, он возвращает 25/12/19 вместо 25/12/1975 в качестве даты «начала». Однако, если я добавлю вторую дату в строку, дата начала будет работать правильно. Так что «75 лет с 25/12/1975 по 25/12/1985» — это нормально. Базовое регулярное выражение выбора даты кажется прекрасным. У вас есть какие-нибудь мысли относительно того, почему? Спасибо, Марк

Ответ №3:

Хотя в вопросе об этом не говорится, я опубликую ниже, если будет полезно, если в тексте есть даты в формате, например starting January 4th, 2017 (поскольку контракты могут содержать эти форматы).

 import datefinder # https://pypi.org/project/datefinder/
import pandas as pd
import re

df = pd.DataFrame({'Text':['75 years from 25/12/1975',
                           '125 years from 14/3/2019 until 13/3/2144',
                           'from 18/02/2011 to 24/03/2156',
                          'starting January 4th, 2017 and ending 13/3/2144']})

# currently looks like...
#                                               Text
# 0                         75 years from 25/12/1975
# 1         125 years from 14/3/2019 until 13/3/2144
# 2                    from 18/02/2011 to 24/03/2156
# 3  starting January 4th, 2017 and ending 13/3/2144



# compile a regex pattern to find a date
pattern = re.compile(r'(d{1,2}/d{1,2}/d{2,4})')

def findDates(s):
    # try to get datefinder to pull out the date
    d = pd.Series(datefinder.find_dates(s))
    if d.empty:
        # fallback is to use the regex
        d = pd.Series(pattern.findall(s))
        d = pd.to_datetime(d)
    return d

df[['Lease_Startdate', 'Lease_Enddate']] = df.apply(lambda x: findDates(x['Text']), axis=1)

print(df)
 

Выход:

     Text                                             Lease_Startdate    Lease_Enddate
0   75 years from 25/12/1975                              1975-12-25              NaT
1   125 years from 14/3/2019 until 13/3/2144              2019-03-14       2144-03-13
2   from 18/02/2011 to 24/03/2156                         2011-02-18       2156-03-24
3   starting January 4th, 2017 and ending 13/3/2144       2017-01-04       2144-03-13
 

Комментарии:

1. Спасибо за ответ MDR. Очень признателен. Я думаю, что хорошо иметь более одного решения….