...

суббота, 19 сентября 2015 г.

Как я участвовал в конкурсе Сбербанка про предсказание оттока клиентов

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

Сбербанк щедро отгрузил данных. Нам дали ~20 000 пользователей, про которых было известно попали они в отток в ноябре, декабре, январе или нет. И было ~30 000 пользователей, для которых нужно было угадать уйдут ли они в феврале. Кроме этого прилагался файлик на 35Гб примерно такого содержания:
30.01.2015 09:22        29.01.2015 16:00        30.01.2015 09:22        EKGh+MraqvwwNT3GqgiMEN2/ySs=    kCE/6TYEHWRa4HwccK95Mq4YP+k=    443045  Самара  Почтовый        K+iMpCQsduglOsYkdIUQZQMtaDM=    2wNaK88zG9Yx/u5F2lFvNBHBgq4=    68APK1+X9Itc5/foOG78A1BhjHc=    5ECajFlJ8wgtg3Be+V6avsV1pgw=    JiMHOv2XOmO6Fiq7acyNJ7ybG8s=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    R823f2PM5MZ2kTwN/PWup/ocizA=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    Rob6shXTeqeQ/W4Sn19CJzuFW+M=    pbotcZX873SrDqATd+kosBvsOFY=    68APK1+X9Itc5/foOG78A1BhjHc=    REHZAJXiL/Fixs/9LqrqGgOTFC0=    lGKaUapcszPSt6UO77mm3R9jC1c=    c5DVo14pn+m59Jy8z2QUXorJtCo=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    IZJ4D+eekkxhXLOUJaZ+MQqmGGE=    443077  Самара  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    2tobHSfP0RM0InwsKB0B2RfC3nk=    dJ/3XzbFv/Fd/1zsCwiDV4X9Dws=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    3bgl2TFAHdPT2qkZpZtKii1W5ac=    40moDWvi2ZOhvSUivfnzLRnjL+4=    K+iMpCQsduglOsYkdIUQZQMtaDM=    lXrM1IpuXivzJ1g9x8/NGEPJt9Q=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    +e0095FfDDZuFhsHLP5lMED3ttQ=    lGKaUapcszPSt6UO77mm3R9jC1c=    x+lNu8tXc34OwUCJEMQ9JfJnIp0=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    wpnh7B+yc22CcZrkRXlTsYcndxo=    Комиссия РКО    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    400000.0        400000.0        400000.0        wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     gu+AE/ARXawRDkF1uN3p/VFyHUw=    PROV    2wNaK88zG9Yx/u5F2lFvNBHBgq4=
01.03.2013 06:38        28.02.2013 16:00        01.03.2013 06:38        K+iMpCQsduglOsYkdIUQZQMtaDM=    oTXLCX+1oY7j5bQRHQeBnlv6pv0=    625048  Тюмень  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    5GcyE42+h92lxrP20xfopBhm2hU=    JmS4MkjUwCLd9H1iWZTCnQ3009U=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LeA91e1hh8TolYM2v8Md33VfsM0=    40moDWvi2ZOhvSUivfnzLRnjL+4=    K+iMpCQsduglOsYkdIUQZQMtaDM=    U+Nz/E4/rOeuSO5yQcWPr5vBjU4=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LG9280r6ZKr3gW8FGuNFKVqg66k=    625029  Тюмень  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    Antbbaf85R6dGC6FKWOZhUWY0Ps=    or83VmvYyVUx2hNUYOQXPo+JVPw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    yQimGc+BR4slI19jTwkDBBDFVEw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    oNQzXC2f9BzusSX6lAMGRgRUwMk=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    K+iMpCQsduglOsYkdIUQZQMtaDM=    7zk0pYI5nHZtFlsgp458x1IxWS8=    or83VmvYyVUx2hNUYOQXPo+JVPw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    153750.0        153750.0        153750.0        wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     99mJrLpejr2E0IgD31Q2cGrVBfc=    PROV    Antbbaf85R6dGC6FKWOZhUWY0Ps=
27.01.2015 13:47        26.01.2015 16:00        27.01.2015 13:47        gZ0SI7XpYBPBnXjOQc8juxzoY/c=    fpzbQEHl82NiVVNPJKQVRHPbRsM=    109044  Москва  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    1X+UBlG07t36gjSIIdPmmPAqC6M=    hMxAglVE38hxluUM4fSVXqabAkQ=    KxwuJISsFaJtmMNblzUw/HLuB90=    ivblkef3XQi2UTgtVgxC6yOKwx8=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    y5Tl7KLkj310QuqpnGOiDM8agT0=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    IOBqzZS0aFreVYN33I/PbzhZzqg=    Fe/OH5JMHf6I0tL2BOBkm98IdXc=    hMxAglVE38hxluUM4fSVXqabAkQ=    CVMB3io2yaPGw/Krc3v/7aQz+Ws=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    eGXHLSkEQzg+r4FMh5H8hrp7Tgg=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    qyu3UzMRa6YpWn8gCAxEIHyDDXE=    109544  МОСКВА  Юридический     K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    feuiW2o7ET1rgBj7qgjQjxRKXRc=    DISDk4lki8N4+REEwCrYqP/sftQ=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    XziMVoejlSILvx9nkS8IwLr7f/U=    40moDWvi2ZOhvSUivfnzLRnjL+4=    K+iMpCQsduglOsYkdIUQZQMtaDM=    /Pbkdf/FCAShNHypf2GIcRyqfzQ=    LR6ehKc5bT1KwZRwd/rc/uY5LiA=    3UNnsbkaQUZPT/KwI2ldCh25Xq0=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    HHsCUXCJpx9B8pWqCkvkTxc6CHU=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    qt4du/oGsA2UmjuJ2e6rp4m7czg=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    593220.0        593220.0        593220.0        wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     GAnLmHDZeSgmZXMIoSmO7TXovMo=    PROV    1X+UBlG07t36gjSIIdPmmPAqC6M=
26.06.2014 02:42        25.06.2014 17:00        26.06.2014 02:42        a0ZixkxJVju8yNHck+rmufP6LE4=    9e4hZde798SdydmuzPk+ZLfVUCo=    173009  Великий Новгород        Почтовый        6qVifvfceXwtxVrs9P01IB11Zyc=    3Ji3G+ARmzO1yVBTSXEWqZ/RpUI=    Na9xb8PpXgJeZj+xihgQHn2gdc0=    kqRQsgPScOPVd5oDV+zw+IUBusA=    dTERXJWzQRTmIOrEr6/pe/iQNs0=    K+iMpCQsduglOsYkdIUQZQMtaDM=    mPfUUmNnLU8bxfRysjFhzjRogQM=    SN5katQnekKDjC0q+YUCauj/nQQ=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    K+iMpCQsduglOsYkdIUQZQMtaDM=    q9QjDYtSH/+6e/NHdAWVT9B1M6M=    Na9xb8PpXgJeZj+xihgQHn2gdc0=    gVPa+gG3JV+E8zsaVFTs0vKiTgw=    6zly/tALWIksVkkTGtCZF4kNl50=    0IJF6vW5KDjKKz1lNMRKzAAHCvM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    jDRY3oGfXFLlH9T+9oKwk+G2zwM=    174406  БОРОВИЧИ        Почтовый        8NHZwcvtbn+LCCz43s7pGOY4UBs=    3Ji3G+ARmzO1yVBTSXEWqZ/RpUI=    pwCdHbjZVqmakV50R1HSRQbz8PM=    5/ws5kVuKtz6QESRwPvPz0jjurw=    HdeUf19XgiIlMLU6j4NH5jNRoig=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    Npz45hMcKJBMBdFE4ovXIB/Vjp4=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    K+iMpCQsduglOsYkdIUQZQMtaDM=    amGdo7mbrAGH+S1QlELG0BHJi08=    pwCdHbjZVqmakV50R1HSRQbz8PM=    YiSPZbeBZpXCVG5DzdLEbLQAmyU=    6zly/tALWIksVkkTGtCZF4kNl50=    1wrl8j0tjE2Lj82jdQfkuC30IDQ=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    2144960.0       2144960.0       2144960.0       wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     mPFBYItUYglELWkOfUnyuYIHe8U=    PROV    3Ji3G+ARmzO1yVBTSXEWqZ/RpUI=
10.12.2014 06:38        09.12.2014 16:00        10.12.2014 06:38        HC1kMBOyAU0TONoaqMgjfLip+dM=    UYh56W0ABat2pFZOCLegagXjH2U=    109439  Москва  Фактический     K+iMpCQsduglOsYkdIUQZQMtaDM=    1X+UBlG07t36gjSIIdPmmPAqC6M=    xDJw8OsOZ05UAYfqLLY3b6YiHac=    vIf+PQ+i6tr8iSvLLb3kzSe+E5A=    mCLg9y5cL8PI18uliJDpsbaOGAA=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    y3myHWlinvPvmVIfxj9yrajd/Kg=    9tpw0k3iVpqAHzrlR2UMYtA6N2M=    zJ9eY3dOBJftz2WCRaNe28qFBmc=    Sd6cIq3t7pmgxIinial5a+AQC5w=    xDJw8OsOZ05UAYfqLLY3b6YiHac=    a7g7e0UBN3M9Wsn9RGtUUXFgAR4=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    dVQhMcirWkdw5zw73gMG/qI5PNw=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    null    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    K+iMpCQsduglOsYkdIUQZQMtaDM=    CS3YMwLIuP0swS8myrV31ULCmGs=    2sCbZbq42P3mjf1/yVVUkBuCTMs=    SerGZ4dw0o2lzXPiDxEMxAWxTkE=    ByHiij4WTahzuNNLPcqJdKpoQ9I=    gQS6HcBAmyWfSH7QfbR3w48gWjA=    Od+lUoMxjTGv5aP/Sg4yU+IEXkM=    ONZZOkw+k/JrEHNJpKURA8eYVzA=    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    K+iMpCQsduglOsYkdIUQZQMtaDM=    null    2084000.0       2084000.0       2084000.0       wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     wTgpJjxGacgy9sjcoSX3wWLAzNw=    RUR     6w7T/Bx7ioIqx8hiasT3d497waI=    PROV    1X+UBlG07t36gjSIIdPmmPAqC6M=


Физический смысл полей специально не раскрывался. Сказали «так интереснее». Было известно только, где искать 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 я себя не обнаружил. А топ большего размера нам не показали.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Комментариев нет:

Отправить комментарий