Обработка крупных массивов данных: Pandas и NumPy на практике

Раздел: Data Science -> Pandas и NumPy

Основные подходы к анализу больших данных

Как эффективно обрабатывать данные, не помещающиеся в оперативную память?

Наиболее действенный метод

Для работы с файлами объёмом больше доступной RAM используется чтение по частям (chunking). Pandas поддерживает параметр chunksize в read_csv() и других функциях. Это позволяет обрабатывать данные последовательно, аккумулируя результаты.

import pandas as pd

agg_list = []
for chunk in pd.read_csv('large_file.csv', chunksize=100000):
    # Трансформация и агрегация в каждом чанке
    agg = chunk.groupby('category').agg({'value': 'sum'})
    agg_list.append(agg)

result = pd.concat(agg_list).groupby(level=0).sum()

Python для анализа данных (python для анализа данных)

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

Типичная ошибка: дублирование чтения заголовков или использование index_col не в каждом чанке. Рекомендуется указывать все параметры парсинга один раз и передавать их в pd.read_csv().

Как уменьшить потребление памяти при загрузке данных?

Вариант: применение оптимизированных типов данных

Pandas автоматически определяет типы, но для больших данных лучше задавать их вручную: float32 вместо float64, int32 или int16, категориальный тип для строк с малым количеством уникальных значений.

dtypes = {
    'id': 'int32',
    'value': 'float32',
    'status': 'category'
}
df = pd.read_csv('large_file.csv', dtype=dtypes)

анализ больших данных python (анализ больших данных в python)

Экономия памяти может составить 50-70%.

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

Что делать, если данные загружены, но операции работают медленно?

Вариант: векторизация с NumPy и избегание apply

Встроенные функции Pandas векторизованы, но df.apply() с Python‑функциями вызывает цикл. NumPy предоставляет ещё более быстрые операции.

import numpy as np
# Быстрое вычисление нового столбца
df['result'] = np.where(df['a'] > 0, df['b'] * 2, df['b'] / 2)

Python анализ данных excel (анализ данных excel в python)

Для сложных вычислений можно использовать np.vectorize или ufuncs.

При использовании np.vectorize фактический прирост скорости небольшой, если функция не чистая на C. Луше применять pd.eval() или numba.

Как параллельно обрабатывать данные без выхода за рамки Pandas?

Вариант: группировка чанков и параллельная обработка с помощью concurrent.futures

Можно разделить данные на независимые блоки (например, по годам) и обрабатывать их параллельно.

from concurrent.futures import ProcessPoolExecutor

def process_chunk(file_chunk):
    # загрузка чанка и вычисления
    return chunk.groupby('key').sum()

with ProcessPoolExecutor() as executor:
    results = list(executor.map(process_chunk, chunk_list))

Результаты объединяются после завершения всех процессов.

Память может умножаться на количество процессов. Нужно отслеживать общий объём данных в каждом процессе.
- анализ данных с использованием python (анализ данных с использованием python)
- Python анализ текстовых данных (анализ текстовых данных в python)
- аналитик данных python sql (аналитик данных python sql)

Дополнительные практические примеры

Пример 1: агрегация огромного CSV с чанками и сохранением промежуточных результатов

Пусть есть файл sales.csv размером 10 ГБ. Нужно получить общую выручку по категориям.

Пример
import pandas as pd
import os

def aggregate_large_file(filepath, chunksize=500000):
    temp_dir = 'temp_agg'
    os.makedirs(temp_dir, exist_ok=True)
    part = 0
    for chunk in pd.read_csv(filepath, chunksize=chunksize):
        agg = chunk.groupby('category')['revenue'].sum().reset_index()
        agg.to_csv(f'{temp_dir}/part_{part}.csv', index=False)
        part += 1
    # Чтение всех частей и финальная агрегация
    parts = [pd.read_csv(f'{temp_dir}/part_{i}.csv') for i in range(part)]
    final = pd.concat(parts).groupby('category')['revenue'].sum().reset_index()
    # Очистка временных файлов
    for f in os.listdir(temp_dir):
        os.remove(os.path.join(temp_dir, f))
    os.rmdir(temp_dir)
    return final

result = aggregate_large_file('sales.csv')
print(result.head())
   category    revenue
0  Electronics  1.23e9
1  Clothing     4.56e8
2  Books        7.89e8

Временные файлы предотвращают переполнение памяти при большом количестве чанков.

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

Требуется заменить значения в столбце по словарю.

Пример
import pandas as pd
import numpy as np

df = pd.DataFrame({'code': ['A', 'B', 'C', 'A', 'B']})
mapping = {'A': 10, 'B': 20, 'C': 30}
# Создание массива NumPy из ключей и значений
keys = np.array(list(mapping.keys()), dtype=object)
values = np.array(list(mapping.values()), dtype=np.int64)
# Векторизованное отображение через поиск индексов
idx = np.searchsorted(keys, df['code'].values)
df['code_int'] = values[idx]
print(df)
  code  code_int
0    A        10
1    B        20
2    C        30
3    A        10
4    B        20

Этот способ в 5–10 раз быстрее df['code'].map(mapping) на больших данных.

Пример 3: разреженные матрицы для One‑Hot кодирования

Если категориальных признаков много, One‑Hot в Pandas занимает много памяти. NumPy + scipy.sparse экономят ресурсы.

Пример
import pandas as pd
import numpy as np
from scipy.sparse import csr_matrix

df = pd.DataFrame({'cat': ['a','b','a','c','b']})
# Получение уникальных значений
codes, uniques = pd.factorize(df['cat'])
# Создание разреженной матрицы (N x K)
sparse = csr_matrix((np.ones(len(codes)), (np.arange(len(codes)), codes)))
print(sparse.toarray())  # для демонстрации
[[1. 0. 0.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [0. 1. 0.]]

Разреженная матрица занимает меньше памяти, если количество уникальных значений значительно меньше числа строк.

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

Для больших DataFrame pd.eval() выполняет операции на C‑уровне, обходя накладные расходы Python.

Пример
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randn(1000000, 4), columns=['a','b','c','d'])
# Стандартный способ
%timeit df['e'] = df['a'] + df['b'] * df['c'] / df['d']
# Через pd.eval
%timeit df.eval('e = a + b * c / d', inplace=True)
Стандартный: 123 ms ± 3 ms per loop
pd.eval: 45.2 ms ± 1.2 ms per loop

Ускорение особенно заметно при цепочках операций.

Анализ больших данных в Python - comments

En
анализ больших данных python (python)