5 методов добавления столбцов по условиям в pandas: руководство

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Аналитики данных и специалисты по работе с данными
  • Студенты и обучающиеся в области анализа данных и программирования на Python
  • Профессионалы, заинтересованные в оптимизации своих навыков написания кода и работы с большими наборами данных

    Добавление столбцов по условиям в pandas — это не просто техническая рутина, а инструмент, который может радикально изменить эффективность вашего анализа данных. Представьте: вы работаете с датасетом из миллиона строк, и одно неоптимальное решение превращает обработку из секундной операции в пятиминутную пытку вашего процессора. Правильный метод добавления условных столбцов может стать тем ключом, который откроет дверь к по-настоящему быстрому и элегантному коду 🚀. Сегодня разберем пять проверенных способов и выясним, какой из них достоин занять место в вашем арсенале.

Хотите не просто копировать решения, а понимать, как эффективно работать с данными? На курсе Профессия аналитик данных от Skypro вы не только освоите pandas на глубинном уровне, но и научитесь оптимизировать код для работы с большими датасетами. Наши студенты не просто пишут код — они создают элегантные решения, которые работают в 5-10 раз быстрее стандартных подходов. Присоединяйтесь и станьте аналитиком нового уровня!

Зачем добавлять столбцы в pandas по условиям

Условное добавление столбцов в pandas — это не просто одна из многих функций библиотеки, а критически важный инструмент в арсенале каждого аналитика данных. Этот метод позволяет трансформировать данные на основе определенных условий, создавая новые признаки без изменения исходной информации.

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

Андрей Петров, Lead Data Scientist Однажды я работал над проектом прогнозирования оттока клиентов для телекоммуникационной компании. У нас был массивный датасет с историей использования услуг, но не хватало критически важного признака — динамики использования за последний квартал.

Вместо того чтобы запрашивать новые данные, я добавил столбец с условием: если использование в последний месяц было ниже среднего за предыдущие два, столбец помечался как "снижение". Это простое изменение повысило точность нашей модели с 76% до 89%.

Что меня поразило: решение, потребовавшее всего 3 строки кода, дало больший эффект, чем неделя тюнинга параметров модели. С тех пор условное добавление столбцов стало моим первым шагом при подготовке данных.

Основные причины использовать условное добавление столбцов:

  • Сегментация данных — разделение наблюдений на категории для последующего анализа
  • Инженерия признаков — создание новых переменных для повышения эффективности моделей машинного обучения
  • Обработка аномалий — выявление и маркировка выбросов в данных
  • Бизнес-логика — внедрение специфических бизнес-правил в анализ данных
  • Агрегация информации — комбинирование нескольких столбцов в один информативный показатель

Давайте создадим пример датафрейма, с которым будем работать в течение всей статьи:

Python
Скопировать код
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() — это мощная функция, которая работает подобно условному оператору: если условие выполнено, возвращается одно значение, если нет — другое. Её главное преимущество — векторизованная реализация, которая позволяет обрабатывать целые массивы данных без явных циклов.

Базовый синтаксис:

Python
Скопировать код
df['new_column'] = np.where(condition, value_if_true, value_if_false)

Давайте применим этот метод для создания столбца, который классифицирует клиентов по доходу:

Python
Скопировать код
# Простая классификация по доходу
df['income_level'] = np.where(df['income'] > 60000, 'High', 'Low')

Но настоящая сила np.where() раскрывается при работе с множественными условиями. Для этого можно использовать вложенные вызовы:

Python
Скопировать код
# Более сложная классификация с множественными условиями
df['income_category'] = np.where(df['income'] < 40000, 'Low',
np.where((df['income'] >= 40000) & (df['income'] < 70000), 'Medium', 'High'))

Также можно комбинировать несколько условий с помощью логических операторов:

Python
Скопировать код
# Комбинирование условий по возрасту и доходу
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().

Основной синтаксис выглядит следующим образом:

Python
Скопировать код
# Создаём столбец с начальным значением
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[] для сложных условий с множественной логикой — это инвестиция в будущую поддержку кода.

Давайте рассмотрим более сложный пример, где нужно учесть несколько параметров:

Python
Скопировать код
# Сначала создаем новый столбец с дефолтным значением
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 для условного обновления значений в уже существующих столбцах или для выполнения математических операций:

Python
Скопировать код
# Создание столбца с базовым бонусом
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[].

Основной синтаксис этого метода:

Python
Скопировать код
df['new_column'] = df.apply(lambda row: some_function_with_conditions(row), axis=1)

Параметр axis=1 указывает, что функция должна применяться к каждой строке, а не к каждому столбцу. Внутри лямбда-функции можно реализовать практически любую логику, включая условные операторы, вычисления и даже вызовы других функций.

Давайте рассмотрим пример с более сложной логикой классификации клиентов:

Python
Скопировать код
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)

Для более простых случаев можно использовать лямбда-функции напрямую:

Python
Скопировать код
# Создание столбца с налоговой категорией на основе нескольких факторов
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
)

Этот метод также позволяет выполнять более сложные вычисления:

Python
Скопировать код
# Расчет персонализированного кредитного лимита
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() стоит использовать, когда гибкость и читаемость кода имеют приоритет над производительностью, и особенно когда логика слишком сложна для реализации другими методами. Это отличный выбор для прототипирования и работы с небольшими и средними наборами данных. 🔧

Сравнение скорости и эффективности методов добавления столбцов

Теперь, когда мы рассмотрели три основных подхода к добавлению столбцов по условиям, пришло время провести объективное сравнение их производительности и удобства использования. Для этого я провёл несколько тестов на датасетах разного размера и с разными типами условий.

Для начала создадим функции, реализующие одинаковую логику разными методами:

Python
Скопировать код
# Метод 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

Теперь проведем измерения времени выполнения для каждого метода на датасетах разного размера:

Python
Скопировать код
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[] становится существенной — выбирайте первый, если позволяет логика.

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

  1. Использование np.select() — удобно, когда нужно обработать множество условий без их вложенности:
Python
Скопировать код
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')

  1. Метод mask() — альтернатива np.where(), более интуитивная для некоторых задач:
Python
Скопировать код
df['high_income'] = df['income'].mask(df['income'] > 70000, 'Yes').mask(df['income'] <= 70000, 'No')

Выбор метода должен основываться на конкретной задаче, размере данных и требованиях к читаемости кода. В идеале, стоит начинать с самого эффективного метода (numpy.where()), и только при необходимости переходить к менее производительным, но более гибким подходам. 📊

Оптимальный выбор метода добавления столбцов в pandas — это баланс между производительностью и читаемостью кода. Если вы работаете с большими данными, отдавайте предпочтение векторизованным решениям вроде np.where(), способным обрабатывать миллионы строк за миллисекунды. Для сложной логики с множеством условий используйте loc[], который обеспечивает хороший компромисс между скоростью и поддерживаемостью кода. И помните: преждевременная оптимизация может сэкономить секунды выполнения, но стоить часов разработки — выбирайте инструмент, соответствующий масштабу вашей задачи.

Читайте также

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Какой метод в pandas используется для добавления нового столбца на основе одного условия?
1 / 5

Загрузка...