Я работаю с очень большими размерными векторами для машинного обучения и думал об использовании numpy для уменьшения объема используемой памяти. Я бегу быстрый тест, чтобы увидеть, сколько памяти я могу сэкономить, используя NumPy (1) (3):Список с разреженными данными потребляет меньше памяти, то те же данные, что и numpy array
Стандартный список
import random
random.seed(0)
vector = [random.random() for i in xrange(2**27)]
Numpy массив
import numpy
import random
random.seed(0)
vector = numpy.fromiter((random.random() for i in xrange(2**27)), dtype=float)
памяти использование (2)
Numpy array: 1054 MB
Standard list: 2594 MB
Как и ожидалось.
Путем выделения оставшегося блока памяти с помощью собственных поплавков numpy потребляет только половину памяти, которую использует стандартный список.
Поскольку я знаю, что мои данные являются довольно запасными, я сделал тот же тест с разреженными данными.
Стандартный список
import random
random.seed(0)
vector = [random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)]
Numpy массив
from numpy import fromiter
from random import random
random.seed(0)
vector = numpy.fromiter((random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)), dtype=float)
Использование памяти (2)
Numpy array: 1054 MB
Standard list: 529 MB
Теперь, внезапно, список python использует половину объема памяти, которую использует массив numpy! Зачем?
Одна вещь, о которой я мог думать, заключается в том, что python динамически переключается на представление dict, когда обнаруживает, что он содержит очень редкие данные. Проверка этого может потенциально добавить много дополнительных накладных расходов во время выполнения, поэтому я не думаю, что это происходит.
Примечание
- Я начал свежий питон оболочку для каждого теста.
- Память измеряется с помощью htop.
- Запуск на 32-разрядном Debian.
Это 32-разрядная или 64-разрядная система? Я подозреваю, что указатели на 0 в списке Python меньше, чем float numpy. –
'0' literal - целое число, поэтому ваш список построен в основном из ints, где в массиве numpy вы все плаваете. Более того, маленькие целые числа (-5..255) интернированы, поэтому все эти нули в списке указывают на один и тот же объект. Попробуйте использовать '0.0' и посмотрите, есть ли разница. –
@ PM2Ring: тесты выполняются на 32-битном Debian. Соответственно обновился вопрос. – zeebonk