В рамках ICBDA 2015 Сбербанк проводил конкурс про предсказание оттока своих клиентов. Я неслабо заморочился по этому поводу, ничего не выиграл и тем не менее хотел бы описать процесс решения.


Сбербанк щедро отгрузил данных. Нам дали ~20 000 пользователей, про которых было известно попали они в отток в ноябре, декабре, январе или нет. И было ~30 000 пользователей, для которых нужно было угадать уйдут ли они в феврале. Кроме этого прилагался файлик на 35Гб примерно такого содержания:
Сорри, НДА

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

Выяснилось невероятное: если пользователь не ушёл в ноябре и декабре, то и в январе он скорее всего не уйдёт. Если пользователь ушёл, то он скорее всего не вернётся:


Кроме этого оказалось, что 70% пользователей из тестовой выборки есть в обучающей. То есть напрашивается следующий гениальный классификатор: если пользователь ушёл в январе, то он будет в оттоке и в феврале, если не ушёл в январе, то и в оттоке его не будет. Чтобы прикинуть качество такого решения, берём всех пользователей из января и делаем для них предсказание по данным за декабрь. Получается не очень, но лучше чем ничего:


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

Чтобы как-то улучшить решение, всё-таки придётся поразбираться в гигантском файле без описания. Первым делом я решил выкинуть все записи, в которых id не принадлежит ни одному пользователю из обучающей или тестовой выборки. О ужас, ни одной записи выкинуть не удалось. Одному пользователю там соответствует ни одна, а, в среднем, 300 записей. То есть, это какие-то логи, а не агрегированные данные. Кроме того, 50 из 60 колонок — это хеши. Логи с хешами вместо значений. В моём представлении это полный бред. Я люблю анализ данных за те моменты, когда удаётся открывать какие-то новые знания. В данном случае открытия могут выглядеть так: «если у пользователя в седьмом столбике часто встречается 8UCcQrvgqGa2hc4s2vzPs3dYJ30= значит, наверное, он скоро уйдёт». Не очень интересно. Тем не менее я решил проверить несколько гипотез, посмотреть, что получится.

Известно, что в каждой строчке лога есть два id, а не один. Поэтому я предположил, что мы работаем с какими-то транзакциями. Чтобы как-то это проверить, был построен граф, где в вершинах располагались id, а рёбра появлялись, если два id встречались в одной записи. Если в логе действительно транзакции, граф должен получится очень разреженным и должен хорошо группироваться в кластеры. Получилось не совсем то, что я ожидал, между кластерами на глаз было много связей:


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


Хорошо, если мы имеем дело с транзакциями, логичным дополнением к модели будет число входящих и исходящих транзакций. Действительно, среди тех, кто ушёл в январе, почти 40% имели менее десяти входящих транзакций.


Добавим это нехитрое условие в модель и получим уже неплохое качество:


Понятно, что просто количество транзакций — это не очень круто. Пользователь может сделать 500 транзакций в январе 2014 и легко уйти в январе 2015. Нужно смотреть на тренд. У утёкших, действительно, всё заканчивается на первом, втором месяце:


А у тех, кто остался историй посложнее:


Как-то просто добавить это условие в модель мне не удалось, поэтому пришлось обратиться к машинному обучению. Запили RandomForest на 500 деревьев глубиной 10 на фичах типа: «месяцев до первой транзакции», «месяцев до последней транзакции», «число месяцев с транзакциями». Качество немного подросло:


Резерв простых понятных решений был исчерпан. Поэтому пришлось закопаться в гигантский файл без описания ещё глубже. Для всех колонок было посчитано сколько уникальных значений там встречается.


Почему число уникальных значений дробное? Потому что пришлось использовать хитрый метод подсчёта уникальных значений с фиксированной памятью. Если всё просто запихивать в сеты, памяти не напасёшься.

Затем для колонок, в которых разумное число разных значений были посчитаны гистограммы:


Видно, что некоторые гистограммы похожи, например, 14 и 33, 22 и 41. Действительно, большинство полей идут парами (да, я вручную запилил граф корреляции признаков):


То есть часть колонок описывают id1, часть id2. Некоторые поля являются признаками транзакции. Чтобы наверняка убедиться какие колонки описывают пользователя, я посчитал как часто для одного id они принимают разные значения. Оказалось, что колонки с 5 по 15 почти никогда не принимают больше одного значения на id. Действительно, некоторые из них это название города, почтовый индекс. Они вошли в модель как категориальные. Остальные могут принимать разные значения для одного id (в основном null, конечно), поэтому они вошли в модель с весами.


Из-за всех этих категориальных фичей сложность модели очень сильно увеличилась, большинство новых признаков особого вклада не внесли. Но нашлась одна фича — 56-я. Она сильно повлияла. Качество значительно подросло:


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


Поподбирал ещё параметры для RandomForest. Разметил тестовую выборку. Убедился, что все кто ушли в январе, ушли и в феврале. Проверил что в целом доля ушедших нормальная. И заслал в Сбербанк. Но что-то видимо пошло не так, потому что в топ-3 я себя не обнаружил. А топ большего размера нам не показали.

Комментарии (49)


  1. midday
    19.09.2015 01:07
    +15

    Где вы находите эти конкурсы?


    1. ternaus
      19.09.2015 09:10
      +1

      Поддерживаю вопрос обеими руками.

      Есть где-нибудь список с сайтами, на которых проводятся соревнования по машинному обучению? Или некий ресурс, который аггрегирует список всех текущих и будущих соревнований?

      Я бы в этом соревновании поучаствовал бы, если бы, знал, что оно существует.


    1. rushter
      19.09.2015 11:28
      +2

      Где русскоязычные конкурсы искать не знаю, но некоторые анонсы мероприятий попадаются на блоге Александра Дьяконова.
      В частности, он писал про качество организации этого конкурса: alexanderdyakonov.wordpress.com/2015/09/11/moscow-data-fest

      Ну и площадки с мировыми конкурсами, если ещё не знайте о них:
      www.kaggle.com
      www.crowdanalytix.com
      www.drivendata.org
      algomost.com/ru (проект Сколково)


    1. alexkuku
      19.09.2015 11:39

      Мне друг написал про него


  1. OlegUV
    19.09.2015 08:02
    +4

    С такими данными, когда большинство полей в виде хешей не-пойми-чего — это какая-то угадайка, игра типа «Код Да Винчи» в самом плохом смысле.
    Хеши нельзя читать нормальными данными.
    Нет данных — нет модели.
    Нет модели — нет ничего, копать бессмысленно.


    1. kraidiky
      19.09.2015 09:54

      habrahabr.ru/article/266543/
      Конкурс от билайна, где кроме чисел так же есть три колонки хэшей от непонятно чего. Возможно тарифных планов или названия городов. Категориальные переменные по 5000 значений в каждой. Ничего, 100 человек за три дня приняли участие. Предсказания идут на уровне 76% в среднем.


      1. rushter
        19.09.2015 11:01

        Просто ещё никто не начинал всерьёз работать, кроме одно человека, у которого 92%. Чтобы получить 74-75% там достаточно всего лишь несколько столбцов.


      1. OlegUV
        19.09.2015 11:10
        +6

        Да, я видел этот конкурс…

        Поясню свою мысль:

        Допустим устраивается конкурс о игре в орлянку.
        Собралось 100 человек, каждый участник подбрасывает монетку 100 раз, и считается рейтинг участника как процент выпадения орла. Что будет в результате? В топе будут игроки с результатами и 60 и 70 и 80%.
        Но значит ли это, что они умеют управлять монеткой?

        Пример утрирован, но суть понятна.

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


        1. gef0rce
          19.09.2015 19:10
          +1

          Собралось 100 человек, каждый участник подбрасывает монетку 100 раз, и считается рейтинг участника как процент выпадения орла. Что будет в результате? В топе будут игроки с результатами и 60 и 70 и 80%.
          Но значит ли это, что они умеют управлять монеткой?


          Именно потому в конкурсах всегда есть открытая часть (та, по которой отображается текущий топ) и закрытая (та, по которой считается финальный результат)
          Если человек показывает 70% на одной части и столько же на другой — да, он вероятно умеет управлять монеткой.


          1. ad1Dima
            20.09.2015 11:01

            А можете пояснить механику на примере? что значит, закрытая часть?


            1. OlegUV
              20.09.2015 11:27

              имеется в виду выборки in samle и out sample. причём неявно предполагается, что обе выборки как бы принадлежат одной генеральной совокупности, если можно так сказать. В случае с монеткой это верно, в реальной жизни — далеко не всегда. Например та же игра в орлянку, но с профи-игроком, который этим зарабатывает на жизнь )))


            1. gef0rce
              20.09.2015 11:29

              Участникам выдаются 2 датасета: тренировочный (с ответам) и тестовый (без ответов). Требуется сгенерировать предсказание для тестового множества и послать его в систему. На стороне сервера предсказания разделяются фиксированным образом (но неизвестным участникам) на открытую (public) и закрытую (private) часть. Как правило, в пропорции 30 \ 70.
              Участники могут отправлять свои решения — и будут видеть качество только на открытой части. Таблица участников ранжируется по этому результату. Однако финальный результат будет вычисляться по закрытой части датасета.

              То есть можно сильно переобучиться на public часть — и быть высоко в таблице. Но это не имеет смысла, потому что по итогам private слетишь вниз. Такое бывает часто =)


              1. ad1Dima
                20.09.2015 11:52

                Спасибо, так понятнее.


      1. BelBES
        19.09.2015 13:08
        +2

        Одно время учавствовал в конкурсах на kaggle… и практика показывает, что когда организаторы конкурса не дают информации о природе признаков, то в ТОП-е сидят алгоритмы, которые представляют собой стек средне обученых классификаторов. Т.е. народ обучает сначала традиционные алгоритмы типа RandomForest, SVM, adaBoost etc. получают на них результаты ~60-80% точности на тестовой выборке, а потом просто считают результат как голосование(иногда делают хитрее и строят по этим выходам регрессию) от всех таких «средних» моделей и получают результаты >90% с которыми и попадают в топ. Т.е. по сути оверфитятся на данные, при этом какой либо значимой практической пользы от таких моделей нет.

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


        1. OlegUV
          19.09.2015 13:11

          да, оверфит — самая лучшая формулировка


        1. gef0rce
          19.09.2015 19:14

          Т.е. народ обучает сначала традиционные алгоритмы типа RandomForest, SVM, adaBoost etc. получают на них результаты ~60-80% точности на тестовой выборке, а потом просто считают результат как голосование(иногда делают хитрее и строят по этим выходам регрессию) от всех таких «средних» моделей и получают результаты >90% с которыми и попадают в топ. Т.е. по сути оверфитятся на данные, при этом какой либо значимой практической пользы от таких моделей нет.

          А что вы в данном случае называете оверфитом? В чем проблема, если народ получает те же >90% на тестовом множестве?


        1. ternaus
          20.09.2015 06:45
          +2

          Вы не могли бы раскрыть свой опыт участия в соревнованиях на кагле? Ну или указать ваш nickname?

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

          • Оверфит — это когда ошибка на тестовой выборке значительно больше, чем на train set. Хитрые комбинации различных алгоритмов — это не overfitting, это ensembling. И если overfitting — это в принципе плохо, то ensembiling — по ситауации. При составлении ансамбля теряется инетрпретируемость и масштабируемость, но часто повышается точность предсказания. И использование ансамблей оправдано, если нужна именно зашкаливающая точность. Да, в большинстве практических задач интерпретируемость и масшабируемость важнее, чем дополнительная пара процентов. Во многих задачах точность 82% или 84% — вообще неотличима. Но, сореванования, они про то, сколько можно выжать из предложенных данных. Своего рода benchmark. Можете воспринимать соревнования, как научную задачу:«Какова максимальная точность модели, на этих данных?» Существует куча статей на тему MNIST dataset, и прочих общеизвестных данных. Тут ровно то же. Поэтому как правило каждое соревнование на кагле приводит к статьям в резензируемых научных журналах и вуступлениям на конференциях.
          • Ещё вот такой нюанс. Недостаточно взять и натравить сложный алгоритм на исходные данные(исключение работа с изображениями, используя нйронные сети и то не всегда). Точность предсказания основывается на двух ступенях: обработка дынных и собственно сама модель. Те, кто в топе, в первую очередь пытаются работать с данными, и это даёт наибольшый выход, а уже потом, когда фичи новые не придумать, то начинаются жёсткие численные методы с ансамблями и прочей экзотикой. Но, ка кправило, в топ 10%, можно выехать на простом алгоритме и правильно обработанных данных. Иногда первая ступень, то есть очистка данных, создание признаков и т.д. Не работает. Вот просто не работает. Пример: Соревнование otto. Все признаки анонимезированы, пропущенных значений нет. Все признаки важны. Комбинирование признаков тоже ничего не даёт. Да, на практике такое, наверно, не встречается. Ну и что? Соревнование было про алгоритмы и как с ними правильно работать. Так что с точки зрения практики это было больше про знания, нежели про применения этого алгоритма в компании, которая предоставила данные. Это Кагл. есть данные, есть метрика, есть вопрос — крутитесь как хотите. Титулы, звания, возраст, опыт работы — в пользу бедных. Важен результат. Распространёно причетание на форуме на тему, данные плохие, поэтому и моя модель плохая, и вообще смысла работать над этими данными нет. Так вот не надо причитать. Надо стороить модель, которая будет наиболее точной. Тут все в одной лодке. Для всех данные зашифрованы. Но это не мешает заниматься построением модели.
          • На тему "… а потом просто считают результат как...". Тут меня смущает слово «просто». Построение ансамблей — это дело тёмное, наука, сама в себе. Я бы побоялся такое слово употреблять.


    1. gef0rce
      19.09.2015 19:03

      Хеши несут информацию о том, что данный признак является категориальным, проверка категорий на равенство сохраняется.
      Почему их нельзя считать нормальными данными?


      1. OlegUV
        19.09.2015 19:24
        +1

        Потому что неизвестно, что это за характеристики, соответственно, могут они в принципе влиять на конечный результат или нет.
        Формально, я не не спорю, можно обойтись и таким полностью обфусцированным набором. Но тогда это превратится в соревнование по фитингу y=f(x1, x1...xn), не более, без претензий на моделирование чего-то.


        1. gef0rce
          19.09.2015 19:32

          А нужно ли моделирование в данном случае?
          Задача ведь ставится именно как аппроксимация y=f(x1, x1...xn), никто не требует интерпретируемости отображения f.


          1. postgree
            19.09.2015 20:10

            Конечно. Представьте себе, что в каком то поле заложен почтовый индекс или адресный классификатор (я не из РФ, поэтому не обладаю данными по таким справочникам). При анализе таких данных нужно разворачивать цепочку населенный пункт->район->область->округ. И даже если эти данные есть в хешах, их нужно нащупать.


            1. gef0rce
              19.09.2015 20:46
              +1

              Почему «конечно»?
              Может мы расходимся в понимании слова «моделирование»? Я его сейчас использую как «написание решающего правила в символьном виде и его обоснование здравым смыслом \ экспертными знаниями».

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

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


      1. kraidiky
        19.09.2015 23:17

        Да можно конечно и считать. Проблема только в том, что ряд популярных пакетов преобразуют категориальные переменные в колонки обычных переменных со значения 0-1. И если у вас есть колонка с неизвестными хэшами, то если вы её привычно превратите в 8000 бинарных колонок на этом многие алгоритмы и сдуются.

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

        Если знаете способ работать с такими данными более весело — подскажите.


        1. gef0rce
          20.09.2015 11:43

          Можно каждое значение хеша закодировать числом. Например, частотой встречаемости. Или сглаженной вероятностью целевой переменной (в случает бинарной классификации). И после кодировки — использовать любимый алгоритм.

          А можно не кодировать, а оставить в виде one-hot и использовать линейную модель, для нее 8000 бинарных колонок — совсем не проблема.
          Кроме того, можно применить разные матричные разложения к получившейся бинарной матрице — и их результаты использовать как признаки для ваше любимого алгоритма.

          Уверены, что между категориальными переменными есть взаимодействие? Можно попробовать построить квадратичную линейную модель.
          Пространство очень большое, а данных не хватает? Можно факторизовать матрицу квадратичных весов (как это сделано в факторизационных машинах)
          Хочется взаимодействий более высоко порядка? Адаптивные полиномы или полные полиномы + хэширование.

          Эти методы (кроме кодировки и описанного сценария использования матричных разложений) реализованы как минимум в vowpal wabbit.


  1. ad1Dima
    19.09.2015 08:04
    +9

    все кто ушли в январе, ушли и в феврале.

    Вы сломали мне мозг, что значит эта фраза?


    1. Biga
      20.09.2015 13:30

      Нельзя просто так взять и уйти из сбербанка.


  1. NightmareZ
    19.09.2015 08:58
    +6

    Если постановка задачи идиотская (есть данные, но мы не скажем, что они значат), то не стоит ожидать адекватности от судейства. Я бы не взялся.


  1. andreylartsev
    19.09.2015 09:57

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


    1. OlegUV
      19.09.2015 12:15
      +6

      Именно, что не так.

      Пусть есть набор данных (x,y) 100 точек.
      Требуется найти взаимосвязь y=f(x), при этом в задаче не говорится о характере взаимосвязи.

      Задачу решают 2 участника.
      Первый знает, что фундаментально взаимосвязь линейная и строит модель y=ax+b
      При этом из-за большой ошибки в исходных данных y=ax+b + N(m,s) точность модели получается очень плохой, скажем 20% ошибки.

      Второй участник не знает о фундаментальной взаимосвязи и строит полином 100-й степени y=a100* x^100+ a99* x^99 +…
      Модель получается изумительной, ошибка 0,00001%

      Вопрос — кто построил лучшую регрессию?


      1. gef0rce
        19.09.2015 19:28

        А как при этом вы измеряете качество? Что такое «ошибка 0,00001%»?
        Если это out-sample — то второй лучше.


        1. OlegUV
          19.09.2015 19:58

          я понимаю вашу мысль, но я бы не делал такую большую ставку на критей аут оф сэмпл, вы, видимо ещё не сталкивались с ситуациями, когда out of sample совсем не помогает


          1. gef0rce
            19.09.2015 20:04
            +1

            А можете привести пример, когда критерий out-of-sample совсем не помогает? Я действительно с таким не сталкивался — кроме случая, когда выборка мала.


            1. OlegUV
              19.09.2015 20:14

              когда есть нестационарность и процесс периодически «ломается» в числовом виде, но при этом базовые «уравнения» остаются теми-же. Из конкретики сейчас вспоминается только корреляция цен, например нефти Brent и WTI, больше с ходу примеров не вспомню… А, вот ещё — продажи товаров на динамичном рынке, тоже out of sample плохо работает


  1. Ermushev
    19.09.2015 12:48

    В блоге Дьяконова, в комментариях, говорится об ошибке в постановке задачи, ID нужно извлекать не так, как описано в условиях. Вы прошли этот этап? Получили правильную схему?


    1. alexkuku
      19.09.2015 13:05

      Да


  1. DnV
    19.09.2015 15:35
    +1

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


    1. alexkuku
      19.09.2015 16:00

      Да не, выиграли крутые чуваки. Всё нормально


  1. DmitryKoterov
    20.09.2015 03:15

    А в какую СУБД загружают такие огромные файлы, чтобы потом быстро с ними работать, рисовать такие графики и т.д.? Одна только загрузка ведь займет полчаса-час, а нужно еще обрабатывать.


    1. ImLiar
      20.09.2015 10:53

      пара-тройка нод с cassandra, например
      и какой-нибудь spark ml сверху через коннектор


    1. Stas911
      21.09.2015 19:06

      Да, было б интересно узнать, как вы с этим 35Г файлом работали


    1. alexkuku
      21.09.2015 19:40

      БД не использовалась. Данные хранились в текстовом файле на жёстком диске. Когда нужно было что-то по нему он читался строчка за строчкой и парсился. Обработка занимался около пяти-десяти минут.


  1. Alexey_mosc
    29.09.2015 15:28

    А почему у вас ROC-Curve только одну точку перегиба имеет? Вы отсекали по порогу решения только один раз?


    1. alexkuku
      29.09.2015 18:58

      Сбербанк почему-то требовал бинарных ответов. Если sklearn передать вектор из 0 и 1, а не вероятности оттока, получаются такие кривые. Почему именно такие я не вникал


      1. Alexey_mosc
        29.09.2015 20:18

        А может в этом и была ваша недоработка. Если передавать в функцию расчета ROC-Curve результаты работы того же рандом фореста в виде уровней зависимой переменной (у вас она бинарная) — 0 или 1, то нельзя построить нормальную кривую, так как отсекать нечего. Тут и следовало бы вникнуть в то, что вы используете. Как вы будете отсекать 0 от 1? Только один раз и получится.

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


        1. alexkuku
          29.09.2015 23:45

          Может быть, но вряд ли


          1. Alexey_mosc
            30.09.2015 00:04

            Ну, это очевидная недоработка, которая бросилась в глаза. Рок кривая используется криво, извините за тавтологию. А могут быть и другие…


            1. alexkuku
              30.09.2015 01:39

              Да, не, у меня здесь всё нормально. Проблема могла быть в том, что просили бинарные оценки, а мерили AUC. Это как-то по-моему странно


  1. ivankomarov
    06.10.2015 12:40

    Вроде бы alexkuku занял Место №2 в конкурсе rusbase.com/news/data-win, выше только www.kaggle.com/stasg7


    1. alexkuku
      06.10.2015 14:53

      На презентации турнирная таблица выглядела так