Главная » Хабрахабр » Как программист новую машину подбирал

Как программист новую машину подбирал

В предыдущих статьях (I, II, III) я подробно рассказывал о разработке сервиса для поиска выгодных б/у автомобилей в РФ.

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

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

Обзор конкурентов

В рунете уже есть сервис для подбора и покупки новых авто — autospot.ru, но он обладает следующими существенными недостатками:

  1. На сайте нет возможности узнать контакты дилеров где находятся интересующие вас автомобили, вы можете только оставить свой телефон для обратной связи. Менеджер autospot.ru свяжется с вами в течение получаса, уточнит у вас марку, модель и комплектацию, после чего сообщит ваш телефон дилерам, которые располагают автомобилями, соответствующими вашим требованиям. Ждать первичного звонка от дилера вы будете не меньше часа. Крайне раздражающим фактором данной коммуникации является назойливость. После разговора менеджер autospot.ru и различные дилеры будут звонить вам довольно часто, напоминая о себе, даже если вы их попросите об обратном.
  2. На сайте представлено ~30 000 новых автомобилей со всей России, что составляет менее 30% от среднего числа реализуемых в месяц новых авто в 2018 году.
  3. На сайте нет оценки стоимости авто относительно рынка в соответствии с комплектацией и доп. опциями, то есть невозможно понять какие предложения наиболее выгодные.

Для досок объявлений auto.ru, drom.ru и avito.ru недостаток №2 актуален в разной степени, а №3 — в полной мере для всех.

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

Сбор данных

Данные о новых автомобилях у официальных дилеров собираются из различных источников, обрабатываются, систематизируются и унифицируются. Обновление данных и добавление новых источников производится на регулярной основе. Объем данных составляет ~75 000 новых автомобилей у более 650 дилеров из 70+ городов России.

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

Преобразование данных и построение модели

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

Для наглядности, набор регрессоров для Volkswagen Tiguan имеет вид:

Подробнее

[1] «price»
[2] «availability»
[3] «year»
[4] «volume»
[5] «power»
[6] «front_drive»
[7] «rear_drive»
[8] «mkpp»
[9] «benzin»
[10] «dizel»
[11] «body_tsvet_kuzova_chernyy_metallik»
[12] «interior_tsvet_peredney_paneli_temnyy»
[13] «interior_tsvet_obivki_sideniy_temnyy»
[14] «interior_tsvet_potolka_temnyy»
[15] «interior_tsvet_kovrovogo_pokrytiya_temnyy»
[16] «equip_dnevnoy_svet»
[17] «equip_avtokorrektor_far_s_dinamicheskim_povorotnym_svetom»
[18] «equip_paket_innovation»
[19] «equip_fary_svetodiodnye»
[20] «equip_omyvatel_far»
[21] «equip_bortovoy_kompyuter»
[22] «safety_avtomaticheskaya_regulirovka_dalnosti_sveta»
[23] «body_tsvet_kuzova_siniy_metallik»
[24] «body_tsvet_kuzova_serebristyy_metallik»
[25] «equip_sistema_avtomaticheskoy_parkovki»
[26] «equip_tekhnicheskiy_kod»
[27] «equip_paket_media»
[28] «equip_usb_interfeysvklyuchaya_auxin»
[29] «equip_interfeys_appconnect»
[30] «equip_paket_zimnie_tekhnologii»
[31] «equip_multimediynaya_sistema_audio»
[32] «equip_parktronik»
[33] «safety_videokamera»
[34] «main_komplektatsiya_city_20_tdi_150hp_7dsg_4motion»
[35] «body_shiny_21565_r17_99_v»
[36] «body_razmer_diskov_r17»
[37] «body_diski_legkosplavnye»
[38] «interior_tip_sideniy_sportivnye»
[39] «interior_obivka_sideniy_kozha»
[40] «equip_distantsionnoe_otkryvanie_bagazhnika»
[41] «equip_zapusk_bez_povorota_klyucha»
[42] «equip_dostup_bez_klyucha»
[43] «equip_interfeys_dlya_smartfonov_appconnect»
[44] «equip_kruizkontrol»
[45] «equip_pamyat_nastroek»
[46] «equip_dopolnitelnyy_otopitel»
[47] «safety_sistema_kontrolya_mertvykh_zon»
[48] «equip_sidenya_ergoactive_dlya_voditelya_s_14pozitsionnoy_regulirovkoy»
[49] «equip_elektroprivod_zerkal»
[50] «equip_paket_tekhnika»
[51] «safety_datchiki_davleniya_v_shinakh»
[52] «safety_okhrannaya_signalizatsiya»
[53] «body_tsvet_kuzova_belyy»
[54] «equip_spetsialnaya_seriya_city»
[55] «main_komplektatsiya_city_14_tsi_150hp_6dsg_4motion»
[56] «equip_panoramnaya_krysha»
[57] «body_bamper_s_uvelichennym_uglom_vezda_24_gradusa»
[58] «body_paket_offroad»
[59] «body_nakladki_na_dvernye_porogi»
[60] «interior_nakladki_na_dvernye_porogi»
[61] «main_komplektatsiya_city_20_tsi_180hp_7dsg_4motion»
[62] «body_shiny_23550_r19_99v»
[63] «body_razmer_diskov_r19»
[64] «interior_dvernye_paneli_skozhanoy_otdelkoy»
[65] «equip_elektroprivod_sideniy»
[66] «main_komplektatsiya_city_14_tsi_150hp_6dsg»
[67] «equip_vybor_rezhimov_vozhdeniya»
[68] «interior_yashchik_dlya_khraneniya_pod_perednim_passazhirskim_kreslom»
[69] «interior_ergonomichnye_perednie_sidenya»
[70] «equip_voditelskoe_sidene_s_regulirovkoy_po_vysote_dline_uglu_naklona_spinki»
[71] «equip_massazhnye_sideniya»
[72] «body_tsvet_kuzova_bezhevyy_metallik»
[73] «body_tsvet_kuzova_krasnyy_metallik»
[74] «body_shiny_23555_r18_100v»
[75] «body_razmer_diskov_r18»
[76] «interior_nakladki_na_porogi_s_podsvetkoy»
[77] «interior_dekorativnye_vstavki_dark_grid»
[78] «interior_dve_lampy_dlya_chteniya_speredi»
[79] «equip_paket_osveshchenie»
[80] «equip_fonovaya_podsvetka_interera»
[81] «equip_svetodiodnye_zadnie_fonari_3d»
[82] «main_komplektatsiya_offroad_20_tsi_180hp_7dsg_4motion»
[83] «body_korpusa_naruzhnykh_zerkal_okrashennye_v_chernyy_tsvet»
[84] «body_polnorazmernoe_stalnoe_zapasnoe_koleso_65x17»
[85] «body_peredniy_bamper_s_uvelichennym_uglom_vezda_26_gradusov_zadniy_bamper_s_dekorativnymi_vstavkami_dekorativnye_nakladki_na_dveri»
[86] «body_spoyler_na_zadney_dveri»
[87] «interior_dekorativnye_vstavki_dlya_spetsialnoy_versii»
[88] «interior_peredniy_podlokotnik_s_dvumya_podstakannikami_i_shtorkoy»
[89] «interior_ploskiy_pol_bagazhnogo_otdeleniy»
[90] «interior_yashchiki_dlya_khraneniya_pod_perednimi_kreslami»
[91] «interior_skladnye_stoliki_v_spinkakh_perednikh_kresel»
[92] «interior_alyuminievye_nakladki_na_pedali»
[93] «interior_rezinovye_salonnye_kovriki_speredi_i_szadi_s_logotipom_offroad»
[94] «interior_nakladki_na_dvernye_porogi_offroad»
[95] «interior_stekla_atermalnye_tonirovannye»
[96] «equip_datchik_sveta»
[97] «equip_spetsialnaya_versiya_offroad»
[98] «equip_klavishi_mekhanicheskoy_razblokirovki_spinok_zadnikh_sideniy_v_bagazhnom_otseke»
[99] «equip_vnutrennee_zerkalo_zadnego_vida_s_avtozatemneniem»
[100] «equip_poyasnichnyy_podpor_dlya_perednikh_sideniy»
[101] «equip_polnostyu_skladnaya_spinka_perednego_passazhirskogo_kresla»
[102] «equip_avtokorrektor_far»
[103] «equip_funktsiya_coming_homeleaving_home»
[104] «equip_2_usb_razema_v_peredney_konsoli_1_usb_razem_v_tsentralnoy_konsoli_dlya_zaryadki»
[105] «equip_datchik_dozhdya»
[106] «equip_obogrev_lobovogo_stekla»
[107] «safety_hdc_sistema_pomoshchi_pri_spuske_so_sklona»
[108] «body_tsvet_kuzova_korichnevyy_metallik»
[109] «equip_navigatsionnaya_sistema»
[110] «equip_paket_navigatsiya»
[111] «equip_golosovoe_upravlenie»
[112] «equip_usb_interfeys_ipodiphonevklyuchaya_auxin»
[113] «equip_multimediynaya_sistema_audiovideo»
[114] «main_komplektatsiya_sportline_20_tsi_220hp_7dsg_4motion»
[115] «body_paket_vneshnikh_elementov_sportline»
[116] «body_shiny_airstop_25545_r_19»
[117] «body_bampery_v_sportivnom_stile_i_nakladki_na_porogi_v_tsvet_kuzova_rasshiriteli_kolesnykh_arok»
[118] «equip_individualnaya_sborka»
[119] «equip_rulevoe_upravlenie_s_peremennym_peredatochnym_otnosheniem»
[120] «equip_multifunktsionalnyy_rul»
[121] «interior_dvernye_paneli_s_kozhanoy_otdelkoy»
[122] «main_komplektatsiya_offroad_14_tsi_150hp_6dsg_4motion»
[123] «equip_zerkalo_zadnego_vida_s_avtozatemneniem»
[124] «equip_tsentralnyy_zamok»
[125] «main_komplektatsiya_sportline_20_tsi_180hp_7dsg_4motion»
[126] «safety_podushki_bezopasnosti_sht_11»
[127] «safety_paket_bezopasnost»
[128] «safety_proaktivnaya_sistema_zashchity_passazhirov_presafe»
[129] «interior_otdelka_dverey»
[130] «main_komplektatsiya_sportline_20_tdi_150hp_7dsg_4motion»
[131] «main_komplektatsiya_offroad_14_tsi_150hp_6mt_4motion»
[132] «main_komplektatsiya_offroad_20_tdi_150hp_7dsg_4motion»
[133] «interior_salonnye_kovriki_speredi_i_szadi»
[134] «interior_tsvet_obivki_sideniy_kombinirovannyy»
[135] «equip_paket_discover_pro»
[136] «interior_paket_khranenie»
[137] «interior_makiyazhnye_zerkala_s_podsvetkoy_v_solntsezashchitnykh_kozyrkakh»
[138] «interior_bagazhnaya_setka»
[139] «interior_potolochnaya_konsol_s_otsekami_dlya_khraneniya»
[140] «body_tsvet_kuzova_belyy_metallik»
[141] «body_pritsepnoe_ustroystvo»
[142] «equip_obogrev_zerkal»
[143] «interior_obivka_sideniy_velyur»
[144] «body_tsvet_kuzova_seryy»
[145] «body_standartnyy_bamper_s_khromirovannoy_otdelkoy»
[146] «interior_khromirovannaya_otdelka_elementov_interera»
[147] «equip_paket_style»
[148] «equip_paket_premium»
[149] «equip_generator_180a»

Для построения регресcионных моделей в первом релизе я использовал хорошо зарекомендовавший себя для б/у авто (II) алгоритм Random Forest.

# загружаем необходимые библиотеки
library(reshape2)
library(caret)
library(randomForest) new_cars_data <- read.csv('new_cars_data_tiguan.txt') # загружаем выборку в R new_cars_data_cor <- as.matrix(cor(new_cars_data)) # рассчитаем корреляции между регрессорами new_cars_data_cor [lower.tri(CM, diag = TRUE)] <- NA # присвоим NA все нижние треугольные элементы матрицы high_cor_vars <- subset(melt(new_cars_data_cor , na.rm = TRUE), value == 1.0) # найдем пары регрессоров с сильной корреляцией # убираем по одному из каждой пары сильно коррелирующих регрессоров
if(length(high_cor_vars[,2])) { dataset <- new_cars_data[(-c(high_cor_vars[,2]))] } else { dataset <- new_cars_data
} set.seed(1) # инициализируем генератор случайных чисел (для воспроизводимости) split <- runif(dim(dataset)[1]) > 0.2 # разделяем нашу выборку train <- dataset[split,] # выборка для обучения и настройки (cross-validation) параметров test <- dataset[!split,] # отложенная (hold-out) выборка

Для перекрестной проверки я использовал пакет caret, который имеет большое количество возможностей для оценки качества модели.

fit.control <- trainControl(method = "repeatedcv", number = 10, repeats = 10) train.rf.model <- train(price~., data=train, method="rf", trControl=fit.control , metric = "RMSE") # применим 10-ти кратную 10-ти блочную кросс-валидацию для настройки модели train.rf.model # посмотрим на результаты кросс-валидации</code>
<spoiler title="Подробнее">Random Forest 1858 samples 111 predictor No pre-processing
Resampling: Cross-Validated (10 fold, repeated 10 times) Summary of sample sizes: 1673, 1672, 1672, 1672, 1671, 1673, ... Resampling results across tuning parameters: mtry RMSE Rsquared 2 132963.50 0.7264413 56 79757.67 0.8626671 111 80401.10 0.8605166 RMSE was used to select the optimal model using the smallest value.
The final value used for the model was mtry = 56.</spoiler>
Полученное значение коэффициента детерминации (<a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D1%8D%D1%84%D1%84%D0%B8%D1%86%D0%B8%D0%B5%D0%BD%D1%82_%D0%B4%D0%B5%D1%82%D0%B5%D1%80%D0%BC%D0%B8%D0%BD%D0%B0%D1%86%D0%B8%D0%B8">Rsquared</a>) означает, что зависимая переменная (цена) очень хорошо объясняется рассматриваемой моделью. <code>train.rf.model <- randomForest(price ~ ., train,mtry=56) # построим модель на основе полученных с помощью кросс-валидации параметров varImpPlot(train.rf.model) # посмотрим на 30 самых важных регрессоров</code>
<img src="https://habrastorage.org/webt/fj/vr/wh/fjvrwh1y9thhtqiy75v-epsmqrc.jpeg" /> <code>rf.model.predictions <- predict(train.rf.model, test) # проверим точность оценки на отложенной выборке print(sqrt(sum((as.vector(rf.model.predictions - test$price))^2)/length(rf.model.predictions))) # средняя ошибка прогноза цены (в рублях)
[1] 82512.59

Апробация алгоритма

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

rf.model <- randomForest(price ~ ., dataset,mtry=56)
predicted.price <- predict(rf.model, dataset)
real.price <- dataset$price
profit <- predicted.price - real.price

Построим график зависимости выгоды от цены.

plot(real.price,profit)
abline(0,0)

Посчитаем выгоду в процентном соотношении.

sorted <- sort(predicted.price /real.price, decreasing = TRUE)
sorted[1:8] 195 193 6 207 202 203 906 206 1.184079 1.176262 1.132920 1.126626 1.123967 1.123967 1.116736 1.116344

Учитывая тот факт, что выгода рассчитывается по априорной информации от дилера, а при личной встрече вы сможете еще поторговаться, полученный максимальный профит в 18% — очень хороший результат.

Реализация web-сервиса

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

0 TSI 180hp 7DSG 4Motio. Я, например, присматриваюсь к Volkswagen Tiguan в комплектации City 2.

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

Напоследок

Таким образом, я реализовал помощника для подбора нового автомобиля у официального дилера по самой выгодной цене на рынке, учитывающего все установленные доп. опции.
Обращаю ваше внимание на тот факт, что низкая цена на авто может предоставляться дилером при определенных условиях (кредит, КАСКО, trade in и т.д.), что в общем случае вносит ошибку в оценку выгоды. На мой взгляд, ради хорошей скидки рационально воспользоваться некоторыми из подобных, навязываемых дилером услуг, будь то КАСКО у партнера или, например, кредит, который вы погасите при первой возможности. Это сугубо индивидуальный вопрос, но в любом случае, желательно, во избежании недопонимания, уточнить условия по телефону до визита в салон.

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

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

Ссылки

Выборка для Volkswagen Tiguan


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

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

*

x

Ещё Hi-Tech Интересное!

[Из песочницы] Контроллер, полегче! Выносим код в UIView

У вас большой UIViewController? У многих да. С одной стороны, в нём работа с данными, с другой — с интерфейсом. Они решают проблему потока данных, но не отвечают на вопрос как работать с интерфейсом: в одном месте остается создание элементов, лейаут, ...

Нужно больше разных Blur-ов

Размытие изображение посредством фильтра Gaussian Blur широко используется в самых разных задачах. Но иногда хочется чуть большего разнообразия, чем просто один фильтр на все случаи жизни, в котором регулировке поддаётся только один параметр — его размер. В этой статье мы ...