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

Почему вам следует прекратить писать циклы в Pandas

Как мыслить в столбик, писать более быстрый код и, наконец, использовать Pandas как профессионал.

Делиться

1f488e7b6c0bde20c9407b8f725e93a6
Создано с помощью Gemini AI

Ладно, признаюсь честно: когда я только начинал использовать Pandas, я постоянно писал циклы вот такого типа:

 for i in range(len(df)): if df.loc[i, "sales"] > 1000: df.loc[i, "tier"] = "high" else: df.loc[i, "tier"] = "low"

Это сработало. И я подумал: «Ну, это же здорово, правда?»
Оказалось… не совсем так.

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

Как только я начал мыслить в столбчатом формате , всё изменилось. Код стал короче. Выполнение ускорилось. И внезапно я почувствовал, что Pandas создан именно для того, чтобы помогать мне, а не замедлять меня.

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

 import pandas as pd df = pd.DataFrame({ "product": ["A", "B", "C", "D", "E"], "sales": [500, 1200, 800, 2000, 300] })

Выход:

 product sales 0 A 500 1 B 1200 2 C 800 3 D 2000 4 E 300

Наша цель проста: пометить каждую строку как high , если объем продаж превышает 1000, и как low в противном случае.

Позвольте мне показать вам, как я это делал вначале, и почему есть лучший способ.

Метод циклов, с которого я начал

Вот цикл, который я использовал, когда учился:

 for i in range(len(df)): if df.loc[i, "sales"] > 1000: df.loc[i, "tier"] = "high" else: df.loc[i, "tier"] = "low" print(df)

В результате получается следующее:

 product sales tier 0 A 500 low 1 B 1200 high 2 C 800 low 3 D 2000 high 4 E 300 low

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

Такой подход не масштабируется — то, что работает нормально при 5 строках, замедляется при 50 000 строках.

Что еще более важно, это заставляет вас мыслить как новичок — строка за строкой — а не как профессиональный пользователь Pandas.

Замеры времени зацикливания (момент, когда я понял, что оно медленное)

Когда я впервые запустил свой цикл на этом крошечном наборе данных, я подумал: «Ничего страшного, он достаточно быстрый». Но потом я задумался… а что, если бы у меня был набор данных большего размера?

Поэтому я попробовал:

 import pandas as pd import time # Make a bigger dataset df_big = pd.DataFrame({ "product": ["A", "B", "C", "D", "E"] * 100_000, "sales": [500, 1200, 800, 2000, 300] * 100_000 }) # Time the loop start = time.time() for i in range(len(df_big)): if df_big.loc[i, "sales"] > 1000: df_big.loc[i, "tier"] = "high" else: df_big.loc[i, "tier"] = "low" end = time.time() print("Loop time:", end - start)

Вот что у меня получилось:

 Loop time: 129.27328729629517

Это 129 секунд .

Более двух минут уходит только на то, чтобы пометить строки как "high" или "low" .

В тот момент до меня дошло. Код был не просто «немного неэффективным». Он принципиально неправильно использовал Pandas.
А теперь представьте, что это работает внутри конвейера обработки данных, при обновлении панели мониторинга, обрабатывая миллионы строк каждый день.

Почему так медленно?

Цикл заставляет Pandas:

  • Получите доступ к каждой строке по отдельности.
  • Выполнять логику на уровне Python для каждой итерации
  • Обновляйте DataFrame по одной ячейке за раз.

Иными словами, это превращает высокооптимизированный столбцовый механизм в усовершенствованный обработчик списков на Python.

А библиотека Pandas создана не для этого.

Решение в одну строчку (и момент, когда всё стало ясно)

После просмотра 129 секунд я понял, что должен быть способ получше.
Поэтому вместо перебора строк я попробовал выразить правило на уровне столбцов :

«Если объем продаж превышает 1000, указывайте высокую маркировку. В противном случае — низкую».

Вот и всё. Таково правило.

Вот векторизованная версия:

 import numpy as np import time start = time.time() df_big["tier"] = np.where(df_big["sales"] > 1000, "high", "low") end = time.time() print("Vectorized time:", end - start)

И каков результат?

 Vectorized time: 0.08

Дайте этому осмыслиться.

Зацикленная версия: 129 секунд
Векторизованная версия: 0,08 секунды

Это более чем в 1600 раз быстрее .

Что только что произошло?

Ключевое различие заключается в следующем:

Цикл обрабатывал DataFrame построчно . Векторизованная версия обрабатывала весь столбец sales за одну оптимизированную операцию .

Когда вы пишете:

 df_big["sales"] > 1000

В Python библиотека Pandas не проверяет значения по одному. Сравнение выполняется на более низком уровне (с помощью NumPy), в скомпилированном коде, по всему массиву.

Затем np.where() применяет метки за один эффективный проход.

Вот незаметное, но существенное изменение:

Вместо того чтобы спрашивать:

«Что мне делать с этим спором?»

Вы спрашиваете:

«Какое правило применяется к этой колонке?»

Вот где проходит грань между начинающими и профессиональными пандами.

В этот момент я подумал, что «перешёл на новый уровень». Но потом обнаружил, что могу сделать это ещё проще.

А потом я открыл для себя булево индексирование.

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

Для этого мне даже не нужен np.where() .

Вернемся к нашему небольшому набору данных:

 df = pd.DataFrame({ "product": ["A", "B", "C", "D", "E"], "sales": [500, 1200, 800, 2000, 300] })

Наша цель остается прежней:

Если объем продаж превышает 1000, пометьте каждую строку high , в противном случае — low .

С помощью np.where() мы написали:

 df["tier"] = np.where(df["sales"] > 1000, "high", "low")

Это чище и быстрее. Гораздо лучше, чем зацикливание.

Но вот что действительно изменило мое представление о Pandas:
Вот эта строчка…

 df["sales"] > 1000

…уже возвращает нечто невероятно полезное.

Давайте посмотрим:

Выход:

 0 False 1 True 2 False 3 True 4 False Name: sales, dtype: bool

Это логический ряд.

Pandas оценила состояние всего столбца сразу.

Нет циклов. Нет условий if . Нет построчной логики.

Программа сгенерировала полную маску значений True/False за один раз.

Булево индексирование ощущается как сверхспособность.

А вот тут начинается самое интересное.

Вы можете использовать эту логическую маску напрямую для фильтрации строк:

 df[df["sales"] > 1000]

И Pandas мгновенно предоставляет вам:

ed537802fdc9679c8bd7a619f6e20a57

Мы даже можем построить столбец tier , используя непосредственно булеву индексацию:

 df["tier"] = "low" df.loc[df["sales"] > 1000, "tier"] = "high"

По сути, я говорю:

  • Предположим, что все показатели "low" .
  • Изменять значения следует только в тех строках, где объем продаж превышает 1000.

Вот и все.

И вдруг я перестаю думать:

«Для каждой строки проверьте значение…»

Я думаю:

«Начните с значения по умолчанию. Затем примените правило к подмножеству».

Этот сдвиг едва заметен, но он меняет всё.

Освоившись с булевыми масками, я начал задумываться:

Что произойдет, если логика не будет такой простой, как «больше 1000»? Что, если мне понадобятся пользовательские правила?

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

Разве apply() недостаточно хорош?

Честно говоря, после того, как я перестал писать циклы, я думал, что во всем разобрался. Потому что существовала одна волшебная функция, которая, казалось, решала все проблемы:
apply() .

Это казалось идеальным компромиссом между запутанными циклами и пугающей векторизацией.

Естественно, я начал писать что-то подобное:

 df["tier"] = df["sales"].apply( lambda x: "high" if x > 1000 else "low" )

А что на первый взгляд?

Выглядит отлично.

  • Нет цикла for
  • Ручная индексация отсутствует
  • Легко читается

Создается впечатление, что это профессиональное решение.

Но вот чего я тогда не понимал:

apply() по-прежнему выполняет код Python для каждой отдельной строки.
Это просто скрывает цикл.

При использовании:

df["sales"].apply(lambda x: ...)

Pandas по-прежнему:

  • Взяв каждое значение
  • Передача его в функцию Python
  • Возвращаем результат
  • Повторяйте это для каждой строки.

Да, это чище, чем цикл for . Но с точки зрения производительности? Это гораздо ближе к циклу, чем к настоящей векторизации.

Это стало для меня своего рода откровением. Я понял, что заменяю видимые циклы невидимыми.

Итак, когда следует использовать apply() ?

  • Если логику можно выразить с помощью векторизованных операций, то следует использовать именно их.
  • Если это можно выразить с помощью булевых масок, сделайте это.
  • Если для этого абсолютно необходима собственная логика на Python, используйте apply() .
    Другими словами:

Сначала векторизуйте. Используйте apply()only в случае крайней необходимости.
Не потому, что apply() плохая функция. А потому что Pandas работает быстрее и чище, когда вы мыслите столбцами, а не построчными функциями.

Заключение

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

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

  • Построчный подход не масштабируется.
  • Скрытые циклы в Python не масштабируются.
  • Правила на уровне столбцов это делают.

Вот где проходит настоящая грань между использованием Pandas на уровне новичка и профессионала.

Итак, вкратце:

Прекратите спрашивать, что делать с каждой строкой. Начните спрашивать, какое правило применяется ко всему столбцу.

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

Ибрагим Салами. Все материалы от Ибрагима Салами.

Источник: towardsdatascience.com

✅ Найденные теги: Pandas, Анализ, Данные, новости, Почему, Программирование, Циклы

ОСТАВЬТЕ СВОЙ КОММЕНТАРИЙ

Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Студенты в аудитории с ноутбуками и тетрадями, занимаются на лекции в университете.
Стильное кольцо на камне с ярким светящимся кругом на фоне.
Зелёный глаз крупным планом, светлые ресницы, светоотражение в зрачке.
Микротомография и анализ структуры с моделированием: съемка, 3D-модели, макро и микро масштаб.
Смартфон с логотипом Nintendo на фоне финансовых графиков.
ideipro logotyp
Генеральный директор HIMSS Хэл Вольф и генеральный директор AdventHealth Дэвид Бэнкс дают старт саммиту руководителей | Новости финансового сектора здравоохранения
Google Stax: проверка моделей и подсказок на соответствие собственным критериям.
Человек в клетке с весами вместо решетки, символизирующими зависимость от веса.
Image Not Found
Стильное кольцо на камне с ярким светящимся кругом на фоне.

«Умное» кольцо Switch Ring для глубокого сна и контроля стресса

Switch Ring — это «умное» кольцо, которое выполняет роль персонального тренера сна и помощника по ежедневному самочувствию. Благодаря технологии SomnoSync™ устройство не просто фиксирует показатели, а активно помогает организму быстрее расслабляться и глубже восстанавливаться ночью. В основе…

Мар 10, 2026
Зелёный глаз крупным планом, светлые ресницы, светоотражение в зрачке.

Ретинальная ретинопатия: обновление для лечения амблиопии

Анестезия сетчатки «ленивого» глаза всего на два дня может восстановить зрение у мышей. SKITTERФОТО ЧЕРЕЗ ВИКИМЕДИЯ ОБЩИЕ При амблиопии (или «ленивом глазе») нарушение зрения в одном глазу в раннем детстве приводит к смещению нейронных связей в зрительной…

Мар 10, 2026
Микротомография и анализ структуры с моделированием: съемка, 3D-модели, макро и микро масштаб.

Добыча газа в Арктике станет безопаснее

Как создаются цифровые двойники коллектора © Валерий Химуля. Ученые предложили комплексный подход к исследованию пластов сложных газовых месторождений в Арктике: они объединили геомеханические методы с цифровой рентгеновской томографией и 3D-моделированием, чтобы точно определить условия разрушения пород вокруг…

Мар 10, 2026
Смартфон с логотипом Nintendo на фоне финансовых графиков.

Компания Nintendo подала в суд на правительство США с требованием возмещения таможенных пошлин.

Вкратце Источник изображений: Omar Marques/SOPA Images/LightRocket / Getty Images В пятницу компания Nintendo подала иск против правительства США по поводу взимания пошлин с предприятий по всему миру. Игровой гигант требует возмещения любых пошлин, уплаченных в связи с…

Мар 10, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых