5 способов добавить столбцы в Pandas DataFrame: пишем эффективный код

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

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

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

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

Хотите превратить базовые знания Pandas в настоящее преимущество на рынке труда? Курс Профессия аналитик данных от Skypro погружает вас в глубокое понимание манипуляций с данными. Вы изучите не только базовые операции с DataFrame, но и продвинутые техники трансформации данных, которые высоко ценятся работодателями. Наши студенты не просто добавляют столбцы — они мастерски управляют данными для принятия бизнес-решений.

Что такое DataFrame в Pandas и зачем добавлять столбцы

DataFrame — это двумерная структура данных в библиотеке Pandas, напоминающая электронную таблицу или SQL-таблицу. Это основной инструмент анализа данных в Python, позволяющий эффективно хранить и обрабатывать табличные данные.

Добавление столбцов в DataFrame — одна из фундаментальных операций при анализе данных. Эта операция позволяет:

  • Создавать новые признаки на основе существующих данных
  • Включать результаты вычислений в набор данных
  • Интегрировать данные из разных источников
  • Подготавливать данные для визуализации или машинного обучения
  • Добавлять метаданные или служебную информацию

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

Давайте начнем с создания примера DataFrame для наших демонстраций:

Python
Скопировать код
import pandas as pd

# Создаем простой DataFrame
data = {
'Имя': ['Анна', 'Борис', 'Виктория', 'Григорий'],
'Возраст': [25, 32, 28, 41],
'Город': ['Москва', 'Санкт-Петербург', 'Казань', 'Новосибирск']
}

df = pd.DataFrame(data)
print(df)

Результат выполнения этого кода:

Имя Возраст Город
Анна 25 Москва
Борис 32 Санкт-Петербург
Виктория 28 Казань
Григорий 41 Новосибирск

Александр Петров, ведущий аналитик данных

Когда я только начинал работать с Pandas, я не задумывался о разных способах добавления столбцов. Просто использовал прямое присваивание для всех задач. Однажды я анализировал данные о клиентском поведении объемом в несколько миллионов строк. Мне нужно было добавить около 20 вычисляемых столбцов на основе условий и агрегаций.

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

После консультации с коллегой, я переписал код, используя комбинацию методов assign() и apply(), объединяя несколько операций в цепочку. Время выполнения сократилось до 3 минут, а потребление памяти снизилось в 5 раз. Этот опыт научил меня, что выбор правильного метода добавления столбцов — не просто вопрос стиля, а критический фактор производительности при работе с большими данными.

Пошаговый план для смены профессии

Простое добавление столбца через присваивание: df['new'] = data

Самый интуитивно понятный способ добавления столбца в DataFrame — это прямое присваивание с использованием синтаксиса индексации. Это базовый метод, который должен знать каждый, кто работает с Pandas.

Рассмотрим несколько примеров простого присваивания:

Python
Скопировать код
# Добавление столбца с константным значением
df['Статус'] = 'Активный'

# Добавление столбца со списком значений
df['Рейтинг'] = [4\.5, 3.8, 4.9, 4.2]

# Добавление вычисляемого столбца
df['Возраст через 5 лет'] = df['Возраст'] + 5

print(df)

После выполнения этого кода наш DataFrame будет выглядеть так:

Имя Возраст Город Статус Рейтинг Возраст через 5 лет
Анна 25 Москва Активный 4.5 30
Борис 32 Санкт-Петербург Активный 3.8 37
Виктория 28 Казань Активный 4.9 33
Григорий 41 Новосибирск Активный 4.2 46

Преимущества и ограничения прямого присваивания:

Преимущества Ограничения
Интуитивно понятный синтаксис Изменяет исходный DataFrame (не иммутабельно)
Минимум кода для простых операций Может быть неэффективно при частых операциях с большими данными
Работает с любыми типами данных Необходимо следить за соответствием длины списка и DataFrame
Легко комбинировать с векторизованными операциями Нет прямого контроля над позицией добавляемого столбца

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

  • Длина списка значений должна соответствовать количеству строк в DataFrame, иначе возникнет ошибка
  • Прямое присваивание изменяет исходный DataFrame, а не создает новую копию
  • При добавлении столбца с вычисляемыми значениями лучше использовать векторизованные операции вместо циклов для повышения производительности
  • Новый столбец всегда добавляется в конец DataFrame

Типичные ошибки при использовании этого метода 🚫:

Python
Скопировать код
# Ошибка: длина списка не соответствует количеству строк
df['Ошибка'] = [1, 2, 3] # В нашем DataFrame 4 строки

# Правильно:
df['Правильно'] = [1, 2, 3, 4] # Длина списка соответствует количеству строк

Использование метода assign() для создания нового DataFrame

Метод assign() представляет собой более функциональный подход к добавлению столбцов, который соответствует парадигме неизменяемости (immutability). В отличие от прямого присваивания, assign() не изменяет исходный DataFrame, а создает и возвращает новую копию с добавленными столбцами.

Базовый синтаксис метода assign():

Python
Скопировать код
# Создание нового DataFrame с добавленным столбцом
new_df = df.assign(новый_столбец=значения)

Рассмотрим практические примеры:

Python
Скопировать код
# Добавление столбца с константным значением
df_with_status = df.assign(Статус='Активный')

# Добавление столбца со списком значений
df_with_rating = df.assign(Рейтинг=[4\.5, 3.8, 4.9, 4.2])

# Добавление вычисляемого столбца с использованием lambda-функции
df_with_age_in_5_years = df.assign(Возраст_через_5_лет=lambda x: x['Возраст'] + 5)

# Добавление нескольких столбцов одновременно
df_enhanced = df.assign(
Статус='Активный',
Рейтинг=[4\.5, 3.8, 4.9, 4.2],
Возраст_через_5_лет=lambda x: x['Возраст'] + 5
)

print(df_enhanced)

Одним из ключевых преимуществ метода assign() является возможность создания цепочек методов, что делает код более читаемым и функциональным:

Python
Скопировать код
# Цепочка методов с assign()
result_df = (df
.assign(Возраст_в_месяцах=lambda x: x['Возраст'] * 12)
.assign(Категория=lambda x: ['Молодой' if age < 30 else 'Взрослый' for age in x['Возраст']])
.assign(Идентификатор=lambda x: [f"{name[:3]}{age}" for name, age in zip(x['Имя'], x['Возраст'])])
)

print(result_df)

Елена Соколова, руководитель отдела аналитики

В нашем проекте мы анализировали большой набор данных о продажах — более 20 миллионов строк. На каждой итерации анализа требовалось создавать новые признаки, добавляя их к DataFrame. Первоначально команда использовала подход с прямым присваиванием:

Python
Скопировать код
df['revenue'] = df['quantity'] * df['price']
df['discount_amount'] = df['revenue'] * df['discount_rate']
df['final_price'] = df['revenue'] – df['discount_amount']

Проблема возникла, когда мы начали анализировать производительность. При каждом присваивании создавались временные копии данных, что приводило к значительному потреблению памяти.

Мы переписали код с использованием метода assign() в цепочке:

Python
Скопировать код
df = (df
.assign(revenue=lambda x: x['quantity'] * x['price'])
.assign(discount_amount=lambda x: x['revenue'] * x['discount_rate'])
.assign(final_price=lambda x: x['revenue'] – x['discount_amount'])
)

Результат превзошел ожидания: потребление памяти уменьшилось на 40%, а время выполнения сократилось с 3 минут до 75 секунд. Дополнительным бонусом стала улучшенная читаемость и поддерживаемость кода. Теперь assign() стал стандартом в нашей команде для всех операций добавления столбцов.

Сравнение метода assign() с прямым присваиванием:

Характеристика assign() Прямое присваивание
Изменяемость Неизменяемый (создает копию) Изменяемый (модифицирует оригинал)
Цепочки методов Поддерживает Не поддерживает
Синтаксис Более многословный Лаконичный
Производительность Эффективнее для нескольких операций Эффективнее для одиночных операций
Доступ к другим столбцам Через lambda-функции Прямой доступ

Когда следует использовать assign()?

  • Когда вам нужно сохранить исходный DataFrame без изменений
  • При добавлении нескольких столбцов одновременно
  • Когда вы используете функциональный стиль программирования с цепочками методов
  • В случаях, когда вы хотите повысить читаемость кода, особенно в сложных трансформациях
  • При работе с большими данными, где эффективность памяти имеет значение

Применение insert() для добавления столбца в нужную позицию

Метод insert() предоставляет уникальную возможность, отсутствующую в предыдущих подходах — добавление столбца в произвольную позицию DataFrame. Это особенно полезно, когда порядок столбцов имеет значение, например, для удобства анализа или визуализации.

Синтаксис метода insert():

Python
Скопировать код
# Добавление столбца в указанную позицию
df.insert(loc=позиция, column=имя_столбца, value=значения)

Параметры метода:

  • loc — числовой индекс позиции, куда будет вставлен столбец (нумерация начинается с 0)
  • column — имя нового столбца (строка)
  • value — значения для нового столбца (скаляр, список, массив NumPy или Series)
  • allow_duplicates (опционально) — разрешить дублирование имени столбца (по умолчанию False)

Рассмотрим примеры использования метода insert():

Python
Скопировать код
# Создаем копию исходного DataFrame для демонстрации
df_demo = df.copy()

# Добавление столбца 'ID' в начало DataFrame (позиция 0)
df_demo.insert(loc=0, column='ID', value=[101, 102, 103, 104])

# Добавление столбца 'Пол' после столбца 'Имя' (позиция 2)
df_demo.insert(loc=2, column='Пол', value=['Ж', 'М', 'Ж', 'М'])

# Добавление вычисляемого столбца перед столбцом 'Город'
position = df_demo.columns.get_loc('Город') # Получаем индекс столбца 'Город'
df_demo.insert(
loc=position, 
column='Возрастная категория', 
value=['Молодой' if age < 30 else 'Взрослый' for age in df_demo['Возраст']]
)

print(df_demo)

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

plaintext
Скопировать код
ID Имя Пол Возраст Возрастная категория Город
0 101 Анна Ж 25 Молодой Москва
1 102 Борис М 32 Взрослый Санкт-Петербург
2 103 Виктория Ж 28 Молодой Казань
3 104 Григорий М 41 Взрослый Новосибирск

Важные моменты при использовании метода insert():

  • Метод изменяет исходный DataFrame, не создавая копию
  • Если указать loc за пределами существующих индексов, будет вызвана ошибка
  • По умолчанию нельзя вставить столбец с именем, которое уже существует
  • Длина списка значений должна соответствовать количеству строк

Получение индекса существующего столбца для вставки относительно него:

Python
Скопировать код
# Получение индекса столбца
column_index = df.columns.get_loc('Имя')

# Вставка перед указанным столбцом
df.insert(column_index, 'Префикс', ['А', 'Б', 'В', 'Г'])

# Вставка после указанного столбца
df.insert(column_index + 1, 'Суффикс', ['-1', '-2', '-3', '-4'])

Типичные случаи использования insert():

  • Организация столбцов в логические группы для улучшения читаемости данных
  • Сохранение порядка столбцов, соответствующего бизнес-логике
  • Добавление идентификаторов или метаданных в начало DataFrame
  • Вставка вычисляемых столбцов рядом с исходными данными для удобства анализа
  • Подготовка данных для экспорта с определенной структурой столбцов

Преимущества использования insert() по сравнению с другими методами:

  • Точный контроль над позицией столбца в DataFrame
  • Возможность организовать столбцы в логической последовательности
  • Улучшение читаемости данных при выводе или визуализации
  • Удобство при интеграции с системами, требующими определенного порядка полей

Ограничения метода insert() 🚫:

  • Нельзя использовать в цепочке методов, так как функция возвращает None
  • Изменяет исходный DataFrame (не соответствует функциональному стилю)
  • Не оптимален для массового добавления множества столбцов

Продвинутые способы: добавление с условиями и вычислениями

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

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

1. Добавление столбца с использованием np.where() для условного выбора

Функция numpy.where() работает как векторизованный оператор if-else и идеально подходит для создания столбцов на основе условий:

Python
Скопировать код
import numpy as np

# Добавление столбца "Статус" на основе возраста
df['Статус клиента'] = np.where(df['Возраст'] < 30, 'Молодой', 'Опытный')

# Более сложное условие с несколькими вариантами
df['Возрастная группа'] = np.where(
df['Возраст'] < 25, 'До 25',
np.where(df['Возраст'] < 35, '25-35',
np.where(df['Возраст'] < 45, '35-45', 'От 45'))
)

2. Использование метода apply() для применения функций к строкам или столбцам

Метод apply() позволяет применять произвольные функции к данным:

Python
Скопировать код
# Функция для расчета индивидуального коэффициента
def calculate_factor(row):
base = row['Возраст'] / 10
if row['Город'] == 'Москва':
return base * 1.2
elif row['Город'] == 'Санкт-Петербург':
return base * 1.1
else:
return base

# Добавление столбца с использованием apply()
df['Коэффициент'] = df.apply(calculate_factor, axis=1)

3. Метод map() для преобразования значений через словарь или функцию

Метод map() удобен для преобразования значений в столбце через словарь соответствий:

Python
Скопировать код
# Создание словаря для маппинга
city_tier = {
'Москва': 'Премиум',
'Санкт-Петербург': 'Премиум',
'Казань': 'Стандарт',
'Новосибирск': 'Стандарт'
}

# Добавление столбца через map()
df['Категория города'] = df['Город'].map(city_tier)

# Добавление столбца через map() с функцией
df['Длина имени'] = df['Имя'].map(len)

4. Использование метода eval() для векторизованных вычислений

Метод eval() позволяет выполнять сложные выражения без создания промежуточных серий данных:

Python
Скопировать код
# Добавление столбца с использованием eval()
df.eval('Индекс = Возраст * 2.5 – Длина имени', inplace=True)

5. Добавление столбца с использованием pd.cut() для категоризации

Функция pd.cut() помогает разделить непрерывные данные на категории:

Python
Скопировать код
# Добавление столбца с категориями возраста
bins = [0, 25, 35, 50, 100]
labels = ['Молодой', 'Взрослый', 'Средний', 'Старший']
df['Возрастная категория'] = pd.cut(df['Возраст'], bins=bins, labels=labels)

Сравнение продвинутых методов по производительности и читаемости:

Метод Производительность Читаемость Гибкость Когда использовать
np.where() Высокая Средняя Средняя Для простых условных операций
apply() Низкая Высокая Очень высокая Для сложной логики, требующей Python-кода
map() Высокая Высокая Средняя Для преобразований с использованием словарей
eval() Очень высокая Средняя Низкая Для сложных математических выражений
cut() Средняя Высокая Средняя Для категоризации непрерывных данных

Рекомендации по оптимизации производительности при добавлении столбцов 🚀:

  • Избегайте использования apply() для больших наборов данных, если существует векторизованная альтернатива
  • Предпочитайте np.where() вместо циклов или конструкций if-else
  • Используйте метод eval() для сложных математических выражений для экономии памяти
  • Объединяйте несколько операций с помощью assign() для минимизации копирования данных
  • Рассмотрите возможность использования метода query() вместе с assign() для фильтрации и добавления столбцов в одной операции

Пример комплексного добавления столбцов с оптимизацией производительности:

Python
Скопировать код
# Оптимизированный подход для добавления нескольких вычисляемых столбцов
enhanced_df = (df
.assign(Возраст_месяцы=lambda x: x['Возраст'] * 12)
.assign(Возрастная_группа=lambda x: pd.cut(
x['Возраст'], 
bins=[0, 25, 35, 50, 100], 
labels=['Молодой', 'Взрослый', 'Средний', 'Старший']
))
.assign(Город_категория=lambda x: x['Город'].map({
'Москва': 'Премиум', 
'Санкт-Петербург': 'Премиум',
'Казань': 'Стандарт', 
'Новосибирск': 'Стандарт'
}))
.assign(Приоритет=lambda x: np.where(
(x['Возрастная_группа'].isin(['Взрослый', 'Средний'])) & 
(x['Город_категория'] == 'Премиум'), 
'Высокий', 'Стандартный'
))
)

print(enhanced_df)

Добавление столбцов в DataFrame – операция, мастерство в которой отличает начинающего аналитика от профессионала. Выбор метода критически влияет на производительность, читаемость и поддерживаемость кода. Прямое присваивание оптимально для простых задач, assign() незаменим при работе с большими данными и функциональном программировании, insert() необходим для контроля структуры данных, а комбинирование условий и вычислений с помощью векторизованных операций – ключ к эффективной обработке сложных наборов данных. Освоив эти техники, вы сможете писать более эффективный и элегантный код для анализа данных.

Загрузка...