В последние пару лет меня достаточно сильно интересовал вопрос ценообразования в российских интернет-магазинах. Каждый раз при заявлении интернет-магазина о большой скидке в душу закрадывается сомнение… Действительно ли такая большая скидка? Была ли реальна цена которая сейчас зачеркнута?
Резкие изменения курса доллара в конце 2014г. подлили масла в огонь. Очень захотелось получить ответ на вопрос как зависят цены от курса доллара в реальности.
В итоге, я решил покончить с этими вопросами и собрать историю изменения цен по российским интернет-магазинам. По катом результаты работы + несколько интересных закономерностей.
Немного технический подробностей
На данный момент в системе работают несколько десятков парсеров написанных на python.
Хранить данные в лоб мне показалось очень расточительным, решил хранить только изменения цены. Если цена не меняется — записи в БД не создаются, такой подход позволяет очень хорошо экономить ресурсы. На данный момент в таблице всего 200 000 000 строк, что не так много для данных по ~100 000 товаров в >1000 магазинов за 8 месяцев.
В качестве хранилища используется MySQL 5.6. Недавно пришлось переехать на SSD, так как обычные HDD на Hetzner не очень справлялись с большой нагрузкой на запись.
В данной статье я хотел бы описать интересные закономерности найденные при анализе собранных данных:
1. Синхронное изменение цены
Собрав базу за несколько месяцев, я решил проанализировать коэффициент корреляции между предложениями одного и того же товара от разных магазинов. Для этого был быстренько набросан скрипт на python + pandas. Pandas в данном случае очень помог наличием функции resample.
sql = """
SELECT pr.date, pr.shopitemid, price from prices AS pr
JOIN shopitems AS si
ON pr.shopitemid = si.id
WHERE si.itemid = 1
AND si.shopid > 10
AND si.last_price IS NOT NULL
ORDER BY pr.date
"""
df = pd.read_sql_query(sql, engine)
for item in df['shopitemid'].unique():
x= df[df['shopitemid'] == item]
nans = x.isnull().sum()['price']/float(len(x))
if nans > 0.2 or len(x['price'].unique()) < 10 or x['date'].min() > (datetime.now() - relativedelta(months=3)):
df = df.drop(df[df['shopitemid'] == item].index)
df = df.dropna()
df = df.pivot(index='date', columns='shopitemid', values='price')
df = df.fillna(method='pad')
df = df.dropna()
df = df.resample('24h', fill_method='pad', how='last', loffset='24h')
mtrx = df.as_matrix().T
columns = df.columns.values
corr = np.corrcoef(mtrx)
z = np.where(corr > 0.90)
for x,y in zip(z[0],z[1]):
if x<y:
print columns[x],columns[y]
myplot(mtrx[x])
myplot(mtrx[y])
plt.show()
Проанализируем историю изменения цен на примере холодильника Indesit SB 185.
На выходе получились достаточно интересные графики типа такого:
Здесь можно посмотреть данный график в более удобном формате.
В данном примере видно что у трех магазинов цена изменяется абсолютно синхронно в течение 8 месяцев. Мне видятся такие вероятные причины такого явления:
- В двух из трёх используются системы автоматического выставления цены на основе цен конкурентов.
- Магазины как-то связаны организационно и имеют доступ к общей БД цен
2. Появление нового смартфона.
В момент анализа я наткнулся на график цен по Samsung Galaxy S6.
Мне показался интересным момент появления телефона.
Первая неделя: одно-два предложения с высокой ценой.
Дальше, в течение двух месяцев, постепенно подключаются остальные магазины и разброс цен становится значительным.
3. Самые дешевые интернет-магазины для каждой категории товаров
Собрав достаточно большую базу цен, появилась идея сформировать ТОП-10 самых дешевых магазинов для каждой категории товаров.
Разберем принципы формирования данного списка на примере категории Холодильники:
Пробегаемся по каждому товару категории.
Каждому магазину, продающему данный товар, начисляем баллы от 0-дорого, до 1-дешево.
Алгоритм расчета баллов score = (maxprice-price)/(maxprice-minprice)
Вычисляем среднее от баллов набранных каждым магазином.
Удаляем магазины продающие очень мало товаров данной категории.
Например, для категории телевизоры, получился такой список:
Название |
Кол-во баллов |
Рейтинг на Yandex.Market |
Кол-во оценок на Yandex.Market |
КРАСНАЯ КНОПКА |
0,877 |
5 |
697 |
Топтел |
0,854 |
5 |
1358 |
Pleer.ru |
0,853 |
4 |
52711 |
Greenbook |
0,853 |
5 |
200 |
ОГО |
0,832 |
5 |
4009 |
Technosteps.ru |
0,832 |
5 |
294 |
Soundbreeze |
0,812 |
5 |
662 |
ELECTROGOR |
0,808 |
5 |
6445 |
ЦИФРОВИК |
0,805 |
5 |
460 |
ЭЛЕКТРОЗОН |
0,804 |
5 |
1664 |
4. Зачем же я всё это писал?
В качестве фидбэка от уважаемого сообщества мне очень хотелось бы получить ваши идеи по анализу данного датасета.
Что ещё можно проанализировать, какие интересные закономерности попробовать найти?
Чтобы предоставить возможность каждому посмотреть историю цен, тем более скоро черная пятница, я набросал простенькую веб-морду с возможностью поиска по товарам. Можете поиграться тут, надеюсь, не ляжет.
UPD 01.12.2015: Добавил возможность уведомления при снижении цены ниже определенного порога.
Комментарии (59)
eaa
26.11.2015 11:15+13В данном примере видно что у трех магазинов цена изменяется абсолютно синхронно в течение 8 месяцев. Мне видятся такие вероятные причины такого явления:
В двух из трёх используются системы автоматического выставления цены на основе цен конкурентов.
Магазины как-то связаны организационно и имеют доступ к общей БД цен
Я вот буквально вчера на сайте МВидео читал, что они готовы продать товар по меньшей цене, если у конкурентов цена меньше. Так вот, оказывается, они учитывают только тех конкурентов — а там прям явно написан их список мелким шрифтом внизу, каких — у которых цены точно такие, как у них плюс-минут 100 рублей. А у кого цены меньше на несколько тысяч — «сорри, это неправильный конкурент».
Очевидно, что цены они согласуют между собой, вопрос только в механизме.Artima
27.11.2015 13:19+2Этот механизм называется РРЦ. А подобные функции типа «готовы продать товар по меньшей цене, если у конкурентов цена меньше» делаются в первую очередь для мониторинга цен конкурентов усилиями клиентов, в не самого магазина. Все немного иначе с другой стороны. ;)
eaa
27.11.2015 16:40Вот только если у кого-то реально цены ниже — то они не готовы по такой цене продать
KriMs
27.11.2015 22:59Готовы. Покупал объектив за 5к вместо 6
icoz
28.11.2015 11:18А сколько вы времени потратили в поисках у кого дешевле?
KriMs
28.11.2015 11:50Минуты 2
icoz
28.11.2015 11:54+1С другой стороны, вы сказали, что есть дешевле, и вам отдали за 5к. Через 10 минут пришёл другой покупатель, он не знал, что есть дешевле, и взял за 6к. Тоже вполне себе модель бизнеса.
Artima
29.11.2015 13:48Все верно, а параллельно они включают определенные рычаги и цена конкурента становится не 5 тыс, а те же 6 тыс.
Artima
29.11.2015 13:46Кто-то готов. Но, возможно, кто-то возьмет от вас полезную информацию, а продавать не будет. Хотя последний случай очень странный и ведет не только к потере клиента и минимального дохода, но и к негативной оценке. Мы, бывало, даже в минус себе продавали, только бы отстоять заявленные нами правила игры. Не скажу, что это сделало нас в итоге супер-счастливыми, но факт в том, что такие магазины бывают, если задаться целью их найти.
rPman
26.11.2015 11:35+1Некоторые (многие?) магазины могут играть ценой за счет изменения цены доставки, специально или так получается, но это тоже важно, особенно если товар категории до 5т.р. даже 500р доставка уже ощутима.
Можно парсить их предложение по доставке в пару тройку регионов страны пары-тройки товаров разной категории (мини — сотовый, средний — ноутбук/монитор,… большой — холодильник), соответственно визуализация может быть либо учтена в графиках при выборе особенности стоимости доставки выше либо отдельные графики по каждой категории товаров.
alexkuku
26.11.2015 12:51+2Вообще, очень крутая тема:
1. Можно пробовать ловить демпинг. На некоторые товары есть минимальная цена. Производитель обычно строго следит, чтобы она не нарушалась, можно ему помочь
2. Пробовать определять успешность продукта по тому, как быстро падает его цена. Например, сравнить Айфоны
3. Пробовать предсказать по первым неделям продаж, какая будет цена через несколько месяцев. Поможет определиться покупать сейчас или подождать
4. Проверять действительно ли магазин делает скидку или сначала повешает, а потом понижает цену
5. Посмотреть с какой задержкой и как влияют курсы на цены и предсказывать цены исходя из курсовAclz
26.11.2015 13:19+3Только часто бывает цена на сайте одна, а звонишь — и там она, оказывается, совсем другая, такая же как у конкурентов («не успели обновить сайт»).
areht
04.12.2015 01:44Не часто, но первые 3-5 строчек на прайсру действительно мошенниками забиты. Наверное, они статистически должны выявляться провалом в 5% от всех конкурентов.
ssh1
26.11.2015 13:26Спасибо за идеи.
1. Вопрос где её взять, да, и интересно ли это производителю.
2. А является ли падение цены критерием успешности?
3. Интересно, но отсмотрев вручную около сотни графиков закономерностей не нашёл.
4. Спасибо, надо подумать как достать предложение о скидке. Бывает приходит рассылка: «Вот купон, он дает ссылку 10% на эти товары» и т.д.
5. Тоже думал. Доллар вырос в 2 раза. У многих товаров цена вообще не зависит от него. Хотя возможно она бы падала в случае неизменного курса.
Вообще я думал попробовать предсказать цену товара на основе прошлых цен + цен на товары в других категориях. Есть надежда что цены на стиралки, например, могут являться хорошими фичами для предсказания цен на холодильники. Пока не дошли руки.
DmitryO
26.11.2015 13:13Замечательный сервис, спасибо. Праздный вопрос — повествование ведется от первого лица, ниужели это все сделано «в одни руки»?
ssh1
26.11.2015 13:17+1Спасибо. Да, долго, нудно, но в одни )
Pashkevich
26.11.2015 21:10Вы цены откуда берете?
Из xml-выгрузок?
Или парсите сайты? Все >1000?
И почему магазинов больше 1000, а товаров всего то 100 000?ssh1
26.11.2015 21:17Парсинг магазинов/аггрегаторов
100 000 имеется в виду уникальных товаров, а не пар товар-магазин.
Да, кстати, как поживает ваш аналогичный проект? Планируется какое-либо развитие?Pashkevich
26.11.2015 21:25Спасибо, что спросили.
Сам сервис живет нормально.
Всё работает, цены каждый день я скачиваю и отображаю на сайте. С этим нет проблем.
С развитием пока не делаю ничего.
Скоро приступлю, я думаю к доработкам.
И первое, что сделаю, это нормальный удобный интерфейс. )))
Anisotropic
26.11.2015 13:28Поиск несколько странный. Sony z5 не находит, выдаёт кучу товаров и ни одного телефона.
ssh1
26.11.2015 13:41+1Согласен, поиск не очень хорош. Думаю прикрутить sphinx как дойдут руки.
icoz
28.11.2015 11:59Может на хабре опишете как реализован ваш проект? Какие технологии, языки, библиотеки…
ssh1
28.11.2015 13:29Парсеры python + urllib
База MySQL 5.6 недавно перешел на SSD
Пришлось немного повозиться чтобы научиться писать данные без избыточности
WEB — python + Django + bootstrap + highcharts
Memcached
Среднее время ответа сервера, судя по ньюрелик, 20-30мс. Учитывая что в кэше явно есть не всё, считаю это вполне достойным результатом)
DmitryO
26.11.2015 13:30+1В копилку «дурацких идей» — вполне очевидная секция «Latest Deals». Навеяно «Черной пятницей».
Список TOP X товаров, цена на которые опусилась [в магазине N] ниже медианы на YY% за какой-то период.
Styxx
26.11.2015 13:33Хотелось бы копию проекта, натравить на магазины своего региона! А то перед покупкой много работы приходится делать в поисках…
И то находишь цену, уточняешь, а она не актуальна или нет в наличии и т.д…
tonick
26.11.2015 14:11Как строится монетизация проекта?
ssh1
26.11.2015 15:09Пока никак, с рекламы есть надежда окупить часть затрат на сервер.
В дальнейшем, была идея преобразовать это в сервис рекомендаций по ценообразованию. Отслеживаем цены конкурентов -> выставляем оптимальную цену на автомате.
Но это уже другая история, вопрос, дойдут ли руки.
BupycNet
26.11.2015 15:45-4А вы ведь данные собираете какими то ботами?
Можете сделать канал у нас в сервисе PushAll, чтобы можно было подписываться на определенные товары? Ну т.е. например если цена на какой то товар упадет ниже определенной цены — уведомить меня об этом push-уведомлением.
Даже можно сделать эту фичу платной, чем собственно окупить в итоге ваш проект.
PS. у нас в сервисе будут платные каналы, можно на основе этой платформы сделать платный канал с оповещениями о изменении цен.
Например я хочу купить Nexus 9 где нить в районе 20-21к, вроде цена много где падает, причем интересно. что цена уже сейчас ниже чем зарубежом в $, интересно упадет ли еще.
- 26.11.2015 15:49+4
А как вы связывали товары между собой?
В магазинах же может быть разное название у одного и того же товара.silenzushka
26.11.2015 21:53Это делает API Яндекс.Маркета, на сколько я понял принцип сервиса.
ssh1
26.11.2015 22:01Связки достаточно сделать один раз.
Тут работает свой алгоритм определения близости по цене и названию + парсинг агрегаторов. В общем есть куда развиваться.silenzushka
26.11.2015 22:05+1Раз не из Маркета берёте, то за алгоритм (и его ручную доводка) отдельный респект. Огромная работа.
ragman
27.11.2015 08:58Здравствуйте. Заинтересовался сервисом и решил проверить на личном опыте.
На днях подбирал смартфон и, в частности, смотрел на модель Prestigio Muze C3. Один такой уже купил жене, теперь заказал дочке.
Так вот, оба телефона приобрел в Юлмарте.
Ваш сервис сообщает что на сегодня (27.11.15г.) его нет в наличии в данном магазине. Иду в магазин — есть. Возможно его нет в каком-либо другом городе. Но тогда нужно и это учитывать в Вашем сервисе. Либо Вы не смогли получить данные с сайта (вчера в 19:00, например, сайт Юлмарта лежал глухо).
И да, они, видимо как и все другие, перед «черной пятницей» подняли на него цену, а затем сделали скидку. Скидка здесь без кавычек, так как скинули все-таки больше, чем добавили. «Но осадочек остался».
Ваш сервис показывает что вчера (26.11.15) цена на него была 7490руб., но я его приобрел вчера же со скидкой за 5990руб.
А вообще приятный сервис. Лишний раз убедился что честных скидок не бывает.ssh1
27.11.2015 09:52Спасибо за комментарий. Данные на графиках выводятся после ресэмплинга, соответственно, если на графике точка в 18:00, это не значит, что именно в 18:00 была такая цена. Плюс к этому магазины скорее всего очень часто меняют цены в период чёрной пятницы.
Спасибо за фидбэк, попробую изучить подробнее что происходило.ragman
27.11.2015 09:59Возможно проблема в том, что нет цены на этот телефон в магазине Юлмарт на Яндекс.Маркете.
pro100olga
27.11.2015 09:52Впечатляет! Очень интересно, спасибо. Помимо курса доллара, о котором говорили выше, еще хотелось бы на графиках видеть собственно даты (месяцы), чтобы понять наличие сезонных колебаний цен (есть ли смысл покупать под Новый Год, например)
ssh1
29.11.2015 13:51Спасибо. Какие даты вы имеете в виду? Снизу вроде есть даты?
pro100olga
29.11.2015 14:49Да, вы правы. Это я сфокусировалась на графиках по холодильникам — там по оси Х только числа (номера наблюдений, видимо).
Получается, вы где-то с весны начали собирать данные (смотрю опять же холодильники на сайте), то есть про Новый год можно будет в следующем году сказать. И кстати про 8 марта тоже будет интересно, по каким категориям цены меняются, если меняются вообще.
Интересно, что максимальная цена меняется чаще и больше, чем минимальная — почему так может быть? Возможно, минимальная установлена на уровне близком к нулевой рентабельности?ssh1
29.11.2015 15:26Да, все праздники в следующем году можно будет отследить в реальном времени.
Мне кажется, максимальная цена меняется чаще, так как в районе максимальной цены плотность магазинов намного меньше чем в районе минимальной. Соответственно пропадание товара в магазине с максимальной ценой ведёт к более резкому скачку.
pro100olga
27.11.2015 13:38А еще вопрос: сколько человекочасов заняла организация парсинга (написание, отладка)? А сколько написание этого материала, включая анализ? Мне кажется, это огромная работа, хочется оценить ее как-то количественно )
ssh1
29.11.2015 13:58+2Проект делался в свободное время, в качестве хобби.
Если пересчитать:
Парсинг + отладка + игра «успей за изменениями на источнике» — 5 недель
Веб морда — 3 недели
Анализ — 5 часов
Статья — 1 час
Могу ошибаться в 2-3 раза в любую сторону)
negodnik
27.11.2015 23:17Сколько магазинов подключено вручную? Ведь довольно много магазинов, которых нет на маркете.
DjOnline
30.11.2015 21:22Есть ли API или выгрузка для интернет-магазинов?
Учитываются ли разные цены на разные цвета в одной карточке товара?
Сюда ещё бы интеграцию с я.маркетом, чтобы помечалось «эта позиция в этом магазине рекламируется в я.маркете». Ведь не все магазины там размещаются, поэтому не всегда там лучшие цены.
Максимальная цена возможно считается неправильно в этом товаре http://priceanalytic.com/item/3612/, цифра 88800 пишется, но магазинов с такой ценой нет.
Ну и актуальный фичареквест — переключатель рубли/USD/Euro для исторических данных.
Также хотелось бы обновления таблицы магазинов при нажатии на дату на графики, например непонятно кто это устроил аттракцион невиданной щедрости 3го августа здесь http://priceanalytic.com/item/40352/
ssh1
01.12.2015 17:43Всем спасибо за обратную связь.
Добавлены уведомления при снижении цены ниже определенного порога.
melon
02.12.2015 15:36+2Круто! Народ, зацените график для цен на айфоны priceanalytic.com/item/73558. Видны два отчётливых пика перед 4 и 11 ноября, которые были днями распродажи) Очередное доказательство, что чёрная пятница в РФ не более чем утка!
Tux
Отличный сервис, весьма полезно. Только таблицы не сортируются, а жаль.
ssh1
Да, это первый вариант. Я думаю соберу фидбэк и что-то доработаю.
foxyrus
Нужно из графика выкидывать (может опционально) экстремум. Сейчас получился например такой график, ничего не разглядеть.
ssh1
Да, это косяки при сборе данных. Лучше обрабатывать при сборе, а не на выводе.
Спасибо за пример.