Оптимизация вложенных циклов для работы с большими наборами данных
Мне нужно обработать многомерный массив, содержащий более 10 миллионов элементов. Вложенные циклы неэффективны при увеличении размера данных. Вот пример кода, который я использую:
data = [[[randint(0, 100) for _ in range(100)] for _ in range(100)] for _ in range(1000)]
def process(value):
# Пример обработки данных
return value * 2
start_time = time.time()
for i in range(len(data)):
for j in range(len(data[i])):
for k in range(len(data[i][j])):
data[i][j][k] = process(data[i][j][k])
print("Время выполнения:", time.time() - start_time)
Примерный объем данных составляет 10 миллионов элементов, распределенных в трехмерном массиве (1000 x 100 x 100).
- Интересны библиотеки и подходы для оптимизации обработки (фокусная задача)
- Отдельно интересна параллельная обработка (побочная задача)
Ответы (2 шт):
Список представляет собой набор математически не связанных элементов, поэтому подобные операции приходится выполнять перебором. Вам надо использовать библиотеку numpy
, которая представит Ваш набор данных как вектор и Вы сможете производить подобные вычисления сразу со всем объектом. Ваша задача будет выглядеть так:
from random import randint
import numpy as np
data = [[[randint(0, 100) for _ in range(100)] for _ in range(100)] for _ in range(1000)]
np_data = np.array(data) # превращаем список в массив numpy
np_data *= 2 # здесь функция, которую надо применить к каждому элементу
Это будет очень быстро.
UPT
Проведем замеры. Операцию с вектором померяем двумя способами. В случае если у Вас есть возможность изначально хранить данные в векторе, померяем только операцию умножения. Если нет - померяем и конвертацию в вектор и умножение.
from random import randint
import numpy as np
import time
data = [[[randint(0, 100) for _ in range(100)] for _ in range(100)] for _ in range(1000)]
np_data = np.array(data)
start_time = time.time()
np_data *= 2
print("Время выполнения умножения вектора:", time.time() - start_time)
start_time = time.time()
np_data = np.array(data)
np_data *= 2
print("Время выполнения преобразования в вектор и умножения вектора:", time.time() - start_time)
def process(value):
# Пример обработки данных
return value * 2
start_time = time.time()
for i in range(len(data)):
for j in range(len(data[i])):
for k in range(len(data[i][j])):
data[i][j][k] = process(data[i][j][k])
print("Время выполнения умножения перебором:", time.time() - start_time)
Результаты:
Время выполнения умножения вектора: 0.005906820297241211
Время выполнения преобразования в вектор и умножения вектора: 0.5156631469726562
Время выполнения умножения перебором: 2.2284791469573975
UPD2
Решил, чисто для изучения, украсть ответ CrazyElf и замерить на моем железе, для сравнения. То есть меряем вместе с генерацией вектора методами numpy
.
start_time = time.time()
np_data = np.random.randint(0, 100, size=(1000, 100, 100))
np_data *= 2
print("Время выполнения генерации и умножения вектора:", time.time() - start_time)
Вот:
Время выполнения генерации и умножения вектора: 0.10832500457763672
1/10 секунды в Google Colab и генерация таких данных и обработка:
import numpy as np
data = np.random.randint(0, 100, size=(1000, 100, 100))
data *= 2