Обработка крупных массивов данных: 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))Результаты объединяются после завершения всех процессов.
Дополнительные практические примеры
Пример 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
Ускорение особенно заметно при цепочках операций.