Как использовать Регулярные выражения в Pandas для работы со строками

Как использовать Регулярные выражения в Pandas для работы со строками

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

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

Мы заметили несоответствующие столбцы в нашем недавнем конвейере данных из определённого источника. Нам нужен был только код office из этой колонки (это две или три буквы, за которыми следует двоеточие и двузначное число). Ранее мы использовали простую операцию замены, чтобы сопоставить столбец с желаемыми значениями. Но поскольку новые данные оказались несовместимыми с этим способом, нам пришлось изменить стратегию. Поскольку мы можем гарантировать согласованность шаблона, мы использовали регулярное выражение для их очистки. Таким образом, нам никогда не придётся беспокоиться об изменении значений в столбцах.

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

# With apply import re df.office.apply(lambda x: re.search(r'\d+', x).group(0)) # With native string operation df.office.str.extract(r'(\d+)')

Прежде чем мы обсудим преимущества этих API, по сравнению с методом map/apply, вот что я имею в виду:

Сравнение извлечения строки Pandas с обычным регулярным выражением

Следующий код генерирует синтетический набор данных с использованием Faker. Он генерирует 100 тысяч поддельных адресов и сохраняет их в серии Pandas. Если вам нужно, вы можете настроить их количество, изменив n на необходимое вам значение, которое может поддерживать ваш компьютер.

import pandas as pd from faker import Faker faker = Faker() n = 100000 address= pd.Series([faker.address() for i in range(n)]) """ | | address | |---:|:-----------------------------| | 0 | 548 Small Parkways Suite 832 | | | South Brianborough, DC 50474 | | 1 | 94291 Jerry Pass Suite 992 | | | East Rebecca, PR 87881 | | 2 | 3973 Wise Spring | | | Grantfort, AS 52002 | | 3 | 62589 David Island | | | East Kathleenville, OH 45208 | | 4 | 0415 Jimenez Hill Apt. 642 | | | Gambleland, WA 99356 | """

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

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

( (address) .map(lambda x: (re.search(r"\w{2} \d{5}", x).group())) .str.split(" ", expand=True) .rename(columns={0: "state", 1: "zip_code"}) ) """ | | state | zip_code | |---:|:--------|-----------:| | 0 | DC | 50474 | | 1 | PR | 87881 | | 2 | AS | 52002 | | 3 | OH | 45208 | | 4 | WA | 99356 | """

Приведённый выше код прост для понимания. Мы сопоставляем все две буквы, за которыми следует пробел и пять цифр. Затем мы выполняем разделение строки и расширяем её до отдельных столбцов. Наконец, мы присваиваем столбцам имена ‘state’ и ‘zip_code’.

Но вот как это реализовывает Pandas:

address.str.extract(r"(?P<state>\w{2}) (?P<zip_code>\d{5})") """ | | state | zip_code | |---:|:--------|-----------:| | 0 | DC | 50474 | | 1 | PR | 87881 | | 2 | AS | 52002 | | 3 | OH | 45208 | | 4 | WA | 99356 | """

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

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

Хорошо, первый метод превосходен по удобочитаемости. Но как насчёт производительности?

Я использовал утилиту timit в Jupyter notebook для записи времени выполнения. Я не вижу, чтобы первый способ давал преимущество в производительности. Маппинг происходит быстрее.

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

Как использовать Регулярные выражения в Pandas для работы со строками

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

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

Полезные строковые методы Pandas с регулярным выражением

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

Мы уже видели один пример использования extract API в предыдущем разделе. Он удобен при использовании регулярных выражений.

Вот три других метода, которыми я также пользуюсь.

1. Разделение текста на отдельные столбцы.

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

import pandas as pd # Create a sample dataframe df = pd.DataFrame( { "location": [ "New York 10001", "California 90001", "Texas-75201", "Georgia 30301", "Oregon97205", "Arizona 85001", "Illinois 60601", "Florida 33101", "Ohio 44101", "Pennsylvania-19104", ] } ) df["location"].str.split(r"[\s|-]*(\d{5})", expand=True) ''' | | 0 | 1 | |---:|:-------------|------:| | 0 | New York | 10001 | | 1 | California | 90001 | | 2 | Texas | 75201 | | 3 | Georgia | 30301 | | 4 | Oregon | 97205 | | 5 | Arizona | 85001 | | 6 | Illinois | 60601 | | 7 | Florida | 33101 | | 8 | Ohio | 44101 | | 9 | Pennsylvania | 19104 | '''

2. Фильтрование записей, содержащих текстовый шаблон где-то посередине.

У меня был набор данных, которые содержали серийные номера. У номера был определённый шаблон. Первые две буквы обозначают короткий код страны. Код местоположения следует за кодом страны. Это трёхзначное число. Затем дефис и идентификатор отдела, который представляет собой ещё одно трехзначное число.

Предположим, нам нужно отфильтровать все записи, относящиеся к финансовому департаменту стран, Великобритании, Индии и Австралии. Мы можем сделать что-то вроде этого:

import pandas as pd # Create a sample dataframe data = { "office_serial_number": [ "US101-001", "UK201-006", "CA301-003", "AU401-004", "UK202-005", "IN302-006", "IR102-007", "AU402-006", "SL303-009", "UK203-010", "FR403-011", "US103-012", ] } df = pd.DataFrame(data) df[df.office_serial_number.str.contains("^(UK|IN|AU)\d{3}-006")] ''' | | office_serial_number | |---:|:-----------------------| | 1 | UK201-006 | | 5 | IN302-006 | | 7 | AU402-006 | '''

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

3. Замена шаблонов новой строкой.

Замена - это частая операция со строкой. Даже в Excel мы часто это делаем. Но некоторые операции замены являются более сложными.

Нам нужно найти шаблоны и заменить их новыми строками.

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

Вот простой пример регулярного выражения для осуществления этого:

import pandas as pd import re # create a sample dataframe (dummy) df = pd.DataFrame({'phone': ["+1 555-555-5555", "+44 20 7123 4567", "+81 3-1234-5678", "0049 30 12345678", "+61 2 1234 5678", "+33 1 23 45 67 89", "+86 10 1234 5678", "011 52 55 1234 5678", "+971 4 123 4567", "+49 911 12345678", "(+81) 3-1234-5678"]}) # define a regular expression pattern to match the country code pattern = r'^\+?\d{1,3}[\s-]?' # match + or digit(s) followed by space/hyphen # apply the pattern to the 'phone' column and replace the matches with an empty string df['phone'] = df['phone'].apply(lambda x: re.sub(pattern, '', x)) print(df) phone 0 555-555-5555 1 20 7123 4567 2 3-1234-5678 3 30 12345678 4 2 1234 5678 5 1 23 45 67 89 6 10 1234 5678 7 52 55 1234 5678 8 4 123 4567 9 911 12345678 10 3-1234-5678

Заключение

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

Некоторые операции сложны даже для обработки с помощью базовых API языка программирования. Особенно те, где задействованы шаблоны. Для их реализации мы можем использовать регулярные выражения.

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

Я поделился с вами некоторыми трюками с регулярными выражениями в Pandas. Хотя каких-либо существенных улучшений производительности нет, я всё равно предпочитаю эти методы, потому что они просты.

Статья была взята из этого источника:

Начать дискуссию