PPC для сверхразумов | Александр Хитро
Открыть в Telegram
13 лет в рекламе @podorozhnik_ppc Автор t.me/ppc_bigbrain/865 Меню t.me/ppc_bigbrain/1191 Чат t.me/+IAE-w7o7tZtjOTNi Подписка t.me/ppc_bigbrain/1496 t.me/ppc_bigbrain/1497 Отзывы t.me/ppc_bigbrain/1004 t.me/ppc_bigbrain/1249 Комбайн t.me/ppc_bigbrain/1582
Больше3 904
Подписчики
+224 часа
+107 дней
-1230 день
Архив постов
+2
эмэйзинг нейродрисня
когда пытаешься вправить нейтронке мозги из задницы в процессор, создав ей пачку скиллов с сотней руководств по тому, как думать, а она всё ещё тупорылая шопездец
via @ppc_bigbrain
маркетологи, как вам портрет платежеспособной аудитории? сохраняем или осуждаем?
via @ppc_bigbrain
Что вы попробовали в своей карьере из любых родов деятельности один раз и сразу поняли, что это не для вас?
Начну с себя.
Меня за 13 лет в контекстной рекламе хватило на один раз в жизни:
- На настройку 1 смарт кампании в Google Ads.
- На настройку 1 мастера кампаний в Яндекс Директе.
- На 1 разговор с менеджером Гугла об аудите моего аккаунта Google Ads.
- На 1 разговор с менеджером Яндекса об аудите моего аккаунта Директа.
Расскажите о своём незабываемом опыте, рот которого вы шатали.
via @ppc_bigbrain
шта? абисните плес, я прост с деревни
шёл 8к26 век, впнологи щщщетали цену клика калкурентов через время появления ремаркетинга
песдос
есус, дай им мозгов
пишите в элэс, пащщетаю в калбайне цену клика ваших калкурентов через разницу в градусах между вашим углом стояния раком при настройке МК и восьмым козырем бубной в четверг
via @ppc_bigbrain
«а мы агентство, которое скликивает рекламу по заказу яндекса»
кулстори от того, кто умеет делать хорошо и кому нет причин не доверять
via @ppc_bigbrain
+3
когда бог директа раздавал хромосомы, но не хватило на целую индустрию
via @ppc_bigbrain
я как бы ни на что не намекаю, но люди интересуются
via @ppc_bigbrain
изучайте портреты ца, говорили они
фильтруйте интенты запросов, говорили они
сегментируйте семантику, говорили они
пишите релевантные заголовки, говорили они
via @ppc_bigbrain
Меня жизнь к такому не готовила.
Как реагировать на то, что легенда веб-аналитики, на книгах и статьях которого выучилось всё русскоязычное сообщество интернет-маркетинга, советует меня своим ученикам?
Для этого существует какая-то специальная медалька в списке карьерных ачивок? А в форме подорожника есть?
via @ppc_bigbrain
Что изучать для BI-разработки и работы с данными.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных. 9. Смерть производительности. Часть 1. 10. Смерть производительности. Часть 2. 11. Плохие и хорошие примеры. 12. Когда в PQ сортировать данные. 13. Параметризация переменными. 14. Что учесть перед созданием кодаЧто развивать и изучать для обработки данных? ✅ Образное мышление: — Как пример из других кейсов применить к моим данным. — Какие операции выполнить с разными столбцами. — Если нужных полей в этом датасете нет, а в другом — есть, как их можно объединить. — Какие проблемы можно обнаружить, имея в датасете нужные столбцы. — Как их создать. — Как данные из кастомных столбцов применить в дашбордах как критерии: а) Группировки. б) Сегментации. в) Фильтрации. — Какие куски кода параметризировать, чтобы применять его на других проектах. — Как реализовать гибкость и управляемость обработкой данных, чтобы не хардкодить пользовательские значения текстом в коде, а обращаться к динамическим спискам: а) Умным таблицам. б) Именованным диапазонам. в) Папкам с файлами. — Какие проблемы и задачи универсальны для всех проектов. — Как подготовить общие (глобальные) библиотеки данных, которыми можно пользоваться в любом проекте. — Какие проблемы и задачи являются частными для каждого проекта. — Как подготовить локальные библиотеки данных, которые в каждом проекте будут свои. — Как заранее предусмотреть конфликты значений в локальных и глобальных библиотеках, т.е. реализовать поэтапную проверку условий. ✅ Получение данных: — Откуда и что получать. — Какие поля. — В каких группировках. — С какой детализацией. — С какими фильтрами. — За какой период. — Каков объём данных. — Не "ляжет" ли получение данных из-за их объёма. ✅ Если это вручную заполняемые данные (CRM, Google Sheets): — В каком виде данные находятся в источнике. — Плоская ли это таблица (в столбцах — названия полей, в строках — значения). — Какие манипуляции с данными нужно произвести для их преобразования в плоскую таблицу. — Кем заполняются данные. — Какие поля нужно автоматически валидировать (проверять, исправлять, изменять). — Какие нужно обрабатывать частные случаи. — Как это автоматизировать. ✅ Хранение данных: — Каков объём исторических данных. — Частота их обновления. — Интенсивность их обновления, т.е. насколько много новых данных появляется ежедневно. ✅ Среду разработки: — Возможности интерфейса. — Возможности и ограничения языка. — Синтаксис. — Библиотеки. — Типы объектов. — Кастомные функции. — Архитектуру. — Исправление ошибок. ✅ Создание модели данных: — Нормализация модели данных. — Как не раздувать модель данных. — Как обработанные данные собрать в нужные столбцы и таблицы для удобных и полезных дашбордов. — Как позаботиться о масштабируемости модели данных. ✅ Вычисляемые поля: — Как вычислить ту или иную сущность в модели данных. — Почему вычисления метрик лучше делать в модели данных, а не на этапе ETL-процесса перед загрузкой в модель. ✅ Визуализацию данных: — Бесконечный простор нажатия галочек, которые пока сам все не понажимаешь и не используешь, не поймешь, что они делают, и не запомнишь, где они находятся. ✅ Фильтры: — Что нужно иметь в источнике данных или вычислить в коде, чтобы это отобразить удобно и понятно. — Локальная фильтрация листа. — Сквозная фильтрация всего отчёта. ✅ Параметры в дашбордах: — Как визуальные элементы дашборда (фильтры, значения, поля в таблице) сделать автоматически пересчитываемыми, чтобы не городить много вкладок, отличающихся одним полем или метрикой. — Как параметризировать часто используемые элементы. — Как уместить всё самое важное на один холст отчёта. — Как выбирать необходимые визуализации в 1 клик.
Вот для чего создавался комбайн: — ч.1 — ч.2 Чтобы не суецыднуться от ежедневных инсультов при работе с любым проектом на любом языке.via @ppc_bigbrain
Что учесть перед созданием кода
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных. 9. Смерть производительности. Часть 1. 10. Смерть производительности. Часть 2. 11. Плохие и хорошие примеры. 12. Когда в PQ сортировать данные. 13. Параметризация переменными.⚫️ В какие типы объектов преобразовать те или иные данные для ускорения их обработки. ⚫️ Нужна ли сортировка и на каком этапе: 😶 По каким атрибутам: текстовым, числовым. 😶 В каком порядке. 😶 Как получить списки этих полей динамически. ⚫️ На каком этапе получать список список уникальных значений: 😶 Удалением дублей в таблице и по каким столбцам:
Table.Distinct.
😶 Получением списка и удаления дублей в нём:
List.Distinct(Table1[Column1])
😶 Группировкой таблицы и по каким столбцам: Table.Group.
😶 Как сгруппировать остальные столбцы:
🥷 С текстом: List.Sort, List.Distinct, Text.Combine.
🥷 С числами: List.Max, List.Sum, List.Min.
😶 Что вы собираетесь делать с этими данными дальше.
⚫️ На каком этапе значения null заменить на 0. Потому что нейронка не знает, что вы текущий кусок кода через 10 этапов преобразований будете группирований с суммированием, а суммирование null вернёт ошибку.
⚫️ На каком этапе преобразований и в каком столбце указать какой тип данных.
😶 Если в столбце с числовыми значениями будет ошибочно указан текстовый тип данных, агрегатные функции List.Max, List.Sum, List.Min вернут ошибку.
😶 При сцепке (конкатенации) двух столбцов, в одном из которых тип данных — текст, а в другом — целое число, эта операция вернёт ошибку. Сцеплять можно только текст с текстом.
😶 Оборачивание столбца с числами в функцию Text.From преобразует их в текст для последующих текстовых преобразований.
⚫️ Какие функции не использовать, т.к. они очень дорогостоящие, чем их заменить, чтобы они выполнялись мгновенно.
⚫️ Использовать аналоги векторной обработки (всего столбца сразу как единого массива), а не каждой строки по отдельности.
⚫️ Как отфильтровать исходный массив, чтобы вхолостую не применять тяжёлые операции преобразований к строкам, в которых даже нет искомых данных.
😶 По каким условиям фильтровать.
😶 Как получить этот список условий динамически.
⚫️ Как не перегрузить модель данных нормализацией и снежинкой, чтобы визуальный слой быстро обновлялся.
Что изучать для BI-разработки и работы с данными — в следующем посте.
via @ppc_bigbrainПараметризация кода переменными под разные проекты.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных. 9. Смерть производительности. Часть 1. 10. Смерть производительности. Часть 2. 11. Плохие и хорошие примеры. 12. Когда в PQ сортировать данные.✅ Примеры функций для получения динамических списков — в предыдущих постах: — Раз. — Два. ✅ При фильтрации по списку условий во избежание хардкода
{"X", "Y", "Z"} фильтруемых значений, вам придётся придумать логику получения этого списка динамически:
⚫️ Если это статический список (одинаковый для всех итераций обновления данных), можно, например, получить их с листа Excel из умной таблицы или именованного диапазона, и при последующих обновлениях запроса он всегда будет неизменным.
⚫️ Если это динамический список (в каждом проекте свои значения, список и количество которых постоянно меняется):
😶 Либо вам придётся самим придумывать логику их получения динамически.
😶 Либо попросите нейронку вам подсказать, как получить их динамически, возможно, из этого что-то толковое и получится.
⚫️ Любой список разнородных значений указать в столбик и рядом в разных столбцах разметить нужные характеристики всех значений как критерии и порядок группировки, сортировки и фильтрации.
⚫️ Все эти критерии передать в код через весь пайплайн обработки данных как динамические списки.
————
Ничего конкретного показывать и рассказывать не буду, ибо на этом основана вся суть комбайна, в котором я всё это просто охерел придумывать, как всё это реализовать, и как из этого сделать универсальный инструмент под все существующие сценарии работы ппсшника в любых рекламных системах на любых языках.
Полезно разбираться в языке, на котором вы вайбкодите, чтобы явно указывать нейронке, что нужно сделать в той или иной ситуации.
Иногда нейронки генерят производительный код, но инструкции должны быть с явным указанием требований к оптимизации, а иногда даже на платных тарифах даже с подробными промптами и явным указанием, что делать, городят полнейшую дичь.
Вайбкодинг без знания даже основ языка, на котором вы что-то генерите — ещё большее усложнение себе жизни.
О чём подумать перед созданием кода — в следующем посте.
via @ppc_bigbrainКогда сортировать данные можно и нельзя.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных. 9. Смерть производительности. Часть 1. 10. Смерть производительности. Часть 2. 11. Плохие и хорошие примеры.Выносим сортировку из ETL-процесса в Power Query на уровень отчета в следующих случаях: 1️⃣ Для визуального представления. Если сортировка нужна только для того, чтобы видеть таблицу красиво (по алфавиту, по убыванию цены). Excel и Power BI сортируют данные в визуальных элементах (графиках, матрицах) мгновенно, используя оптимизированные движки, не нагружая процесс обновления данных. 2️⃣ Для интерактивности. Если хотим иметь возможность менять порядок сортировки (кликом по заголовку столбца). Жесткая сортировка в Power Query лишает отчет гибкости. 3️⃣ При использовании Top-N фильтров в Power BI. Движок VertiPaq (DAX) вычисляет "Топ-10" в визуализациях быстрее, чем Power Query готовит пред-отсортированную таблицу. ———— Оставляем сортировку в Power Query только если она влияет на логику расчетов: 1️⃣ Для вычисления индекса строки (Index Column). 2️⃣ Для расчета нарастающего итога (Running Total). 3️⃣ Для функций заполнения (Fill Down, Fill Up). В этих случаях обязательно используем
Table.Buffer после сортировки.
Во всех остальных случаях сортировка в Power Query — ошибка и излишняя нагрузка.
————
⚫️ Не сортируем, если можем агрегировать.
Всегда проверяем, можно ли получить результат через Max, Min, Sum или Group. Это золотой стандарт оптимизации.
⚫️ Ранняя фильтрация.
Никогда не сортируем данные до фильтрации. Сначала используем Table.SelectRows, чтобы отсечь все лишнее, и уменьшить количество строк. Сортировка 1000 строк в 100 раз быстрее, чем сортировка 100.000 строк (спасибо, кэп).
⚫️ Используем буферизацию с умом.
Если отсортировали таблицу для сложного расчета и многократного обращения к результатам, берём этот шаг в Table.Buffer. Иначе Power Query может выполнять сортировку заново для каждой последующей строки вычислений.
⚫️ Разделяем данные и представление.
Если сортировка нужна только для презентации, делаем её в модели данных или элементах визуализации данных, а не в ETL.
⚫️ Query Folding — приоритет (но не поддерживается при работе с локальными файлами на ПК, а только с базой данных).
Table.Sort при работе с SQL часто прерывает Query Folding — свертывание запросов. Если сортировка неизбежна и данные не лежат на ПК, выполняем её на стороне сервера, а не в памяти Power BI.
Итого: ➕ Нужно Макс/Мин значение? Используем List.Max, List.Min (вместо Sort+First). ➕ Нужен Топ-N? Используем List.MaxN (вместо Sort+FirstN). ➕ Нужен уникальный список? Используем List.Distinct (вместо Sort+RemoveDuplicates). ➕ Нужно найти соответствие? Используем Table.Join (вместо SelectRows внутри AddColumn). ➕ Нужна красота в отчете? Сортируем в Excel/Power BI, а не в Power Query.✅ Хороший код Power Query: — Выполняется за секунды или минуты, а не часы. — Работает за время O(n) или O(n+m). — Масштабируется с тысяч до миллионов строк. ❌ Плохой код Power Query: — Сортирует "на всякий случай". — Сортирует в циклах. — Сортирует ради отображения. — Отдаёт ошибку нехватки памяти. Для использования самых быстрых альтернатив сортировки, спрашиваем у нейросети:
Как по каждому значению столбца X получить значение из столбца Y, которое соответствует наибольшему значению метрики Z, но: — Не используя при этом сортировок. — Используя функцию, которая сразу возьмёт максимальное значение.В каждом промпте про оптимизацию скорости кода обязательно явно указываем на минимизацию количества вычислений из «Big O» нотации:
1. Используй операции с вычислительной сложностью: O(1), O(log n), O(n), O(n + m), но как можно меньшее из них. 2. Не используй операции вычислительной сложностью: O(n log n), O(n × m), O(n²), O(nᵏ), O(2ⁿ), O(n!).В следующем посте — о параметризации кода переменными для его использования в разных проектах. via @ppc_bigbrain
Плохо vs хорошо — сравнение сложности вычислений.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных. 9. Смерть производительности. Часть 1. 10. Смерть производительности. Часть 2.Рассмотрим альтернативы сортировки и сложность их вычислений. Пример 1: Найти максимальное значение. ❌ Плохо: Отсортировать таблицу по убыванию -> Взять первую строку. Функции:
Table.Sort + Table.First.
Сложность: O(n log n).
Почему плохо: сортируются сотни тысяч строк ради одной.
✅ Хорошо: Использовать функцию поиска максимума.
Функции: List.Max или Table.Max.
Сложность: O(n).
Результат: В разы быстрее.
————
Пример 2: Найти топ-10 самых дорогих товаров.
❌ Плохо: Сортировка всей таблицы -> Взять первые 10 строк.
Функции: Table.Sort + Table.FirstN.
Сложность: O(n log n).
✅ Хорошо: Использовать функцию частичной выборки.
Функции: List.MaxN или Table.MaxN.
Сложность: O(n) или O(n log k), где k — это всего 10 строк.
Результат: Экономия памяти, не нужно упорядочивать "хвост" таблицы.
————
Пример 3: Найти последнюю продажу для каждого клиента (внутри группы).
❌ Плохо: Группировка -> Внутри каждой группы. Сортировка -> Взять первую строку.
Функции: Table.Group + (each Table.Sort -> Table.First).
Сложность: O(n²) или O(n log n).
Катастрофически медленно на больших данных.
✅ Хорошо: Группировка -> Внутри группы поиск максимума.
Функции: Table.Group + (each List.Max).
Сложность: O(n).
Результат: Линейное выполнение за один проход.
————
Пример 4: Проверка наличия значения в списке.
❌ Плохо: Сортировка списка -> Бинарный поиск.
Функции: List.Sort + List.Contains.
Сложность: O(n log n).
✅ Хорошо: Прямой поиск или преобразование в запись (Hash set).
Функции: List.Contains или List.Buffer + Record.FromList.
Сложность: O(n).
————
Пример 5: Поиск соответствий (аналог ВПР или VLOOKUP).
❌ Плохо: Добавление столбца с фильтрацией внутри.
Функции: Table.AddColumn + (each Table.SelectRows).
Сложность: O(n × m). Квадратичная сложность (Nested Loop).
✅ Хорошо: Объединение таблиц (Merge).
Функции: Table.NestedJoin или Table.Join.
Сложность: O(n + m). Использует Hash Match.
————
Пример 6: Сортировка внутри циклов.
❌ Плохо: List.Transform или Table.AddColumn с Table.Sort внутри.
Сложность: O(n² log n) и хуже.
✅ Хорошо: Один проход с агрегатами или предварительная группировка.
Сложность: O(n).
————
Пример 7: Проверка существования значения.
❌ Плохо: Sort + Contains
Сложность: O(n log n)
✅ Хорошо: List.Contains
Сложность: O(n)
✅ Ещё лучше при множественных обращениях к списку для его проверки:
List.Buffer + lookup
Сложность: O(n + m)
В следующем посте — когда в Power Query данные сортировать можно и нельзя.
via @ppc_bigbrainСортировка в Power Query — зло. Часть 2.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных. 9. Смерть производительности. Часть 1.Продолжим список альтернатив сортировке. 7️⃣ Агрегатные функции — сложность O(n). Эти функции выполняют один проход по данным для вычисления результата. ⚫️
List.Max — поиск максимального или минимального значения в списке.
Сложность: O(n).
Применение: вместо тяжелой сортировки всей таблицы по убыванию и взятия первого элемента со сложностью O(n log n).
⚫️ List.Min — поиск минимального значения в списке.
Сложность: O(n).
Применение: Вместо List.Sort + List.First — сортировки по возрастанию и взятия первого элемента.
⚫️ List.Sum — сумма элементов списка.
Сложность: O(n).
Применение: Для агрегации без предварительной сортировки.
⚫️ List.Average — среднее значение элементов.
Сложность: O(n).
Применение: Расчет среднего без сортировки.
⚫️ List.Count — подсчет элементов.
Сложность: O(1) или O(n) в зависимости от реализации.
Применение: Быстрый подсчет элементов без материализации.
⚫️ Table.RowCount — количество строк в таблице.
Сложность: O(1) при наличии метаданных.
Применение: Быстрая проверка размера данных.
✅ Правильный паттерн:
Group + Aggregate
❌ Неправильный паттерн:
Group + Sort внутри каждой группы
————
8️⃣ Функции фильтрации и поиска — O(n).
Фильтрация почти всегда дешевле сортировки и должна выполняться раньше.
⚫️ List.Select — фильтрация списка по условию.
Сложность: O(n).
Применение: Отбор элементов без сортировки.
⚫️ Table.SelectRows — фильтрация строк таблицы.
Сложность: O(n).
Применение: Основной метод фильтрации в Power Query.
⚫️ List.PositionOf — поиск позиции элемента.
Сложность: O(n).
Применение: Линейный поиск в несортированном списке.
⚫️ List.Contains — проверка наличия элемента.
Сложность: O(n).
Применение: Быстрая проверка существования.
⚫️ Table.Distinct — удаление дубликатов.
Сложность: O(n) с использованием хеш-таблицы.
Применение: Дедупликация без сортировки.
⚫️ List.Distinct — уникальные элементы списка.
Сложность: O(n).
Применение: Получение уникальных значений.
⚫️ Record.Field — сложность O(1).
Применение: Самый быстрый способ поиска (Lookup) по ключу.
————
9️⃣ Индексация и lookup — O(1) или O(n).
⚫️ Table.AddIndexColumn — добавление индекса строки.
Сложность: O(n) для создания, O(1) для доступа.
Применение: Быстрый доступ по позиции после создания индекса
⚫️ Table.Buffer — кеширование таблицы.
Сложность: O(n) для создания буфера.
Применение: Предотвращение повторных вычислений.
⚫️ Record lookup (обращение к полю записи) — прямой доступ.
Сложность: O(1).
Применение: Самый быстрый способ lookup в M.
⚫️ List.Buffer — кеширование списка в памяти.
Сложность: O(n) для создания, O(1) для последующих обращений.
Применение: Оптимизация повторных операций.
List.Buffer + lookup — сложность O(n) на построение, дальше — O(1).
Record и Join почти всегда лучше, чем сортировка + поиск.
————
1️⃣0️⃣ Объединение — O(n + m).
⚫️ Table.NestedJoin — вложенное соединение.
Сложность:
✅ Хорошо: O(n + m) — с правильными ключами.
❌ Плохо: O(n × m) — без оптимизации.
Применение: Join с сохранением вложенной структуры. При использовании Hash Join это намного быстрее, чем вложенные циклы.
⚠️ Недостаток: Table.NestedJoin медленее, чем Table.Join, т.к. первая присоединяет и разворачивает вложенные таблицы в каждой строке, а вторая — всю таблицу целиком.
⚫️ Table.Join — соединение таблиц с хешированием.
Сложность: O(n + m) при использовании hash join.
Применение: Объединение данных без сортировки.
⚠️ Неудобство: названия столбцов в таблице 2 не должны повторять названия столбцов из таблицы 1.
————
1️⃣1️⃣ Специализированные функции.
⚫️ List.BinarySearch — бинарный поиск в отсортированном списке.
Сложность: O(log n).
Применение: Эффективный поиск, но требует предварительной сортировки.
В следующем посте — плохие и хорошие примеры с анализом сложности вычислений.
via @ppc_bigbrainСортировка — смерть производительности. Часть 1.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений. 8. Порядок обработки данных.В Power Query функции сортировки
Table.Sort, List.Sort — одни из самых "дорогих" операций.
❌ Имеют вычислительную сложность O(n log n).
❌ Прерывают потоковую обработку данных.
❌ Ломают ленивые вычисления.
❌ Заставляют систему загружать все данные в оперативную память.
❌ При использовании в циклах быстро превращаются в вычислительную сложность O(n²) и хуже.
❌ Часто ломают Query Folding (свертывание запросов) — касается только к SQL запросов, а не к лежащим на ПК файлам.
Эксперты BI индустрии сортировку используют только в крайних случаях.
————
Категоризация альтернатив сортировке.
Ниже перечислены функции, которые выполняют задачи поиска и отбора данных быстрее, чем сортировка.
1️⃣ Функции поиска экстремумов (максимума/минимума) для таблиц — сложность O(n).
Вместо упорядочивания всего списка ради одного значения используются агрегатные функции.
⚫️ Table.Max — поиск строки с максимальным значением по столбцу.
Сложность: O(n).
Применение: Вместо Table.Sort + Table.First. Например, чтобы не оставлять только одну строку с максимальным расходом для каждой рекламной кампании, где сложность — O(n²) или O(n log n).
⚫️ Table.Min — поиск строки с минимальным значением по столбцу.
Сложность: O(n).
Применение: Вместо Table.Sort + Table.First
————
2️⃣ Получение элементов списка по позиции — сложность O(1).
Если данные уже имеют структуру, сортировка не нужна.
⚫️ List.First — первый элемент списка.
Сложность: O(1). Мгновенное взятие первого элемента.
Применение: Быстрый доступ к началу списка.
⚫️ List.Last — последний элемент списка.
Сложность: O(1).
Применение: Быстрый доступ к концу списка.
————
3️⃣ Топ-N без полной сортировки списка
⚫️ List.MaxN — N максимальных элементов из списка.
Сложность: O(n × k).
Применение: Частичная сортировка для топ-элементов.
⚫️ List.MinN — N минимальных элементов из списка.
Сложность: O(n × k).
Применение: Поиск топ-элементов.
⚫️ List.FirstN — первые N элементов.
Сложность: O(n).
Применение: Срез данных с начала.
⚫️ List.LastN — последние N элементов.
Сложность: O(n).
Применение: Срез данных с конца.
————
4️⃣ Получение элементов таблицы по позиции.
Если данные уже имеют структуру, сортировка не нужна.
⚫️ Table.First — первая строка таблицы.
Сложность: O(1).
Применение: Получение первой строки без сортировки.
⚫️ Table.Last — последняя строка таблицы.
Сложность: O(1).
Применение: Последняя строка без сортировки.
⚫️ Table.FirstN — первые N строк таблицы.
Сложность: O(n).
Применение: Выборка строк с начала.
⚫️ Table.LastN — последние N строк таблицы.
Сложность: O(n).
Применение: Выборка строк с конца.
————
5️⃣ Топ-N без полной сортировки таблицы
⚫️ Table.MaxN — поиск N строк с наибольшими значениями.
Сложность: O(n × k), где k — количество элементов (обычно k << n). На практике близко к O(n).
Применение: Топ-N элементов без полной сортировки.
⚫️ Table.MinN — поиск N строк с наименьшими значениями.
Сложность: O(n × k).
Применение: Поиск нижних N элементов.
Используется вместо: Sort + FirstN.
————
6️⃣ Группировка и агрегация — O(n) или O(n + g).
⚫️ Table.Group с вложенными функциями агрегации List.Max, List.Sum, List.Average, List.Count в группируемых полях.
Сложность: O(n) для группировки + O(g) для агрегации, где g — количество групп.
Применение:
— За один проход группирует данные с агрегацией.
— Самый мощный инструмент для замены сортировки.
— Cокращает объем данных при работе с группами.
— Ищет "лучшую" строку в группе без внутренней сортировки.
— Не замедляет обработку папки с файлами до сложности O(n²).
⚫️ List.Accumulate — пользовательская агрегация.
Сложность: O(n) при O(1) операции в функции.
Применение: Сложные агрегации без сортировки.
В следующем посте — больше альтернатив сортировке: агрегация, фильтрация и поиск, индексация и lookup, join.
via @ppc_bigbrainВ каком порядке оптимальнее обрабатывать данные.
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления. 7. Фатальный пример вычислений.1️⃣ Удаляем ненужные столбцы. 2️⃣ Обрабатываем не исходный массив с разбивкой по датам и другим атрибутам, а в новом запросе ссылаемся на этот массив, получаем список уникальных значений из нужного столбца. 3️⃣ Обрабатываем уникальные значения в новом столбце. 4️⃣ Если эти данные нужны на следующих этапах — объединяем исходный массив с этим запросом по общему полю. 5️⃣ Если эти данные нужны в таком виде в конечной визуализации данных: а) Выгружаем второй запрос в модель данных. б) Объединяем две таблицы по ключевому полю в модели данных, т.к. это работает быстрее. ✅ Нет необходимости понимать код. Достаточно понимать, как попросить нейронку:
1. Обратиться к нужным таблицам и столбцам. 2. Какие операции нужно сделать. 3. Что должно получиться в результате. 4. Какие вычисления безопасны: O(1), O(log n), O(n), O(n + m). 5. А какие — смерть для производительности: O(n log n), O(n × m), O(n²), O(nᵏ), O(2ⁿ), O(n!).✅ Если группировать таблицу нужно по списку полей, названия которых могут меняться от проекта к проекту, для возможности использования кода в других проектах, список этих полей нужно получить динамически: 😶 Либо обратившись к умной таблице в Excel, куда вводить вручную эти значения, и передавать их дальше в код просто как название списка (количество элементов в списке и их значения при этом будут не важны). 😶 Либо вычленив общие текстовые паттерны в заголовках этих полей и отфильтровав: 1. Значение:
{"Текст"}.
2. Хардкод списка (так делать не нужно): {"Текст1", "Текст2", "Текст3"}.
3. Имя списка, который динамически получает список текстовых значений.
Примеры, как их отфильтровать (список неполный, ибо способов — уйма) по:
— Содержанию: List.Contains
— Отсутствию: not List.Contains
— Началу: Text.StartsWith
— Не началу: not Text.StartsWith
— Окончанию: Text.EndsWith
— Не окончанию: not Text.EndsWith
😶 Либо обратив внимание на расположение в таблице самих полей и если они находятся:
— Или всегда в начале;
— Или всегда в конце;
— Или идут подряд;
— Или стоят до, после или между полями с заведомо известными значениями;
То получить функцией Table.ColumnNames список полей таблицы, а дальше отфильтровать их:
— Взяв N элементов с начала списка: List.FirstN
— Взяв N элементов с конца списка: List.LastN
— Удалив N элементов в конце списка: List.RemoveLastN
— Получив диапазон значений между N и M позициями списка: List.Range
— Пропустив N элементов с начала списка: List.Skip
✅ Преобразуем список уникальных значений:
😶 Удаляем дубликаты, пустоты, null.
😶 В начале следующего запроса буферизуем его: List.Buffer.
В следующем посте — о смерти производительности кода в Power Query.
via @ppc_bigbrainФатальный пример, который будет вычисляться вечность
Предыдущие посты серии: 1. Документация по промптам. 2. Выбор нейронок. 3. Подготовка к разработке. 4. Оптимизация кода. 5. Если код не "летает". 6. Минимизируем вычисления.Это не придуманный пример. Это кулстори о том, как началось моё знакомство с обработкой данных 6 лет назад. ❓ Задача: взять данные из одной таблицы и отфильтровать в ней данные из другой таблицы. Решение от сверхразума (НЕ НАДО ТАК ДЕЛАТЬ): 1️⃣ К текущей Таблице 1 — небольшой выгрузке данных из рекламного кабинета со всеми возможными атрибутами и метриками и детализацией до дат:
500.000 строк * 30 столбцов = 15.000.000 ячеекПрисоединяем Таблицу 2:
10.000 строк * 10 столбцов = 100.000 ячеек2️⃣ Потом отсортируем строки. 3️⃣ Потом отфильтруем строки по ряду условий. 4️⃣ Потом создаем новые столбцы, что инициирует создание копии целой таблицы. Но из-за незнания матчасти к чему приводит именно такой порядок действий: 1️⃣ Сначала в Таблице 1 создаем новый столбец. Тем сам записывая в память всю таблицу целиком, т.к. каждая операция
Table.AddColumn создаёт в памяти копию всей исходной таблицы.
2️⃣ В новом столбце Таблицы 1 ссылаемся в каждой ячейке на целиком всю Таблицу 2. Тем самым создав столько же копий Таблицы 2, сколько строк в Таблице 1.
Только за сам факт того, что объединение таблиц выполняется таким зверским садистским для процессора способом, уже нужно отрубать руки и публично пинать ссаными тряпками.
3️⃣ Разворачиваем Таблицу 2 целиком, тем самым умножив друг на друга количество строк из Таблицы 1 на количество строк из Таблицы 2:
500.000 строк * 10.000 строк = 5 млрд строкА также расширили объединённую таблицу на количество столбцов из Таблицы 2:
5 млрд строк * (30 + 10 столбцов) = 200 млрд ячеекТеперь в объединённой таблице 200 миллиардов ячеек. 4️⃣ И этот массив мы еще дальше собираемся: ➕ Сортировать. ➕ Фильтровать. ➕ Добавлять несколько новых столбцов — каждая вызванная функция
Table.AddColumn создает в памяти копию целиком всей объединённой таблицы из 200 млрд ячеек с каждого предыдущего шага.
Нетрудно догадаться, что после перемножения таблиц каждая из последующих операций вызовет во столько же раз больше вычислений, во сколько раз выше стала Таблица 1, будучи умноженной по вертикали на количество строк из Таблицы 2.
Накинем сюда ещё и то, что чем больше столбцов в любом обрабатываемом массиве, тем дольше отрабатывает каждый шаг.
При присоединении и разворачивании целиком всех столбцов из Таблицы 2, в которой было 10 столбцов, ради того, чтобы, например, оставить в итоге 1–2 столбца, общее количество вычислений при дальнейших сортировках и фильтрациях будет рассчитываться не только умножением строк из Таблицы 1 на количество строк из Таблицы 2, а ещё теперь и на общее количество столбцов в объединённой таблице.
Вот откуда берутся долго работающие запросы.
Вот откуда растут ноги у проблемы.
Надо ли добавить очевидное, что спустя сутки ожидания я так и не дождался обработки этого запроса 6 лет назад? А ждал бы до сих пор.В каком порядке оптимальнее и быстрее обрабатывать данные для возможности масштабирования алгоритма его вычислений на объёмах данных, во много раз превышающих размеры вашего текущего или тестового датасета — в следующем посте. via @ppc_bigbrain
Уже доступно! Исследование Telegram 2025 — ключевые инсайты года 
