Feature Engineering, о чём молчат online-курсы

frhzi1pq96guehwq2vi76noee3g.jpeg
Sherlock by ThatsWhatSheSayd


Чтобы стать великим сыщиком, Шерлоку Холмсу было достаточно замечать то, чего не видели остальные, в вещах, которые находились у всех на виду. Мне кажется, что этим качеством должен обладать и каждый специалист по машинному обучению. Но тема Feature Engineering«а зачастую изучается в курсах по машинному обучению и анализу данных вскользь. В этом материале я хочу поделиться своим опытом обработки признаков с начинающими датасаентистами. Надеюсь, это поможет им быстрее достичь успеха в решении первых задач. Оговорюсь сразу, что в рамках этой части будут рассмотрены концептуальные методы обработки. Практическую часть по этому материалу совсем скоро опубликует моя коллега Osina_Anya.


Один из популярных источников данных для машинного обучения — логи. Практически в любой строчке лога есть время, а если это web-сервис, то там будут IP и UserAgent. Рассмотрим, какие признаки можно извлечь из этих данных.


Время


UnixTimestamp


UnixTimestamp — это количество секунд, прошедшее с 1970–01–01 00:00:00.000, популярное представление времени, натуральное число. Можно в модель добавить время в этом формате, но такой подход чаще работает в задачах регрессии. В задачах классификации он работает редко, так как в UnixTimestamp-формате сохраняется только информация о последовательности событий, а о днях недели, месяцах, часах и т. д. модель ничего знать не будет.


Год, месяц, день, часы, минуты, секунды, день недели


Часто время добавляют в модель в виде набора натуральных чисел: отдельно год, отдельно номер месяца и т. д. до нужной детализации. Например, 2017–09–08 12:07:12.997 можно преобразовать в пять признаков: 2017, 09, 08, 12, 07. Ещё можно добавить бинарный признак: выходной день или нет, время года, рабочее время или нет — и т. д., и т. п. Удачный набор таких признаков чаще всего позволяет решить задачу c высоким качеством. Иногда работает метод Создание OneHotEncoding признаков на месяцы/годы, но это скорее экзотика, нежели практика.


Отображение на круг


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


Допустим, у нас есть задача: по текущему времени определить, зачем человек взял в руки мобильный телефон — отключить звук или поставить будильник. При этом мы видим по историческим данным, что человек ставит будильник с 23.00 до 01.00, а выключает звук с 07.00 до 21.00. Если мы станем решать задачу логистической регрессией, то ей надо будет построить разделяющую плоскость для следующей картинки:


glaqc7gv33obc0nrvxv94kvn9ae.png


Очевидно, что она не сможет этого сделать: такое представление времени теряет информацию о том, что 23.00 и 01.00 — это очень близкие события. В данном случае можно добавить квадратичные признаки, но у меня есть способ получше! Для решения таких проблем пригодится следующий приём: берём признак, о котором мы знаем, что он меняется по циклу. Например, «час» — он меняется от 0 до 23. И превращаем его в два признака: cos («час» 2 pi / 24), sin («час» 2 pi / 24), т. е. мы равномерно распределили все элементы цикла по единичной окружности с центром в 0 и диаметром 1.


jkhcdjjhz_xly5pgekbsnkvi-0o.png


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


IP-адрес


Немного слов об IP


На первый взгляд IP-адрес — важный признак, но что с ним делать — совершенно непонятно. Наиболее распространённый сейчас вариант — это IPV4, т. е. последовательность из 4 байтов, традиционно записываемых в виде »255.0.0.1». Работать с этими числами или со всем IP как с числовыми признаками абсолютно некорректно. Если у вас есть два IP-адреса — 123.123.123.123 и 124.123.123.123, — то близость этих чисел совершенно ничего не значит (первый — это China Unicom Beijing province network, второй — Beam Telecom Pvt Ltd). Корректно было бы рассматривать IP как категориальный с выделением подсетей, но у больших сервисов таких категорий очень много. Например, если рассматривать категории по подсетям третьего уровня, то их получается 2^24 — ~10^16. Чтобы обучить модель более чем с 16 миллионами признаков, нужно действительно много данных, и, скорее всего, они создадут ненужный шум.


m7hrxvwpjp_fbx3sunpmcaxtg3k.png


https://xkcd.com/742/


Геолокация


На самом деле из IP достаётся гораздо больше информации, чем просто разбиение по сетям. Так, из IP-адреса с хорошей точностью извлекается страна, регион, а иногда даже город, в котором находился пользователь сервиса. Для этого можно использовать:


  1. Открытые GeoIP-базы, которых сейчас в избытке, многие из них предоставляют бесплатное API. Главное — не слишком их нагружать (не более 100—1000 запросов в минуту). Если вам нужны большие объёмы данных, то можно купить регулярно обновляемые базы у таких компаний, как MindMax.
  2. Сервис WhoIs, где опубликована публичная информация о владельцах многих IP-адресов (в случае обычных пользователей — об их провайдерах). Для получения этих данных можно воспользоваться одним из WhoIs-сервисов, например https://www.nic.ru/whois/, или Python-пакетом. Например, сейчас у моего мобильного телефона IP-адрес 176.59.41.95. Сервис WhoIs показывает, что IP принадлежит российскому Tele2. Можно проделать такую же операцию с любым IP и узнать его страну, но количество информации, предоставляемой о владельце IP-адреса, отличается от случая к случаю. Кроме того, не стоит забывать, что есть особые IP-адреса, о них можно почитать тут.


Внимательно обходитесь с данными, полученными об IP из подобных сервисов. Данные иногда устаревают, иногда бывают ошибочны, а IP-адреса мобильных операторов связи — вообще большая проблема, так как нередко вы можете через одного оператора с одним и тем же IP выйти как из Москвы, так и из Владивостока. Поэтому я рекомендую формировать эти дополнительные поля к логу в момент его получения, а не позже, в момент сбора признаков, так как у вас уже может не быть версии базы на тот момент, как случилось описанное в логе событие. Плюс подхода: вы сможете отследить тот факт, что какой-то IP, встречавшийся в России, перешёл в Европу, или наоборот. Но даже с этими оговорками данная функция очень полезна для анализа данных и способна значительно повысить качество модели.


Постскриптум для этого пункта


Если ваш сервис достаточно большой, то вы можете сами собирать GeoIP-базы. Если пользователь предоставит вашему сайту/приложению доступ к своей геолокации, то вы автоматически получите информацию о расположении конкретных IP-адресов. Только вам придётся придумать, как быть с некорректными геолокациями и IP-адресами, которые имеют широкую географию. Кроме того, пользуясь этим приёмом, можно предполагать, откуда заходил пользователь: из дома, с работы, находясь в дороге.


Чистота IP-адреса


Для анализа данных иногда стоит отфильтровывать действия настоящих пользователей от действий ботов, поисковых роботов и подобной «нечисти». В исходной формулировке эта задача очень сложная, используемая во многих областях, например антиспаме и антифроде. Но для задачи фильтрации данных иногда хватает и более простых методов — фильтрации по IP. Так, в интернете можно найти открытые списки IP-адресов, с которых часто проводятся фрод- и ддос-атаки, IP-адреса tor-exitnode (боты часто используют их для обхода блокировки IP за частые запросы к сервису) и IP-адреса открытых прокси-серверов (иногда применяются для тех же целей). Так, можно добавить в вектор признаков флаг «наличие IP-адреса в этих базах». Кроме того, по историческим данным вы можете считать вероятность встретить такого же провайдера, что и у IP-адреса в данной строке лога. Эта вероятность тоже может быть признаком, только у него есть гиперпараметр: как далеко смотреть историю, чтобы считать вероятность. Это важно, так как распределение пользователей и, как следствие, распределение провайдеров пользователей на сервисе меняется.


Возвращаясь к вопросу фильтрации «плохих» пользователей, отмечу: стандартная практика — фильтрация логов с IP-адресов, фигурировавших в доверенных чёрных списках. При этом пользователи, их инициировавшие, не принадлежат к списку пользователей, недавно совершавших доверенные действия. Оба этих условия одинаково важны, так как даже хорошие пользователи иногда обращаются к Tor«у и прокси-серверам, но аккаунт хорошего пользователя может быть взломан. Поэтому действие, характеризующее его как настоящего человека, должно произойти недавно.


UserAgent


Немного о UserAgent


Если мы говорим об HTTP-протоколе, то программное обеспечение, которое отправляет запрос на ваш сервер, в заголовке запроса передаёт поле User-Agent, в котором содержится информация о версии программного обеспечения и операционной системы. С помощью этого поля заголовка часто происходит перенаправление на мобильную версию сайта или на версию сайта без использования JS. Кроме версии браузера и операционной системы, в UserAgent может содержаться и другая полезная информация, но её иногда непросто достать. Дело в том, что единого утверждённого формата для строки User-Agent«а нет, и каждый пишет туда информацию так, как захочет. Есть много различных библиотек, позволяющих извлечь из строки UserAgent браузер и операционную систему, и их можно выбирать на свой вкус. Лично мне нравится https://github.com/ua-parser.


ОС, ПО, что сложного?


Браузер и операционную систему можно добавить как категориальный признак, воспользовавшись OneHotEncoding, даже тип устройства достаётся. Только для этого нужно аккуратно смотреть и на браузер, и на операционную систему. Но в UserAgent ещё можно опознать поисковых ботов, скрипты на Python, программы и кастомные сборки браузеров, использующие WebKit. Только с этим многообразием возможностей приходит и многообразие проблем. Записать в UserAgent-строку можно всё что угодно, и этим пользуются разработчики вредоносного ПО: для вашего сервера всё будет выглядеть так, будто к вам пришёл обычный пользователь с браузером Chrome и Windows 10 на компьютере. Поэтому надо относиться очень аккуратно к данным из UserAgent и следить за аномалиями в статистике версий браузеров. В ней вы можете заметить, что очень старая версия хрома гораздо популярней последней, или увидеть «вспышки» из старых андроидов. Кроме того, поможет частотный анализ, как и в случае с IP. Чаще всего разработчики роботов не знают распределения браузеров у вашей целевой аудитории и берут UserAgent из своих баз данных о распределении UserAgent среди пользователей интернета, а базы могут устаревать, не соответствовать географии, целевой аудитории вашего сервиса и т. д. Но все эти трудности — не повод не пользоваться этими данными. Это повод посмотреть на них внимательнее и извлечь ещё больше полезной информации.


Заключение


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


Спасибо за внимание — и удачи!

© Habrahabr.ru