Как почистить данные, не удаляя лишние знаки

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

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

Задача:найти сотрудников компании, зарегистрировавшихся на сайте облачного сервиса;Дано:таблица cloud — данные всех зарегистрированных пользователей нового сервиса,таблица employees_hr — внутренняя информация о сотрудниках;

Все данные сгенерированы, любые совпадения случайны.

# загружаем данные: # таблица со списком людей, зарегистрированных в новом сервисе cloud = pd.read_excel('DA.xlsx') # данные сотрудников компании employees_hr = pd.read_excel('HR.xlsx')

Первые строки датасетов:

cloud:

Как почистить данные, не удаляя лишние знаки

employees_hr:

Как почистить данные, не удаляя лишние знаки

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

Чтобы извлечь почту и телефон, можно использовать парсер библиотеки Natasha. Но есть способ намного проще и быстрее. Используем токенайзер, который входит в этот модуль. Он не просто разбивает текст на единицы, а формирует линейную последовательную структуру с информацией по каждому токену:

some_text = '''Как и два года назад, ключевыми факторами, которые влияют на деятельность подразделения, респонденты называют нехватку кадровых ресурсов (78%) и большие затраты времени на получение необходимой информации (88%).''' # инициализируем токенайзер: tokenizer = Tokenizer() # токенайзер возвращает генератор, поэтому понадобится упаковать все значения в список tokens = list(tokenizer(some_text))

Вывод:

[… Token( value='два', span=[6, 9), type='RU' ), Token( value='года', span=[10, 14), type='RU' ), Token( value='назад', span=[15, 20), type='RU' ), Token( value=',', span=[20, 21), type='PUNCT' )…]

Такая структура содержит извлекаемые атрибуты: из нее можно вытащить и значение, и координаты, и тип токена. Она полезна не только для простого извлечения нужных объектов, но и может пригодиться, например, для анализа координат разных типов токенов.

И парсер, и токенайзер работают на правилах, однако парсер – высокоуровневый модуль, позволяющий извлечь намного более сложные структуры и получить разветвленную характеристику токена (в основном благодаря классу MorphTokenizer(), но сейчас не о нём). Стандартный токенайзер (Tokenizer()) – гибкий и простой в использовании инструмент, он работает быстрее парсера (особенно на больших данных).

Разметка токенов (‘type’ в структуре) производится регулярными выражениями. В токенайзере есть очень удобный метод ‘add_rules’, позволяющий встраивать правила для разметки токенов определенного типа. Если нужного правила нет, можно создать собственное:

# создаем новое правило, выделяющее число процентов из текста PERCENT = TokenRule('PERCENT', '\\d+[%]') # добавляем готовое правило tokenizer = Tokenizer().add_rules(PERCENT) # разбиваем текст на токены list(tokenizer(some_text))

Вывод:

[… Token( value='кадровых', span=[119, 127), type='RU' ), Token( value='ресурсов', span=[128, 136), type='RU' ), Token( value='(', span=[137, 138), type='PUNCT' ), Token( value='78%', span=[138, 141), type='PERCENT' ), Token( value=')', span=[141, 142), type='PUNCT' )…]

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

def email_extract(text): #добавляем правило нахождения почты tokenizer = Tokenizer().add_rules(EMAIL_RULE) # разбиваем на токены tokens = list(tokenizer(text)) # берем из результата только те значения, тип которых равен ‘email’ emails = [token.value for token in tokens if token.type=='EMAIL'] return emails #аналогично для номера телефона def phone_number_extract(text): tokenizer = Tokenizer().add_rules(PHONE_RULE) tokens = list(tokenizer(text)) phone_numbers = [token.value for token in tokens if token.type=='PHONE'] return phone_numbers # перезаписываем столбцы, заполняя их извлеченными строками (если нужен анализ результата, или # есть риск потерять исходные данные, лучше записать в новые столбцы): cloud['email'] = cloud['email'].apply(email_extract()) cloud['телефон'] = cloud['телефон'].apply(phone_number_extract()) employees_hr['email'] = employees_hr['email'].apply(email_extract()) employees_hr['телефон'] = employees_hr['телефон'].apply(phone_number_extract())

Вывод:

Как почистить данные, не удаляя лишние знаки

Как можно заметить, от двойного постфикса в адресе почты это не спасло. Однако теперь мы знаем ограниченный набор искажений в данных. Уберем их привычным способом:

cloud.replace({'email' : {'.ru.ru' : '.ru', '.com.com' : '.com'}}, inplace=True)

Готово! Данные очищены. Осталось самое простое — сгруппировать таблицы по имени и номеру телефона и посмотреть совпадения. Объединяем по указанным столбцам:

registered = pd.merge(cloud, employees_hr, on=[‘ФИО’, ‘телефон’])

Получаем вывод:

Как почистить данные, не удаляя лишние знаки

Из 29 уникальных записей о сотрудниках в выгрузке HR нашлись 3 (9,6%). Передадим эти данные специалистам по рекламе.

На этом выбор инструментов модуля не заканчивается. Отдельного внимания стоит класс MorphTokenizer(), который подключает pymorphy2 для характеристики токена. Некоторые задачи требуют исследования или извлечения словоформ, и подобные инструменты значительно упростят обработку текста.

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

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