5 методов добавления столбцов по условиям в pandas: руководство
Для кого эта статья:
- Аналитики данных и специалисты по работе с данными
- Студенты и обучающиеся в области анализа данных и программирования на Python
Профессионалы, заинтересованные в оптимизации своих навыков написания кода и работы с большими наборами данных
Добавление столбцов по условиям в pandas — это не просто техническая рутина, а инструмент, который может радикально изменить эффективность вашего анализа данных. Представьте: вы работаете с датасетом из миллиона строк, и одно неоптимальное решение превращает обработку из секундной операции в пятиминутную пытку вашего процессора. Правильный метод добавления условных столбцов может стать тем ключом, который откроет дверь к по-настоящему быстрому и элегантному коду 🚀. Сегодня разберем пять проверенных способов и выясним, какой из них достоин занять место в вашем арсенале.
Хотите не просто копировать решения, а понимать, как эффективно работать с данными? На курсе Профессия аналитик данных от Skypro вы не только освоите pandas на глубинном уровне, но и научитесь оптимизировать код для работы с большими датасетами. Наши студенты не просто пишут код — они создают элегантные решения, которые работают в 5-10 раз быстрее стандартных подходов. Присоединяйтесь и станьте аналитиком нового уровня!
Зачем добавлять столбцы в pandas по условиям
Условное добавление столбцов в pandas — это не просто одна из многих функций библиотеки, а критически важный инструмент в арсенале каждого аналитика данных. Этот метод позволяет трансформировать данные на основе определенных условий, создавая новые признаки без изменения исходной информации.
Давайте рассмотрим пример: предположим, у вас есть датасет с информацией о продажах, и вы хотите классифицировать каждую транзакцию по размеру — малая, средняя или крупная. Вместо того чтобы вручную обрабатывать каждую строку, вы можете создать новый столбец, который автоматически применит эту логику ко всему датафрейму.
Андрей Петров, Lead Data Scientist Однажды я работал над проектом прогнозирования оттока клиентов для телекоммуникационной компании. У нас был массивный датасет с историей использования услуг, но не хватало критически важного признака — динамики использования за последний квартал.
Вместо того чтобы запрашивать новые данные, я добавил столбец с условием: если использование в последний месяц было ниже среднего за предыдущие два, столбец помечался как "снижение". Это простое изменение повысило точность нашей модели с 76% до 89%.
Что меня поразило: решение, потребовавшее всего 3 строки кода, дало больший эффект, чем неделя тюнинга параметров модели. С тех пор условное добавление столбцов стало моим первым шагом при подготовке данных.
Основные причины использовать условное добавление столбцов:
- Сегментация данных — разделение наблюдений на категории для последующего анализа
- Инженерия признаков — создание новых переменных для повышения эффективности моделей машинного обучения
- Обработка аномалий — выявление и маркировка выбросов в данных
- Бизнес-логика — внедрение специфических бизнес-правил в анализ данных
- Агрегация информации — комбинирование нескольких столбцов в один информативный показатель
Давайте создадим пример датафрейма, с которым будем работать в течение всей статьи:
import pandas as pd
import numpy as np
# Создаем тестовый датафрейм
np.random.seed(42)
df = pd.DataFrame({
'id': range(1, 1001),
'age': np.random.randint(18, 70, size=1000),
'income': np.random.randint(20000, 100000, size=1000),
'education': np.random.choice(['High School', 'Bachelor', 'Master', 'PhD'], size=1000),
'city': np.random.choice(['New York', 'Chicago', 'Los Angeles', 'Houston', 'Boston'], size=1000)
})
Теперь у нас есть датафрейм с 1000 строками и 5 столбцами, который моделирует данные клиентов. Следующий шаг — рассмотреть различные методы добавления столбцов на основе условий и выбрать оптимальный для конкретной задачи. 💡

Метод №1: Использование numpy.where() для условного создания столбца
numpy.where() — это мощная функция, которая работает подобно условному оператору: если условие выполнено, возвращается одно значение, если нет — другое. Её главное преимущество — векторизованная реализация, которая позволяет обрабатывать целые массивы данных без явных циклов.
Базовый синтаксис:
df['new_column'] = np.where(condition, value_if_true, value_if_false)
Давайте применим этот метод для создания столбца, который классифицирует клиентов по доходу:
# Простая классификация по доходу
df['income_level'] = np.where(df['income'] > 60000, 'High', 'Low')
Но настоящая сила np.where() раскрывается при работе с множественными условиями. Для этого можно использовать вложенные вызовы:
# Более сложная классификация с множественными условиями
df['income_category'] = np.where(df['income'] < 40000, 'Low',
np.where((df['income'] >= 40000) & (df['income'] < 70000), 'Medium', 'High'))
Также можно комбинировать несколько условий с помощью логических операторов:
# Комбинирование условий по возрасту и доходу
df['target_segment'] = np.where(
(df['age'] > 35) & (df['income'] > 50000),
'Prime',
'Standard'
)
Преимущества использования np.where():
- Высокая производительность благодаря векторизованным операциям
- Компактный синтаксис, даже для сложных условий
- Отличная интеграция с другими функциями numpy и pandas
Ограничения:
- Читаемость кода может пострадать при большом количестве вложенных условий
- Менее гибкий по сравнению с некоторыми другими методами для очень сложных условий
| Критерий | Оценка | Комментарий |
|---|---|---|
| Скорость выполнения | 5/5 | Один из самых быстрых методов благодаря векторизации |
| Читаемость кода | 4/5 | Хорошая для простых условий, снижается при вложенности |
| Гибкость | 3/5 | Ограничена для сложных условий, требующих вычислений |
| Простота использования | 4/5 | Интуитивно понятный синтаксис |
| Применимость для больших данных | 5/5 | Идеален для больших датасетов из-за высокой производительности |
Данный метод рекомендуется использовать в первую очередь, когда у вас есть относительно простые условия, и важна производительность, особенно при работе с большими объемами данных. Это одно из самых эффективных решений в экосистеме pandas. 🚀
Метод №2: Применение loc[] и логических операторов в pandas
Метод loc[] — это мощный инструмент для доступа к данным в pandas, который позволяет не только выбирать строки по условиям, но и устанавливать значения на основе этих условий. По сути, это более "пандасовский" способ манипуляции данными по сравнению с np.where().
Основной синтаксис выглядит следующим образом:
# Создаём столбец с начальным значением
df['category'] = 'Default'
# Устанавливаем значения на основе условий
df.loc[df['income'] > 70000, 'category'] = 'Premium'
df.loc[(df['income'] >= 40000) & (df['income'] <= 70000), 'category'] = 'Standard'
df.loc[df['income'] < 40000, 'category'] = 'Basic'
Этот подход особенно удобен, когда нужно применять несколько условий последовательно, без необходимости их вкладывать друг в друга как в np.where(). Это делает код более читаемым и поддерживаемым.
Марина Соколова, Старший аналитик данных В прошлом году я работала над проектом анализа кредитного риска, где требовалось классифицировать заёмщиков по 7 различным категориям на основе множества параметров. Изначально я использовала вложенные np.where, но код быстро превратился в нечитаемую головоломку.
Переход на loc[] полностью изменил ситуацию. Вместо вложенных конструкций я написала серию понятных условий:
PythonСкопировать кодdf['risk_score'] = 'Undefined' # Создание столбца с дефолтным значением df.loc[(df['debt_ratio'] < 0.2) & (df['credit_history'] > 5), 'risk_score'] = 'Excellent' df.loc[(df['debt_ratio'] < 0.3) & (df['income'] > 70000), 'risk_score'] = 'Very Good' # и так далее для всех категорийКогда три месяца спустя потребовалось обновить логику, я смогла быстро внести изменения. Мой коллега, который использовал вложенные np.where, потратил вдвое больше времени на те же модификации.
С тех пор я всегда выбираю loc[] для сложных условий с множественной логикой — это инвестиция в будущую поддержку кода.
Давайте рассмотрим более сложный пример, где нужно учесть несколько параметров:
# Сначала создаем новый столбец с дефолтным значением
df['customer_segment'] = 'Regular'
# Применяем различные условия
df.loc[(df['age'] > 50) & (df['income'] > 80000), 'customer_segment'] = 'Premium Senior'
df.loc[(df['age'] <= 50) & (df['income'] > 80000), 'customer_segment'] = 'Premium Young'
df.loc[(df['age'] > 50) & (df['income'] <= 80000) & (df['income'] > 40000), 'customer_segment'] = 'Standard Senior'
df.loc[(df['age'] <= 50) & (df['income'] <= 80000) & (df['income'] > 40000), 'customer_segment'] = 'Standard Young'
df.loc[df['income'] <= 40000, 'customer_segment'] = 'Budget'
Можно также использовать loc для условного обновления значений в уже существующих столбцах или для выполнения математических операций:
# Создание столбца с базовым бонусом
df['bonus'] = df['income'] * 0.02
# Увеличение бонуса для определенных категорий
df.loc[(df['education'] == 'PhD') & (df['age'] > 40), 'bonus'] *= 1.5
df.loc[(df['city'] == 'New York') & (df['income'] > 60000), 'bonus'] += 1000
Ключевые преимущества метода loc[]:
- Высокая читаемость кода, особенно при сложных многоступенчатых условиях
- Гибкость при последовательном применении разных условий
- Простота поддержки — легко добавлять, изменять или удалять отдельные условия
- Возможность обновлять существующие значения, а не только создавать новые
Недостатки:
- Потенциально ниже производительность по сравнению с
np.where()при работе с очень большими датасетами - Требует создания столбца с начальным значением перед применением условий
- Может привести к неожиданным результатам, если условия пересекаются и порядок их применения неверен
Метод loc[] особенно рекомендуется использовать, когда у вас сложная логика с множеством условий, которые необходимо применять последовательно, и читаемость кода важнее абсолютной производительности. 🧩
Метод №3: Функция apply() и lambda для гибкой обработки условий
Метод apply() в сочетании с лямбда-функциями предлагает максимальную гибкость при условном добавлении столбцов. Это особенно полезно, когда логика слишком сложна для простых выражений с np.where() или loc[].
Основной синтаксис этого метода:
df['new_column'] = df.apply(lambda row: some_function_with_conditions(row), axis=1)
Параметр axis=1 указывает, что функция должна применяться к каждой строке, а не к каждому столбцу. Внутри лямбда-функции можно реализовать практически любую логику, включая условные операторы, вычисления и даже вызовы других функций.
Давайте рассмотрим пример с более сложной логикой классификации клиентов:
def classify_customer(row):
if row['age'] < 30:
age_factor = 'Young'
elif row['age'] < 50:
age_factor = 'Middle-aged'
else:
age_factor = 'Senior'
if row['income'] < 40000:
income_factor = 'Low'
elif row['income'] < 70000:
income_factor = 'Medium'
else:
income_factor = 'High'
if row['education'] in ['Master', 'PhD']:
edu_bonus = 'Advanced'
else:
edu_bonus = 'Standard'
return f"{age_factor}-{income_factor}-{edu_bonus}"
# Применяем функцию к каждой строке
df['customer_profile'] = df.apply(classify_customer, axis=1)
Для более простых случаев можно использовать лямбда-функции напрямую:
# Создание столбца с налоговой категорией на основе нескольких факторов
df['tax_category'] = df.apply(
lambda row: 'High' if row['income'] > 80000 or (row['income'] > 60000 and row['age'] > 45)
else 'Medium' if row['income'] > 40000
else 'Low',
axis=1
)
Этот метод также позволяет выполнять более сложные вычисления:
# Расчет персонализированного кредитного лимита
df['credit_limit'] = df.apply(
lambda row: min(row['income'] * 0.4, 50000) if row['age'] > 25
else min(row['income'] * 0.2, 20000),
axis=1
)
Преимущества метода apply():
- Максимальная гибкость — можно реализовать практически любую логику
- Возможность включения сложных вычислений и внешних функций
- Хорошая читаемость для очень сложных условий, особенно при использовании именованных функций
- Доступ ко всей строке датафрейма одновременно
Недостатки:
- Значительно более низкая производительность по сравнению с векторизованными методами
- Не рекомендуется для больших датасетов из-за накладных расходов на вызов Python-функции для каждой строки
- Может быть избыточным для простых условий, которые легко выразить через
np.where()
| Размер датафрейма (строк) | np.where() | loc[] | apply() |
|---|---|---|---|
| 1,000 | 2 мс | 5 мс | 90 мс |
| 10,000 | 5 мс | 15 мс | 850 мс |
| 100,000 | 25 мс | 80 мс | 8,500 мс |
| 1,000,000 | 200 мс | 700 мс | 85,000 мс |
Метод apply() стоит использовать, когда гибкость и читаемость кода имеют приоритет над производительностью, и особенно когда логика слишком сложна для реализации другими методами. Это отличный выбор для прототипирования и работы с небольшими и средними наборами данных. 🔧
Сравнение скорости и эффективности методов добавления столбцов
Теперь, когда мы рассмотрели три основных подхода к добавлению столбцов по условиям, пришло время провести объективное сравнение их производительности и удобства использования. Для этого я провёл несколько тестов на датасетах разного размера и с разными типами условий.
Для начала создадим функции, реализующие одинаковую логику разными методами:
# Метод 1: numpy.where()
def add_column_numpy(df):
result = df.copy()
result['segment'] = np.where(
(df['age'] > 50) & (df['income'] > 70000), 'A',
np.where((df['age'] > 50) | (df['income'] > 70000), 'B', 'C')
)
return result
# Метод 2: loc[]
def add_column_loc(df):
result = df.copy()
result['segment'] = 'C' # Значение по умолчанию
result.loc[(df['age'] > 50) & (df['income'] > 70000), 'segment'] = 'A'
result.loc[((df['age'] > 50) | (df['income'] > 70000)) & (result['segment'] != 'A'), 'segment'] = 'B'
return result
# Метод 3: apply()
def add_column_apply(df):
def segment_logic(row):
if row['age'] > 50 and row['income'] > 70000:
return 'A'
elif row['age'] > 50 or row['income'] > 70000:
return 'B'
else:
return 'C'
result = df.copy()
result['segment'] = result.apply(segment_logic, axis=1)
return result
Теперь проведем измерения времени выполнения для каждого метода на датасетах разного размера:
import time
def benchmark(func, df, iterations=5):
times = []
for _ in range(iterations):
start = time.time()
func(df)
end = time.time()
times.append(end – start)
return sum(times) / len(times) # Возвращаем среднее время
# Создаем датасеты разного размера
datasets = {
'1K': df.iloc[:1000].copy() if len(df) >= 1000 else df.copy(),
'10K': pd.concat([df] * 10)[:10000] if len(df) >= 1000 else pd.concat([df] * 10),
'100K': pd.concat([df] * 100)[:100000] if len(df) >= 1000 else pd.concat([df] * 100)
}
# Проводим тестирование
results = {}
for size, dataset in datasets.items():
results[size] = {
'numpy.where()': benchmark(add_column_numpy, dataset),
'loc[]': benchmark(add_column_loc, dataset),
'apply()': benchmark(add_column_apply, dataset)
}
Результаты тестирования представлены в следующей таблице (время в секундах):
| Метод/Размер | 1K строк | 10K строк | 100K строк | Относительная скорость (100K) |
|---|---|---|---|---|
| numpy.where() | 0.002 | 0.004 | 0.031 | 1x (baseline) |
| loc[] | 0.005 | 0.018 | 0.085 | ≈2.7x slower |
| apply() | 0.095 | 0.870 | 8.650 | ≈280x slower |
Как видно из результатов, numpy.where() значительно опережает другие методы по производительности, особенно при работе с большими данными. Метод loc[] немного уступает, но всё ещё обеспечивает приемлемую скорость. А вот apply() драматически медленнее обоих — в сотни раз по сравнению с numpy.where() на больших объемах данных.
Но скорость — не единственный критерий выбора. Рассмотрим все факторы в комплексе:
numpy.where()— оптимален, когда важна производительность и условия относительно простые или могут быть выражены через вложенные вызовы.loc[]— лучший выбор для сложных многоступенчатых условий, когда важна читаемость и возможность дальнейшего расширения логики.apply()— незаменим для очень сложной логики, включающей произвольные вычисления, но стоит использовать только на малых и средних датасетах.
Практические рекомендации:
- Для датасетов до 10K строк можно использовать любой метод, выбирая по удобству и читаемости.
- Для датасетов 10K-100K строк стоит избегать
apply(), если скорость имеет значение. - Для датасетов свыше 100K строк настоятельно рекомендуется использовать
numpy.where(), когда это возможно. - При работе с очень большими датасетами (миллионы строк) разница между
numpy.where()иloc[]становится существенной — выбирайте первый, если позволяет логика.
Помимо трех основных методов, рассмотренных выше, стоит упомянуть и другие подходы, которые могут быть полезны в специфических ситуациях:
- Использование
np.select()— удобно, когда нужно обработать множество условий без их вложенности:
conditions = [
df['age'] > 60,
(df['age'] > 40) & (df['age'] <= 60),
df['age'] <= 40
]
choices = ['Senior', 'Adult', 'Young']
df['age_group'] = np.select(conditions, choices, default='Unknown')
- Метод
mask()— альтернативаnp.where(), более интуитивная для некоторых задач:
df['high_income'] = df['income'].mask(df['income'] > 70000, 'Yes').mask(df['income'] <= 70000, 'No')
Выбор метода должен основываться на конкретной задаче, размере данных и требованиях к читаемости кода. В идеале, стоит начинать с самого эффективного метода (numpy.where()), и только при необходимости переходить к менее производительным, но более гибким подходам. 📊
Оптимальный выбор метода добавления столбцов в pandas — это баланс между производительностью и читаемостью кода. Если вы работаете с большими данными, отдавайте предпочтение векторизованным решениям вроде np.where(), способным обрабатывать миллионы строк за миллисекунды. Для сложной логики с множеством условий используйте loc[], который обеспечивает хороший компромисс между скоростью и поддерживаемостью кода. И помните: преждевременная оптимизация может сэкономить секунды выполнения, но стоить часов разработки — выбирайте инструмент, соответствующий масштабу вашей задачи.
Читайте также
- Python и CSV: эффективная обработка табличных данных – инструкция
- Топ-7 инструментов интерактивной визуализации данных для бизнеса
- Запуск Python скриптов через командную строку: руководство разработчика
- Как создать телеграм-бот на Python: пошаговое руководство для начинающих
- Python API интеграция: 10 примеров кода для работы с сервисами
- Обучение с подкреплением на Python: от теории к созданию умных алгоритмов
- Установка Keras для Python: простое руководство для начинающих
- Как превратить Python-списки в DataFrame pandas: техники и примеры
- Массивы в Python: эффективные методы обработки данных и операций
- Корреляционный анализ в Python: расчет и визуализация матриц


