Иллюстрация распространенных приложений с Python

Введение

Снова и снова специалисты по данным оказываются в ситуации, когда им необходимо определить, соответствуют ли определенные поля в их данных требуемому текстовому формату или присутствует или отсутствует конкретная строка. В других ситуациях им, возможно, придется заменить определенную строку в своих данных другой. Для этого они используют то, что стало нормой для подобных задач: регулярные выражения.

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

Что такое регулярные выражения?

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

Чтобы определить эти шаблоны поиска, необходимо ознакомиться с соответствующим синтаксисом. Подробная, но краткая шпаргалка по синтаксису регулярных выражений на основе Python предоставлена ​​Dataquest. Хотя в этой статье не рассматриваются все эти варианты использования, все же стоит выделить некоторые основные символы, используемые для определения шаблонов поиска (таблица 1).

Регулярные выражения в Python

Python предлагает модуль с именем re, который предоставляет обширный набор операций сопоставления регулярных выражений. Здесь мы сосредоточимся на четырех часто используемых модульных функциях:

  1. Поиск. Соответствует первому экземпляру выражения.
  2. Найти все. Соответствует всем экземплярам выражения.
  3. Sub: используется для замены строки другой.
  4. Разделить. Используется для разделения строки на основе указанного разделителя.

Давайте проиллюстрируем эти концепции далее, рассмотрев несколько конкретных примеров:

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.