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

от автора

В рамках 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 я себя не обнаружил. А топ большего размера нам не показали.

ссылка на оригинал статьи http://habrahabr.ru/post/267217/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *