5 мощных способов создания столбцов в Pandas для аналитиков
Для кого эта статья:
- Аналитики данных и специалисты по обработке данных
- Студенты и начинающие программисты, изучающие Python и Pandas
Профессионалы, работающие с большими массивами данных и стремящиеся оптимизировать свои навыки в программировании
Работа с данными часто требует трансформации исходных таблиц, и создание новых столбцов — одна из самых распространённых операций при анализе данных с Pandas. Неоптимальный подход может превратить простую задачу в многочасовое мучение, особенно когда речь идёт о больших датасетах. 📊 Правильно выбранный метод не только сэкономит ваше время, но и существенно повысит производительность кода. Разберём 5 самых мощных способов создания новых столбцов в Pandas, которые должен знать каждый аналитик данных.
Изучая Обучение Python-разработке от Skypro, вы не только освоите базовые принципы программирования, но и погрузитесь в мир обработки данных с Pandas. Наши студенты быстро переходят от теории к практике, решая реальные задачи по трансформации данных уже с первых месяцев обучения. Присоединяйтесь, если хотите не просто писать код, а создавать решения, которые действительно работают с данными любой сложности.
Создание нового столбца в Pandas: основные концепции
Прежде чем погрузиться в конкретные методы, давайте разберемся с фундаментальными принципами создания столбцов в Pandas. Библиотека Pandas является мощным инструментом для манипуляции данными в Python, и создание новых столбцов на основе существующих — одна из ключевых операций в арсенале любого аналитика.
Создание нового столбца можно рассматривать как функцию трансформации, где входные данные — это значения из существующих столбцов, а выходные — новая колонка в DataFrame. В Pandas эта операция может выполняться несколькими способами, каждый из которых имеет свои преимущества в зависимости от конкретной ситуации.
Алексей Петров, Senior Data Scientist
Однажды мне пришлось обрабатывать датасет с миллионами строк информации о клиентских транзакциях. Задача стояла вычислить специальный коэффициент лояльности на основе частоты покупок и среднего чека. Изначально я использовал циклы Python для перебора строк — это заняло почти 40 минут на выполнение. Когда я переписал код с использованием векторизованных операций Pandas, то же самое вычисление заняло 12 секунд! Именно в тот момент я понял, насколько критично выбирать правильный метод создания столбцов при работе с большими данными.
Основные концепции, которые следует понимать:
- Векторизация — принцип выполнения операций над целыми массивами данных вместо итерации по отдельным элементам
- Broadcasting — автоматическое расширение массивов меньших размерностей для соответствия большим при выполнении операций
- Индексирование — обращение к элементам DataFrame с помощью меток и условных выражений
- Функциональное преобразование — применение функций к данным для получения новых значений
При выборе метода создания нового столбца важно учитывать следующие факторы:
| Фактор | Влияние на выбор метода |
|---|---|
| Размер данных | Для больших датасетов предпочтительны векторизованные операции |
| Сложность трансформации | Для простых операций подходит прямое присваивание, для сложных — apply() или numpy |
| Тип данных | Числовые данные лучше обрабатываются векторизованными методами |
| Требуемая производительность | Критичные к скорости операции требуют оптимизированных подходов |
Теперь, когда мы понимаем фундаментальные концепции, давайте перейдем к конкретным методам и их практическому применению. 💡

Метод прямого присваивания для добавления столбца в DataFrame
Самый интуитивно понятный и часто используемый метод создания нового столбца в Pandas — прямое присваивание. Этот подход настолько естественен, что многие начинают использовать его даже без предварительного изучения документации.
Синтаксис прямого присваивания предельно прост:
df['новый_столбец'] = значение_или_выражение
Где "значениеиливыражение" может быть:
- Константой (одинаковое значение для всех строк)
- Списком или массивом (должен совпадать по длине с DataFrame)
- Результатом операции над существующими столбцами
Рассмотрим несколько примеров прямого присваивания:
import pandas as pd
# Создаём тестовый DataFrame
data = {
'имя': ['Анна', 'Иван', 'Мария', 'Алексей', 'Екатерина'],
'возраст': [25, 30, 22, 35, 27],
'зарплата': [60000, 85000, 55000, 100000, 75000]
}
df = pd.DataFrame(data)
# 1. Добавление столбца с константой
df['премия_фиксированная'] = 5000
# 2. Добавление столбца на основе другого столбца
df['зарплата_со_стажем'] = df['зарплата'] * 1.1
# 3. Добавление столбца на основе нескольких столбцов
df['возраст_коэффициент'] = df['возраст'] * df['зарплата'] / 1000
# 4. Добавление столбца через списочное выражение (list comprehension)
df['категория'] = ['A' if x > 30 else 'B' for x in df['возраст']]
Преимущества метода прямого присваивания:
- Простота и читабельность кода
- Высокая скорость выполнения для простых операций
- Отлично подходит для большинства базовых преобразований
- Автоматическая векторизация для многих операций
Ограничения метода:
- Сложно реализовать комплексные условные логики
- Не всегда подходит для сложных математических функций
- Может быть неэффективным при цепочке операций
Михаил Соколов, Lead Data Analyst
В начале моей карьеры я работал над проектом по анализу эффективности маркетинговых кампаний. Клиентский датасет содержал данные о расходах на рекламу и полученной прибыли. Мне нужно было вычислить ROI для каждой кампании. Сначала я использовал циклы Python, что занимало неоправданно много времени. После консультации с опытным коллегой я переписал всё на прямое присваивание:
df['ROI'] = (df['profit'] – df['cost']) / df['cost'] * 100. Это не только ускорило код в десятки раз, но и сделало его гораздо понятнее. Тогда я усвоил важный урок: в Pandas всегда стоит начинать с самых простых решений, прежде чем переходить к сложным методам.
Важно замечание: при использовании прямого присваивания с арифметическими операциями Pandas автоматически обрабатывает пропущенные значения (NaN). Любая операция с NaN даст результат NaN, что может быть желаемым поведением или требовать дополнительной обработки.
Метод прямого присваивания особенно полезен, когда вы работаете с числовыми данными и выполняете базовые математические операции. Он является предпочтительным для большинства простых преобразований благодаря своей эффективности и читаемости. 🚀
Применение метода apply() и lambda-функций в Pandas
Когда прямое присваивание оказывается недостаточно гибким для создания новых столбцов, на помощь приходит мощный дуэт: метод apply() и lambda-функции. Эта комбинация позволяет применять произвольную логику к каждой строке или столбцу DataFrame, открывая практически безграничные возможности для трансформации данных.
Метод apply() принимает функцию в качестве аргумента и применяет ее к каждому элементу указанной оси (строке или столбцу). Синтаксис выглядит следующим образом:
# Применение к строкам (axis=1)
df['новый_столбец'] = df.apply(функция, axis=1)
# Применение к столбцу (axis=0 по умолчанию)
df['новый_столбец'] = df['существующий_столбец'].apply(функция)
Lambda-функции в Python — это анонимные (однострочные) функции, которые особенно удобны для использования с apply(). Они позволяют определить логику преобразования "на месте", без создания отдельной функции:
df['новый_столбец'] = df.apply(lambda row: row['столбец1'] + row['столбец2'] if условие else другое_значение, axis=1)
Рассмотрим практические примеры использования apply() и lambda-функций:
import pandas as pd
# Создаём тестовый DataFrame
data = {
'имя': ['Анна', 'Иван', 'Мария', 'Алексей', 'Екатерина'],
'возраст': [25, 30, 22, 35, 27],
'город': ['Москва', 'Санкт-Петербург', 'Москва', 'Екатеринбург', 'Москва'],
'стаж': [3, 7, 1, 10, 4]
}
df = pd.DataFrame(data)
# 1. Простая трансформация с использованием lambda-функции
df['опыт_категория'] = df['стаж'].apply(lambda x: 'Опытный' if x > 5 else 'Начинающий')
# 2. Сложная логика с использованием нескольких столбцов
df['статус'] = df.apply(lambda row:
'VIP' if row['стаж'] > 5 and row['город'] == 'Москва'
else 'Стандарт' if row['стаж'] > 3
else 'Новичок',
axis=1)
# 3. Использование внешней функции вместо lambda
def рассчитать_коэффициент(row):
base = row['стаж'] * 0.1
if row['город'] == 'Москва':
return base + 0.2
elif row['город'] == 'Санкт-Петербург':
return base + 0.15
else:
return base
df['коэффициент'] = df.apply(рассчитать_коэффициент, axis=1)
# 4. Применение строковых преобразований
df['имя_город'] = df.apply(lambda row: f"{row['имя']} из {row['город']}", axis=1)
| Сценарий использования | Прямое присваивание | apply() с lambda |
|---|---|---|
| Простые арифметические операции | ✓ Предпочтительно | Возможно, но избыточно |
| Условная логика | Ограниченно (только с numpy) | ✓ Предпочтительно |
| Строковые манипуляции | Базовые операции | ✓ Предпочтительно для сложных |
| Использование внешних функций | Ограниченно | ✓ Предпочтительно |
| Производительность (большие датасеты) | ✓ Высокая | Средняя или низкая |
Преимущества apply() с lambda-функциями:
- Высокая гибкость и возможность реализации любой логики
- Доступ ко всем столбцам DataFrame при использовании axis=1
- Возможность использования сложных условных конструкций
- Читабельный код для сложных преобразований
Ограничения метода:
- Более низкая производительность по сравнению с векторизованными операциями
- Потенциальные проблемы при работе с большими датасетами
- Не всегда очевидный синтаксис для начинающих
Метод apply() с lambda-функциями особенно полезен, когда вам нужно создать новый столбец на основе нетривиальной логики, которая сложно реализуется векторизованными операциями. Однако следует помнить о компромиссе между гибкостью и производительностью — для больших датасетов лучше использовать более эффективные методы, если это возможно. 🔄
Векторизованные операции для эффективного создания столбцов
Векторизация — это парадигма, позволяющая выполнять операции над целыми массивами данных вместо поэлементной обработки. В контексте Pandas это означает использование оптимизированных методов, которые работают напрямую с внутренними структурами данных (обычно на основе NumPy), обеспечивая существенное повышение производительности.
Векторизованные операции особенно важны при работе с большими датасетами, где даже небольшое улучшение производительности может сократить время выполнения с часов до секунд. Фактически, большинство операций прямого присваивания в Pandas являются векторизованными, но существуют и более специализированные методы.
Рассмотрим основные векторизованные подходы для создания новых столбцов:
import pandas as pd
import numpy as np
# Создаём тестовый DataFrame
data = {
'продажи_2021': [100, 150, 200, 300, 250],
'продажи_2022': [120, 180, 190, 310, 280],
'регион': ['Север', 'Юг', 'Запад', 'Восток', 'Центр'],
'рейтинг': [4\.5, 3.8, 4.2, 4.7, 3.9]
}
df = pd.DataFrame(data)
# 1. Арифметические операции (встроенная векторизация)
df['рост_продаж'] = df['продажи_2022'] – df['продажи_2021']
df['процент_роста'] = (df['продажи_2022'] / df['продажи_2021'] – 1) * 100
# 2. Использование NumPy универсальных функций (ufuncs)
df['лог_продаж'] = np.log10(df['продажи_2022'])
df['нормализованный_рейтинг'] = (df['рейтинг'] – df['рейтинг'].min()) / (df['рейтинг'].max() – df['рейтинг'].min())
# 3. Использование методов строк (str accessor)
df['регион_верхний'] = df['регион'].str.upper()
df['первая_буква'] = df['регион'].str[0]
df['длина_названия'] = df['регион'].str.len()
# 4. Векторизованные вычисления с помощью NumPy
df['комбинированный_показатель'] = np.sqrt(df['продажи_2021'] * df['продажи_2022']) * (df['рейтинг'] / 5)
Одним из самых мощных векторизованных инструментов является метод pandas.Series.str, который позволяет применять строковые операции к целым столбцам сразу:
# Дополнительные примеры использования str accessor
df['содержит_е'] = df['регион'].str.contains('е')
df['регион_форматированный'] = df['регион'].str.pad(10, fillchar='-')
df['регион_код'] = df['регион'].str.slice(0, 3) + '-' + df['рейтинг'].astype(str).str.replace('.', '')
Преимущества векторизованных операций:
- Значительно более высокая производительность по сравнению с apply() и циклами
- Лаконичный и читабельный код для многих типовых операций
- Встроенная обработка отсутствующих значений (NaN)
- Оптимальное использование памяти и вычислительных ресурсов
Специализированные векторизованные методы для различных типов данных:
- Для числовых данных: стандартные арифметические операции, методы .round(), .clip(), статистические функции
- Для строковых данных: Series.str.* методы (.lower(), .upper(), .replace(), .extract() и т.д.)
- Для данных даты/времени: Series.dt.* методы (.year, .month, .day, .dayofweek и т.д.)
- Для категориальных данных: Series.cat.* методы (.codes, .categories, .removeunusedcategories() и т.д.)
Важно помнить, что даже когда требуется сложная логика, часто можно найти способ выразить её через векторизованные операции вместо использования apply(). Например, вместо:
df['категория'] = df['значение'].apply(lambda x: 'Высокий' if x > 100 else 'Средний' if x > 50 else 'Низкий')
Можно использовать векторизованный подход:
conditions = [
(df['значение'] > 100),
(df['значение'] > 50) & (df['значение'] <= 100),
(df['значение'] <= 50)
]
choices = ['Высокий', 'Средний', 'Низкий']
df['категория'] = np.select(conditions, choices, default='Неизвестно')
Такой подход может быть в десятки или даже сотни раз быстрее для больших датасетов. 🚀 Всегда стремитесь использовать векторизованные операции вместо циклов и apply(), когда это возможно.
Условное добавление данных с методами where() и np.select()
При создании новых столбцов часто возникает необходимость применять различную логику в зависимости от условий. Вместо использования apply() с lambda-функциями, которые могут работать медленно на больших наборах данных, Pandas предлагает векторизованные методы для условного добавления данных: pandas.Series.where() и numpy.select().
Метод where() работает по принципу: "Сохранить значение, если условие выполнено, иначе заменить другим значением". Базовый синтаксис выглядит так:
df['новый_столбец'] = df['столбец'].where(условие, другое_значение)
Более гибкий метод np.select() позволяет определить несколько условий и соответствующих им значений:
conditions = [условие1, условие2, условие3, ...]
choices = [значение1, значение2, значение3, ...]
df['новый_столбец'] = np.select(conditions, choices, default=значение_по_умолчанию)
Рассмотрим практические примеры использования этих методов:
import pandas as pd
import numpy as np
# Создаём тестовый DataFrame
data = {
'товар': ['Ноутбук', 'Смартфон', 'Планшет', 'Монитор', 'Клавиатура'],
'цена': [65000, 45000, 35000, 25000, 5000],
'рейтинг': [4\.7, 4.5, 4.2, 4.8, 4.0],
'в_наличии': [15, 25, 10, 5, 30]
}
df = pd.DataFrame(data)
# 1. Простое условное присваивание с методом where()
df['категория_цены'] = df['цена'].where(df['цена'] > 30000, 'Бюджетный')
df.loc[df['цена'] > 30000, 'категория_цены'] = 'Премиум'
# 2. Многоуровневое условие с np.select()
price_conditions = [
(df['цена'] > 50000),
(df['цена'] > 30000) & (df['цена'] <= 50000),
(df['цена'] > 10000) & (df['цена'] <= 30000),
(df['цена'] <= 10000)
]
price_categories = ['Премиум', 'Высокий', 'Средний', 'Бюджетный']
df['ценовая_категория'] = np.select(price_conditions, price_categories)
# 3. Комбинирование нескольких условий из разных столбцов
conditions = [
(df['цена'] > 40000) & (df['рейтинг'] >= 4.5), # Дорогой и высокий рейтинг
(df['цена'] > 40000) & (df['рейтинг'] < 4.5), # Дорогой, но низкий рейтинг
(df['цена'] <= 40000) & (df['рейтинг'] >= 4.5), # Недорогой и высокий рейтинг
(df['цена'] <= 40000) & (df['рейтинг'] < 4.5) # Недорогой и низкий рейтинг
]
recommendations = ['Рекомендуемый премиум', 'Завышенная цена', 'Выгодная покупка', 'Базовый выбор']
df['рекомендация'] = np.select(conditions, recommendations)
# 4. Создание скидки на основе нескольких условий
discount_conditions = [
(df['в_наличии'] > 20), # Большие запасы
(df['в_наличии'] <= 20) & (df['в_наличии'] > 10), # Средние запасы
(df['в_наличии'] <= 10) & (df['в_наличии'] > 5), # Малые запасы
(df['в_наличии'] <= 5) # Критические запасы
]
discount_rates = [0\.15, 0.10, 0.05, 0.0] # Соответствующие скидки
df['скидка'] = np.select(discount_conditions, discount_rates)
df['цена_со_скидкой'] = df['цена'] * (1 – df['скидка'])
Метод loc[] также часто используется для условного обновления значений:
# Пример использования loc[] для условного обновления
df.loc[df['в_наличии'] <= 5, 'статус'] = 'Заканчивается'
df.loc[df['в_наличии'] > 5, 'статус'] = 'В наличии'
# Цепочка условных обновлений
df.loc[df['цена'] > 50000, 'класс'] = 'A'
df.loc[(df['цена'] > 30000) & (df['цена'] <= 50000), 'класс'] = 'B'
df.loc[(df['цена'] > 10000) & (df['цена'] <= 30000), 'класс'] = 'C'
df.loc[df['цена'] <= 10000, 'класс'] = 'D'
Сравнение методов условного добавления данных:
- pandas.Series.where(): Лучше всего подходит для бинарных условий (да/нет)
- numpy.select(): Идеально для нескольких взаимоисключающих условий
- DataFrame.loc[]: Гибкий метод для обновления существующих данных по условию
Преимущества этих методов:
- Высокая производительность благодаря векторизации
- Читабельный код для сложных условных конструкций
- Возможность комбинирования условий из разных столбцов
- Предсказуемая обработка NaN и краевых случаев
Важно замечание: при использовании loc[] с условными выражениями убедитесь, что вы обрабатываете все возможные случаи, иначе некоторые строки могут остаться без присвоенных значений. С np.select() всегда рекомендуется указывать параметр default для обработки случаев, когда ни одно из условий не выполняется. 🔍
Выбор правильного метода для создания новых столбцов в Pandas может существенно повлиять на производительность и читаемость вашего кода. Прямое присваивание подходит для простых операций, apply() с lambda-функциями даёт гибкость при сложной логике, векторизованные операции обеспечивают максимальную производительность, а методы where() и np.select() идеальны для условного добавления данных. Овладев всеми этими техниками, вы сможете эффективно трансформировать данные под любые аналитические задачи, делая ваши датасеты более информативными и готовыми к дальнейшему анализу.