#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. Очень признателен. Я думаю, что хорошо иметь более одного решения….