Home » Функции melt, unmelt и pivot в Pandas — преобразование данных
Функции melt, unmelt и pivot в Pandas — преобразование данных

Функции melt, unmelt и pivot в Pandas — преобразование данных

Если вы работаете с серверными логами, мониторингом или обработкой данных на серверах, то рано или поздно столкнётесь с необходимостью преобразовать данные из одного формата в другой. Логи веб-сервера, метрики системы, данные из баз — всё это часто приходится перекраивать для анализа. Pandas предоставляет мощные инструменты для решения этих задач: melt(), unmelt() и pivot(). Эти функции позволяют легко переводить данные из широкого формата в длинный и обратно, что критически важно для обработки серверных метрик и логов.

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

Как это работает: теория в двух словах

Представьте, что у вас есть CSV с метриками сервера, где каждая строка содержит timestamp, а столбцы — это CPU, RAM, disk I/O. Это “широкий” формат. Иногда нужно преобразовать данные в “длинный” формат, где каждая метрика занимает отдельную строку. Именно для этого и нужны эти функции:

  • melt() — преобразует данные из широкого формата в длинный
  • pivot() — обратная операция, из длинного в широкий
  • unmelt() — алиас для pivot_table(), более интуитивное название

Основная идея: данные одни и те же, но структура меняется в зависимости от задач анализа.

Быстрая настройка и базовые примеры

Установим pandas и создадим тестовые данные, похожие на серверные метрики:

import pandas as pd
import numpy as np

# Создаём тестовые данные (метрики сервера)
data = {
    'timestamp': ['2024-01-01 10:00', '2024-01-01 10:01', '2024-01-01 10:02'],
    'cpu_usage': [45.2, 67.8, 52.1],
    'memory_usage': [78.3, 82.1, 79.9],
    'disk_io': [12.5, 15.2, 11.8]
}

df = pd.DataFrame(data)
print("Исходные данные (широкий формат):")
print(df)

Melt: от широкого к длинному

Функция melt() — это швейцарский нож для преобразования широких данных в длинные. Особенно полезна для временных рядов и метрик:

# Базовое использование melt
melted_df = df.melt(id_vars=['timestamp'], 
                   value_vars=['cpu_usage', 'memory_usage', 'disk_io'],
                   var_name='metric', 
                   value_name='value')

print("Данные после melt (длинный формат):")
print(melted_df)

Параметры функции:

  • id_vars — столбцы, которые остаются неизменными (идентификаторы)
  • value_vars — столбцы для “расплавления”
  • var_name — имя нового столбца с названиями переменных
  • value_name — имя нового столбца со значениями

Pivot: обратно в широкий формат

Теперь вернём данные в широкий формат с помощью pivot():

# Возвращаем в широкий формат
pivoted_df = melted_df.pivot(index='timestamp', 
                           columns='metric', 
                           values='value')

print("Данные после pivot (широкий формат):")
print(pivoted_df)

# Сброс индекса для более привычного вида
pivoted_df = pivoted_df.reset_index()
print("\nПосле reset_index():")
print(pivoted_df)

Практические кейсы: работа с логами и метриками

Рассмотрим реальный пример — обработка логов веб-сервера с несколькими серверами:

# Пример с логами нескольких серверов
server_logs = {
    'date': ['2024-01-01', '2024-01-02', '2024-01-03'],
    'server1_requests': [1200, 1350, 1180],
    'server2_requests': [980, 1100, 1050],
    'server3_requests': [1500, 1420, 1600],
    'server1_errors': [12, 8, 15],
    'server2_errors': [5, 12, 8],
    'server3_errors': [18, 16, 22]
}

logs_df = pd.DataFrame(server_logs)
print("Логи серверов (широкий формат):")
print(logs_df)

# Melt для requests
requests_melted = logs_df.melt(id_vars=['date'],
                              value_vars=['server1_requests', 'server2_requests', 'server3_requests'],
                              var_name='server',
                              value_name='requests')

# Очистка названий серверов
requests_melted['server'] = requests_melted['server'].str.replace('_requests', '')

print("\nЗапросы в длинном формате:")
print(requests_melted)

Продвинутые техники и автоматизация

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

# Функция для автоматической обработки серверных метрик
def process_server_metrics(df, metric_prefix='server'):
    """
    Автоматически обрабатывает метрики серверов
    """
    # Находим все столбцы с метриками
    metric_columns = [col for col in df.columns if col.startswith(metric_prefix)]
    
    # Melt для всех метрик
    melted = df.melt(id_vars=[col for col in df.columns if col not in metric_columns],
                    value_vars=metric_columns,
                    var_name='metric_server',
                    value_name='value')
    
    # Разделяем сервер и тип метрики
    melted[['server', 'metric_type']] = melted['metric_server'].str.split('_', n=1, expand=True)
    melted = melted.drop('metric_server', axis=1)
    
    return melted

# Пример использования
processed_metrics = process_server_metrics(logs_df)
print("Автоматически обработанные метрики:")
print(processed_metrics.head(10))

Сравнение производительности и альтернативы

Метод Скорость Память Гибкость Лучше для
melt() Быстро Средне Высокая Простые преобразования
pivot() Быстро Средне Средняя Уникальные индексы
pivot_table() Медленно Высокое Очень высокая Агрегация данных
stack()/unstack() Средне Низкое Низкая Работа с индексами

Для больших объёмов данных (логи за месяц и более) рекомендую использовать Dask или Polars как альтернативу pandas.

Интеграция с другими пакетами

Эти функции отлично работают в связке с другими инструментами:

# Пример с Matplotlib для визуализации
import matplotlib.pyplot as plt

# Создаём данные для графика
melted_for_plot = df.melt(id_vars=['timestamp'], 
                         value_vars=['cpu_usage', 'memory_usage'],
                         var_name='metric', 
                         value_name='value')

# Построение графика
melted_for_plot['timestamp'] = pd.to_datetime(melted_for_plot['timestamp'])

for metric in melted_for_plot['metric'].unique():
    data = melted_for_plot[melted_for_plot['metric'] == metric]
    plt.plot(data['timestamp'], data['value'], label=metric)

plt.legend()
plt.title('Server Metrics Over Time')
plt.xticks(rotation=45)
plt.tight_layout()
# plt.show()  # Раскомментируйте для показа графика

Скрипты для автоматизации

Создадим готовый скрипт для обработки логов сервера:

#!/usr/bin/env python3
"""
Скрипт для автоматической обработки логов сервера
Использование: python log_processor.py input.csv output.csv
"""

import pandas as pd
import sys
import argparse

def main():
    parser = argparse.ArgumentParser(description='Process server logs')
    parser.add_argument('input', help='Input CSV file')
    parser.add_argument('output', help='Output CSV file')
    parser.add_argument('--format', choices=['wide', 'long'], default='long',
                       help='Output format (default: long)')
    
    args = parser.parse_args()
    
    # Читаем данные
    df = pd.read_csv(args.input)
    
    if args.format == 'long':
        # Преобразуем в длинный формат
        result = df.melt(id_vars=['timestamp'], 
                        var_name='metric', 
                        value_name='value')
    else:
        # Предполагаем, что данные уже в длинном формате
        result = df.pivot(index='timestamp', 
                         columns='metric', 
                         values='value').reset_index()
    
    # Сохраняем результат
    result.to_csv(args.output, index=False)
    print(f"Processed {len(df)} rows, saved to {args.output}")

if __name__ == '__main__':
    main()

Типичные ошибки и как их избежать

Вот самые частые проблемы и их решения:

  • Дублирующие индексы в pivot() — используйте pivot_table() с агрегацией
  • Пропущенные значения — добавьте fill_value=0 в pivot()
  • Неправильные типы данных — проверяйте dtypes перед преобразованием
  • Проблемы с памятью — используйте chunksize для больших файлов
# Пример обработки больших файлов
def process_large_logs(filename, chunksize=10000):
    """Обработка больших логов по частям"""
    chunks = []
    
    for chunk in pd.read_csv(filename, chunksize=chunksize):
        processed_chunk = chunk.melt(id_vars=['timestamp'],
                                   var_name='metric',
                                   value_name='value')
        chunks.append(processed_chunk)
    
    return pd.concat(chunks, ignore_index=True)

Новые возможности в автоматизации

Эти функции открывают множество возможностей для автоматизации:

  • Динамическое создание дашбордов — длинный формат идеален для Plotly/Dash
  • Автоматическая агрегация метрик — легко группировать по времени и серверам
  • Интеграция с системами мониторинга — форматирование для Grafana/Prometheus
  • Автоматизация отчётов — преобразование для Excel/PDF отчётов

Если вы планируете развернуть систему мониторинга на собственном сервере, рекомендую обратить внимание на VPS-решения для небольших проектов или выделенные серверы для high-load систем.

Выводы и рекомендации

Функции melt(), pivot() и pivot_table() — это фундаментальные инструменты для работы с данными. Используйте их когда:

  • melt() — нужно преобразовать широкие данные в длинные для анализа или визуализации
  • pivot() — требуется обратное преобразование с уникальными индексами
  • pivot_table() — необходима агрегация данных при преобразовании

Эти функции особенно полезны для:

  • Обработки логов веб-серверов
  • Анализа метрик системы
  • Подготовки данных для машинного обучения
  • Создания отчётов и дашбордов

Помните о производительности при работе с большими объёмами данных и не забывайте про альтернативы вроде Dask для действительно больших датасетов. Автоматизируйте рутинные задачи с помощью скриптов — это сэкономит массу времени в долгосрочной перспективе.


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

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

Leave a reply

Your email address will not be published. Required fields are marked