Существует универсальное правило покупки вещей: «лучше платить меньше, чем платить больше». По личным причинам мне нужно было купить подержанную машину, но я никуда не торопился, у меня было время подумать и найти лучшее предложение.

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

Сбор данных

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

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

  • Расстояние от меня: менее 100 км
  • Возраст автомобиля: менее 10 лет.
  • Цена: менее 10 000 евро

Давайте проверим инструменты, используемые для извлечения данных с этих сайтов:

  • urllib.request: использовал этот модуль в стандартной библиотеке Python для загрузки html-кода веб-сайтов.
  • BeautifulSoup4: использовал этот модуль для синтаксического анализа html-кода и поиска соответствующей информации.

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

Для списка автомобилей пример URL-адреса может быть:

https: //www.adspage/cars-search/? Location = Barcelona & uptoprice = 10000 & yearfrom = 2010

Для определенного автомобиля URL-адрес может быть примерно таким:

https: //www.adspage/cars/? carid = 141238

Используя urllib, мы загружаем и сохраняем следующие страницы:

from urllib.request import urlopen
def download_and_save_page(url, file):
    html_code = urlopen(url).read()#.decode('utf-8')
    f = open(file, 'wb')
    f.write(html_code)
    f.close()
    return html_code

Сначала мы очищаем страницу со списком автомобилей, чтобы найти все ссылки на доступные автомобили и также их загрузить. Это легко сделать с помощью метода find_all BeautifulSoup.

links = soup.find_all('a', href=True, class_='car-link')
for link in links:
    print(link['href'])

Имейте в виду, что страницы с тематическими объявлениями обычно следуют системе нумерации страниц, поэтому на каждой странице мы будем получать определенное количество перечисленных автомобилей (например, 20), чтобы получить все автомобили в наличии, нам необходимо понять, как работает система нумерации страниц. Обычно нам просто нужно добавить номер страницы к URL-адресу, например:

https: //www.adspage/cars-search/? location = Barcelona & uptoprice = 10000 & yearfrom = 2010 & page = 7

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

Следующим шагом будет обработка всех загруженных страниц и извлечение соответствующей информации об автомобилях. Вся информация была сохранена в файле CSS. Я решил сохранить следующие данные:

  • URL объявления (чтобы потом проверить его вручную, когда найду что-нибудь интересное)
  • Марка машины
  • Модель автомобиля
  • Тип продавца (Частный / профессиональный)
  • Цена
  • Описание
  • Год
  • Км
  • Дата публикации
  • Список URL-адресов с картинками

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

Извлечение данных производилось в основном с помощью методов BeautifulSoup find и find_all, выполняющих поиск по релевантным полям на странице.

soup.find('div', class_='car-price').get_text()

Важно найти правильные имена классов, я сделал это с помощью инструментов разработчика Firefox (откройте инспектор с помощью Ctrl + Shift + C).

С помощью инспектора мы выбираем все соответствующие поля на странице и записываем их информацию.

  • Это элементы ‹div›, ‹p› элементы или что за элементы?
  • Как отличить их от всех элементов одного типа (уникальный идентификатор или уникальное имя класса)

Соединив все эти элементы, мы можем создать CSV-файл со всеми данными об автомобилях. В моем случае файл CSV был 5 МБ и включал данные о 3487 автомобилях. Эти данные относятся только к автомобилям, проданным в декабре 2019 года и в рамках моих критериев поиска, описанных ранее. Было бы интересно получить более старые данные, но они не были доступны в Интернете.

Анализ данных

А теперь самое интересное: мы открываем наш блокнот Jupyter и начинаем анализировать данные.

#Load data
df = pd.read_csv('data/car_data.csv')

Позвольте представить вам Pandas Profiling, модуль Python, который генерирует отчеты из Pandas DataFrame. Отчет дает нам быструю визуализацию статистики для всех переменных в нашем наборе данных.

from pandas_profiling import ProfileReport
prof = ProfileReport(df)
prof.to_file('output.html')

Интересная статистика по наиболее распространенным брендам и моделям, которые продаются в Испании:

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

Затем применили одно горячее кодирование для брендов и моделей и получили 371 переменную.

Использовал разделение на поезд / тест для проверки точности моделей машинного обучения и RMSE для оценки их производительности. Целевой переменной была цена на машину.

Модели, о которых я хочу поговорить, - это XGBoost, обеспечивающие наилучшее соотношение RMSE и KNN, которые я считаю интересными для этого приложения, поскольку то, что мы делаем интуитивно при поиске цены на автомобиль, - это сравнение его с другими аналогичными автомобилями в продаже.

XGBoost:

import xgboost as xgb
model=xgb.XGBRegressor(random_state=1, n_estimators=5000, learning_rate=0.01)
model.fit(X_train, y_train)
sqrt(mean_squared_error(y_val, model.predict(X_val)))

Получил RMSE 1,288,39. Обратите внимание, что эта величина сопоставима с ошибкой в ​​евро. Это высокая стоимость, имейте в виду, что мы рассматриваем только автомобили дешевле 10.000 евро и средней стоимостью 7,226 евро.

KNN:

from sklearn.neighbors import KNeighborsRegressor
knn = KNeighborsRegressor(n_neighbors=5)
knn.fit(X_train, y_train)
sqrt(mean_squared_error(y_val, model.predict(X_val)))

Несмотря на то, что я ожидал хороших результатов от интуитивно понятного подхода к этой модели, она с треском провалила среднеквадратичное значение 7,242.

Выводы

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

В итоге я получил отличную сделку по Citroen C4, которым я очень доволен.

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

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

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

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