Иллюстрация распространенных приложений с Python
Введение
Снова и снова специалисты по данным оказываются в ситуации, когда им необходимо определить, соответствуют ли определенные поля в их данных требуемому текстовому формату или присутствует или отсутствует конкретная строка. В других ситуациях им, возможно, придется заменить определенную строку в своих данных другой. Для этого они используют то, что стало нормой для подобных задач: регулярные выражения.
В этой статье будет кратко рассказано о том, что такое регулярные выражения, представлены некоторые основные символы, необходимые для формирования соответствующих шаблонов поиска, проиллюстрированы некоторые часто используемые функции в Python и, наконец, рассмотрены некоторые практические примеры использования, которые часто встречаются в повседневной жизни специалиста по данным. .
Что такое регулярные выражения?
Регулярное выражение или регулярное выражение — это набор символов, который позволяет выполнять поиск и, при желании, замену определенного текстового шаблона. Это чрезвычайно удобный метод, который могут применять специалисты по данным, чтобы обойти рутинную и громоздкую задачу ручного поиска.
Чтобы определить эти шаблоны поиска, необходимо ознакомиться с соответствующим синтаксисом. Подробная, но краткая шпаргалка по синтаксису регулярных выражений на основе Python предоставлена Dataquest. Хотя в этой статье не рассматриваются все эти варианты использования, все же стоит выделить некоторые основные символы, используемые для определения шаблонов поиска (таблица 1).
Регулярные выражения в Python
Python предлагает модуль с именем re, который предоставляет обширный набор операций сопоставления регулярных выражений. Здесь мы сосредоточимся на четырех часто используемых модульных функциях:
- Поиск. Соответствует первому экземпляру выражения.
- Найти все. Соответствует всем экземплярам выражения.
- Sub: используется для замены строки другой.
- Разделить. Используется для разделения строки на основе указанного разделителя.
Давайте проиллюстрируем эти концепции далее, рассмотрев несколько конкретных примеров:
import re # Defining the string upon which we'll run some regex operations s = "Paris is the capital of France. Also, Paris is a beautiful city." # Search re.search("Paris", s) >>> <re.Match object; span=(0, 5), match='Paris'> # Find All re.findall("Paris", s) >>> ['Paris', 'Paris'] # Sub re.sub("Paris", "Rome", s) >>> 'Rome is the capital of France. Also, Rome is a beautiful city.' # Split re.split("\. ", s) >>> ['Paris is the capital of France', 'Also, Paris is a beautiful city.']
Как и ожидалось, функция search возвращает только первый экземпляр выражения в виде объекта re.Match. С другой стороны, функция findall сопоставляет все экземпляры выражения и возвращает их в виде списка. С помощью функции sub можно заменить одну строку на другую — в этом случае Париж был заменен на Рим. Наконец, строку можно разбить с помощью функции split и указания определенного разделителя — в данном случае символа точки. Обратите внимание, что нам пришлось использовать escape-символ \
перед точкой, чтобы избежать его специального значения в регулярном выражении.
Полезность в науках о данных
Поиск на основе шаблонов — это концепция, с которой часто сталкиваются специалисты по данным. Давайте рассмотрим некоторые из них, чтобы подчеркнуть полезность наличия регулярных выражений в качестве инструмента в своем наборе инструментов.
Проверить формат текста
Довольно распространенным сценарием является анализ табличных данных, при котором задача состоит в том, чтобы проверить, соответствуют ли поля в конкретном столбце желаемому формату. Предположим, у нас есть какие-то надуманные данные в файле с именем sample.csv
, который содержит следующие столбцы: адрес электронной почты, город, штат и почтовый индекс (таблица 2).
Теперь мы хотели бы убедиться, что все адреса электронной почты имеют формат [email protected]
. Используя регулярные выражения, мы можем сделать следующее:
import re import pandas as pd df = pd.read_csv("sample.csv") # Define pattern that matches the email format [email protected] pattern = "^[a-z]+\.+[a-z][email protected]$" # Iterate through rows and print those that do not match for index, row in df.iterrows(): match = re.search(pattern, row.Email) if match == None: print(index, *row) # Output >>> 0 [email protected] Pasadena California 91103 >>> 3 [email protected] Kailua Hawaii 96734
Функция search вернет None
, если шаблон не соответствует введенной строке. Если мы распечатаем эти сценарии, мы сразу же обнаружим, что имя и фамилия адреса электронной почты в строке 0 не разделены точкой и что адрес электронной почты в строке 3 использует Hotmail вместо Gmail.
Аналогичным образом мы можем проверить, соответствуют ли почтовые индексы в данных стандартному 5-значному формату.
# Define pattern that matches 5-character strings comprised of all digits pattern = "^\d{5}$" for index, row in df.iterrows(): match = re.search(pattern, row.ZIP) if match == None: print(index, *row) # Output >>> 2 Kirkland Washington 9560
Мы видим, что в строке 2 почтовый индекс ошибочен, так как состоит всего из четырех цифр.
Тот же принцип можно применить для различных записей полей, зависящих от формата, таких как даты, URL-адреса, номера телефонов, IP-адреса, номера социального страхования и т. д.
Обнаружение запутанных слов
Текст можно анализировать на наличие определенных фраз, слов или их обфускаций. Например, спамеры склонны запутывать определенные слова в надежде обойти спам-фильтры. Например, можно использовать j@ckpot, jackp0t,илиj@ackp0tвместо jackpot. Регулярное выражение может гарантировать захват не только интересующего слова, но и некоторых его обфускаций:
import re # Define pattern capable of handling some obfuscations of "jackpot" pattern = "^j[a@]ckp[o0]t$" re.search(pattern, "j@ckpot") re.search(pattern, "jackp0t") re.search(pattern, "j@ckp0t") # Outputs >>> <re.Match object; span=(0, 7), match='j@ckpot'> >>> <re.Match object; span=(0, 7), match='jackp0t'> >>> <re.Match object; span=(0, 7), match='j@ckp0t'>
Здесь мы определяем набор символов, которые будут сопоставляться в определенной позиции, например, [a@]
в позиции 1 и [o0]
в позиции 5. В результате все наши вышеупомянутые запутывания слова джекпот сопоставляются.
Правильные форматы или написание
Предположим, у нас есть текстовые данные, включающие даты в американском формате, то есть MM/DD/YYYY
. Однако мы хотели бы преобразовать все даты в этом корпусе в более широко используемый формат DD/MM/YYYY
. Опять же, для решения этой конкретной проблемы можно применить регулярные выражения:
import re string = "I have a dentist appointment on 04/06/2023 at 10:00 AM." # Define pattern capable of capturing data format pattern = "(\d{1,2}/)(\d{1,2}/)(\d{4})" # Substitute days and months re.sub(pattern, r"\2\1\3", string) # Output >>> 'I have a dentist appointment on 06/04/2023 at 10:00 AM.'
Мы успешно заменили 06.04.2023 на 04.06.2023. В частности, мы группируем выражения, соответствующие месяцу (группа 1), дню (группа 2) и году (группа 3), используя ( )
. Для того, чтобы поменять местами месяц и день, нужно просто указать нужный порядок групп в аргументе замены — в нашем случае r"\2\1\3"
. Обратите внимание, что здесь мы используем нотацию необработанной строки, чтобы избежать специальной обработки обратной косой черты, которая в противном случае возникла бы в строковом литерале без префикса r
.
Подобные методы можно применять для исправления орфографии в текстовом документе, например, заменяя серый на серый или наоборот.
Приложения в вычислительной биологии
Еще одна область, в которой широко используются регулярные выражения, — вычислительная биология. Белки состоят из цепочки аминокислот, которые после складывания в окончательную трехмерную структуру обычно выполняют определенную функцию в нашем организме. Обнаружение присутствия или отсутствия определенных структурных мотивов — короткого аминокислотного паттерна, связанного с различными функциями — может иметь решающее значение для лучшего понимания его возможной функциональности.
Допустим, у нас есть список коротких белков, и мы хотели бы найти те, которые содержат следующий мотив: xC[DA]GG{Y}
. Это биологическая запись, которая интерпретируется следующим образом: любая аминокислота (x), затем цистеин (C), затем либо аспарагиновая кислота (D), либо аланин (A), затем два последовательных глицина (G), затем любой аминокислота, кроме тирозина (Y). Используя регулярные выражения в Python, мы можем обнаружить белки с этим мотивом следующим образом:
import re # Define pattern capable of matching the above-mentioned motif pattern = ".C[DA]GG[^Y]" proteins = ['AARKYL', 'LELCDGGPG', 'RAAANCDD', 'LYYRCAGGEGPGG', 'CAEELR'] for prot in proteins: match = re.search(p, prot) if match: print(prot, match) # Output >>> LELCDGGPG <re.Match object; span=(2, 8), match='LCDGGP'> >>> LYYRCAGGEGPGG <re.Match object; span=(3, 9), match='RCAGGE'>
Этот подход правильно идентифицирует два белка, которые содержат желаемый мотив, который мы искали.
Заключение
Как мы видели, регулярные выражения невероятно полезны в самых разных дисциплинах, от фильтров спама в электронной почте до вычислительной биологии. В этой статье демонстрируется лишь несколько сценариев, в которых обычно применяются регулярные выражения, но область их применимости действительно широка. Хотя у них есть ограничения и, конечно, они не являются панацеей от всех проблем с обработкой текста, регулярные выражения следует рассматривать как важный инструмент в наборе инструментов каждого специалиста по данным.
Рекомендации
[1] Памятка по науке о данных. Датаквест. Получено 4 января 2023 г. с https://www.dataquest.io/wp-content/uploads/2019/03/python-regular-expressions-cheat-sheet.pdf.
[2] Операции с регулярными выражениями. Питон. Получено 4 января 2023 г. с https://docs.python.org/3/library/re.html.