вам с питоном и его pandas :)
Сразу скажу, что я не профессионал ни в R, ни в питоне, тем не менее я пишу рабочие .py и .R скрипты уже больше двух лет. Поэтому буду очень рад конструктивной обратной связи.
Ситуация. Работаю с API Авито, получаю статистику сразу от нескольких клиентов, собираю в 1 таблицу, чтобы хранить в таком виде в БД - это удобно, потому что список клиентов каждый раз меняется. Изначально при парсинге данные с API собираются в один большой JSON {клиент: статистика}, откуда уже удобно для меня превращается в таблицу итоговой статистики сразу по нескольким клиентам.
Данный код отрабатывает за 43 сек и потребляет в пике 1765 MB ОЗУ. JSON и свой код питона прикладываю.
Нюанс 1. Я знаю что такое асинхронность и многопоточность в питоне, но прежде чем распараллеривать процессы - я бы хотел их для начала оптимизировать, поэтому в примере работа кода последовательна.
Нюанс 2. Я пробовал генераторы обернуть в pd.Series, получалось снизить ОЗУ на 200-250 MB, но процесс растягивался по времени почти в 2 раза - с 43 сек до 81 сек.
Почему я вообще взялся решать вопрос потребления ОЗУ? Потому что из-за того, что на Ubuntu процесс жадно потребляет ОЗУ - система просто убивает процесс как опасный для системы. Как временное решение - я с запасом выкрутил параметры сервера с 1 гига ОЗУ до 4. Теперь ничего не падает, но вопрос не даёт покоя)
Я переписывал на R данный блок, что удивительно - он отрабатывал практически без потребления ОЗУ и на 20 с быстрее. Но только из-за этого момента я бы не хотел все действующие скрипты переписывать на R. Поэтому прошу совета по работе с pandas у знатоков с опытом :)
Заранее всех участников благодарю.
А вы уверены, что хотите хранить несколько клиентов в одном json? Вы же даже в коде все операции выполняете на уровне клиента. Если у вас каждый клиент представлен списком словарей, то логично использовать pd.DataFrame.from_records(dict_list) Это должно быть быстрее прохода по циклу и меньше по памяти
есть какая-то причина почему это нужно держать именно в формате словаря? а не csv например? мне кажется, что если сможете избежать использования циклов, то существенно сократите потребление ОЗУ и повысите скорость скрипта
Чуть поправлю. Я всего-лишь пригласил. Многие же не пугаются питон кода и могут подсказать. Можно и альтернативу на R дать.
Стикер
Я сейчас не вижу какой-то причины, почему сбор информации по клиенту не может быть отдельным процессом/вызовом функции, вы же не высчитываете, какие-то метрики для которых вам нужны все записи, вы просто поочередно проходитесь по каждому клиенту, они друг от друга никак не зависят. Может быть проще сделать сбор данных по каждому клиенту отдельным процессом, выносить это в отдельную таблицу, а уже потом собирать результаты воедино? Логично, что у вас потребление памяти высокое - словарь не очень оптимальный способ хранить данные
Я думаю основная проблема именно в сборе информации. Сам по себе скрипт практически не использует память ровно до момента сбора воедино. Именно процесс сбора воедино занимает пиковую нагрузку.
тогда поиграйтесь с типами данных - условно, можно привести строковые колонки к категориям, заменить float на int, тогда снизится потребление памяти при конкатенации датафреймов вот здесь разбирают конкретные примеры но в любом случае это pandas, он очень сильно ест память, к сожалению
я все задачи перекладывания джесонов возложил на это: https://airbyte.com/ Есть как клауд (платный), так и open source. В источниках нет апи авито, но в моём кейсе также нет кучи источников из коробки, зато есть connector builder и там за час-другой (в зависимости от опыта, я коннектор на простом апи создаю менее чем за час) можно с нуля создать любой коннектор к апи, который возвращает джейсоны. Советую
Airbyte в моём случае (перекладывание данных из mysql в postgresql) оказался тяжеловесным медленным куском копролита. Решили в итоге задачу одним коротким оператором в airflow
ну так я и говорил про перекладывания из апи в хранилище, а не из базы в базу)
Это туда входит. Перекладывание джейсонов - общий неформальный термин.
Если мне надо читать данные из апи, складировать их в хранилище и попутно преобразовывать (не супер сложно, но то же объединение, удаление лишних полей). Например Интерком в кликхаус или тикток в бигквери. Ваша задача похожа на довольно простую в плане логики: забери из апи, немного преобразуй и положи в базу. Это именно то, что и делает эйрбайт.
по примеру непонятно зачем словарь. словарь — вещь тормозная + накладные на менеджмент памяти. Все складывается в прямоугольную таблицу. Ну и про pandas лучше забыть в таких задачах. polars спасет. + если беспокоит память и нужно ускорить то лучше делать в многопоток , каждый поток сбрасывает в файлы на диск, а потом одним махом все с диска считать и собрать. не будет оверхеда на передачу данных между потоками. можно и в баше собрать если csv
Словарь типа "клиент: все его данные ', там токены, id, балансы всякие. Просто складировать удобно.
в плоской таблице кратно удобнее и быстрее
Увы, вопрос не в скорости)
Словарь много хуже прямоугольной таблицы поскольку в нем энтропия больше. В таблице известен размер, а также типы колонок. В словаре — неизвестно ничего, можно встретить любого зверя. Больше хаоса — больше времени и доп. информации, чтобы держать это под контролем.
Еще упоминал типовые схемы здесь и здесь
Меня всегда интересовал вопрос, как вы всё помните где и о чем писали? У вас какая-то таблица с тегами?)
Обсуждают сегодня