Обработка крупных массивов в языке Python: практические советы
Основные подходы к работе с большими массивами
Как обрабатывать большие списки, не перегружая память?
Стандартные списки Python хранят ссылки на объекты, поэтому каждый элемент занимает дополнительную память (около 28 байт на число в CPython). При размере в миллионы элементов потребление памяти становится значительным, а операции копирования и вставки – медленными.
# Пример создания большого списка
big_list = [i for i in range(10_000_000)]
print(sys.getsizeof(big_list)) # 80000072 байт (без учета элементов)минимальный элемент массива python (поиск минимального элемента в массиве)
Типичная проблема:
При добавлении элементов через append память выделяется с запасом, но при частых вставках/удалениях производительность падает. Решение – использовать array.array или NumPy для однотипных данных.Как хранить однотипные данные с меньшим расходом памяти?
Модуль array предоставляет компактное представление для чисел фиксированного типа (int, float, char). Элементы хранятся как C-массивы, что экономит память в 3-10 раз по сравнению со списком.
from array import array
arr = array('d', [0.0]) * 10_000_000 # массив из 10 млн double
print(arr.buffer_info()) # адрес и размер в байтахPython массив последнего элемента (получение последнего элемента массива)
Ограничение:
array поддерживает только примитивные типы и не имеет удобных векторных операций. Для сложных вычислений требуется цикл.Как выполнять векторные операции над массивами с максимальной производительностью?
Библиотека NumPy – основной инструмент для работы с многомерными массивами. Операции выполняются на уровне C, без циклов Python, и используют оптимизированные алгоритмы BLAS/LAPACK.
import numpy as np
big_arr = np.arange(10_000_000, dtype=np.float64)
result = big_arr * 2 + 1 # векторная операция
print(result[:5]) # [1. 3. 5. 7. 9.]
массив python примеры (примеры массивов в python)
NumPy также поддерживает продвинутые функции: broadcasting, агрегации, линейную алгебру, случайные числа.
Возможные ошибки:
Использование списка Python при создании массива приводит к копированию и потере памяти. Всегда передавайтеdtype явно. При работе с массивами, не помещающимися в RAM, применяйте numpy.memmap.Как обрабатывать данные по частям, не загружая весь массив в память?
Генераторы и итераторы позволяют обрабатывать элементы последовательно, не создавая полной копии в памяти. Особенно полезно при чтении больших файлов.
def read_large_file(file_path, chunk_size=1024):
with open(file_path, 'rb') as f:
while chunk := f.read(chunk_size):
yield chunk
for data_chunk in read_large_file('huge.bin'):
process(data_chunk) # обработка кускасписки в python примеры (примеры работы со списками в python)
Проблема:
Генераторы не подходят для случайного доступа. Для численных массивов лучше использовать NumPy сnumpy.fromfile или numpy.memmap.Как анализировать большие наборы данных с метками столбцов?
Библиотека pandas строит DataFrame на основе NumPy, добавляя индексы и метки. Она оптимизирована для табличных данных и поддерживает чтение по частям с помощью chunksize.
import pandas as pd
chunk_iter = pd.read_csv('large.csv', chunksize=10_000)
for chunk in chunk_iter:
mean_val = chunk['value'].mean()
print(mean_val)
Типичная ошибка:
Загрузка всего CSV в память (без chunksize) может вызвать MemoryError. Всегда оценивайте размер данных.Дополнительные продвинутые примеры
Работа с массивами, превышающими оперативную память, через numpy.memmap
NumPy позволяет отображать файл на диск как массив, не загружая его целиком.
import numpy as np
import os
# Создаём файл 200 МБ на диске
filename = 'big_array.dat'
arr = np.memmap(filename, dtype='float32', mode='w+', shape=(50_000_000,))
arr[:] = np.arange(50_000_000, dtype='float32')
del arr # закрываем
# Открываем для чтения
arr_ro = np.memmap(filename, dtype='float32', mode='r', shape=(50_000_000,))
print(arr_ro[42]) # 42.0
# Изменяем участок
arr_rw = np.memmap(filename, dtype='float32', mode='r+', shape=(50_000_000,))
arr_rw[0:10] = 999
print(arr_rw[0]) # 999.0
os.unlink(filename) # удаляем файл
42.0 999.0
Параллельная обработка массива с разбиением на чанки
Использование multiprocessing.Pool для ускорения вычислений на многоядерном процессоре.
import numpy as np
from multiprocessing import Pool
def sum_chunk(chunk):
return np.sum(chunk)
if __name__ == '__main__':
data = np.arange(100_000_000, dtype='float64')
num_chunks = 4
chunks = np.array_split(data, num_chunks)
with Pool(num_chunks) as pool:
results = pool.map(sum_chunk, chunks)
total = sum(results)
print(f'Сумма: {total}') # 4.99999995e+15
Сумма: 4999999950000000.0
Построчная обработка большого CSV без pandas
Генератор для чтения строк и накопления статистики.
import csv
from collections import Counter
def process_large_csv(file_path, column_index):
with open(file_path, 'r') as f:
reader = csv.reader(f)
next(reader) # пропустить заголовок
counter = Counter()
for row in reader:
counter[row[column_index]] += 1
return counter
# Пример использования (файл должен существовать)
# result = process_large_csv('data.csv', 2)
# print(result.most_common(5))
(вывод зависит от данных)