Обработка крупных массивов в языке 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))
(вывод зависит от данных)

Работа с большими массивами в Python - comments

En
Python большие массивы (python)