Я пытаюсь реализовать функцию в NumPy/Scipy, чтобы вычислить Jensen-Shannon divergence между одним (обучающим) вектором и большим числом других (наблюдательных) векторов. Векторы наблюдения хранятся в очень большом (500 000x65536) Scipy sparse matrix (плотная матрица не будет вписываться в память).Добавление очень повторяющейся матрицы к разреженной в numpy/scipy?
В рамках алгоритма мне нужно вычислить T + O я для каждого вектора наблюдения O я, где Т представляет собой обучающий вектор. Я не смог найти способ сделать это, используя обычные правила вещания NumPy, поскольку разреженные матрицы, похоже, не поддерживают их (если T остается как плотный массив, Scipy пытается сначала разрезать разреженную матрицу, если я превращаю T в разреженную матрицу, T + O i терпит неудачу, потому что формы несовместимы).
В настоящее время я беру грубо неэффективный шаг черепицы тренировочную вектора в 500,000x65536 разреженную матрицу:
training = sp.csr_matrix(training.astype(np.float32))
tindptr = np.arange(0, len(training.indices)*observations.shape[0]+1, len(training.indices), dtype=np.int32)
tindices = np.tile(training.indices, observations.shape[0])
tdata = np.tile(training.data, observations.shape[0])
mtraining = sp.csr_matrix((tdata, tindices, tindptr), shape=observations.shape)
Но это занимает огромное количество памяти (около 6GB), когда это только хранение ~ 1500 «реальных» элементов. Это также довольно медленно.
Я попытался получить умный, используя stride_tricks, чтобы заставить indptr и члены данных матрицы CSR не использовать дополнительную память для повторных данных.
training = sp.csr_matrix(training)
mtraining = sp.csr_matrix(observations.shape,dtype=np.int32)
tdata = training.data
vdata = np.lib.stride_tricks.as_strided(tdata, (mtraining.shape[0], tdata.size), (0, tdata.itemsize))
indices = training.indices
vindices = np.lib.stride_tricks.as_strided(indices, (mtraining.shape[0], indices.size), (0, indices.itemsize))
mtraining.indptr = np.arange(0, len(indices)*mtraining.shape[0]+1, len(indices), dtype=np.int32)
mtraining.data = vdata
mtraining.indices = vindices
Но это не работает, потому что strided просмотров mtraining.data и mtraining.indices являются неправильную форму (и в соответствии с this answer нет никакого способа, чтобы сделать его правильной формы). Пытаясь заставить их выглядеть плоскими, используя итератор .flat, терпит неудачу, потому что он не выглядит достаточно, как массив (например, он не имеет элемента dtype), а использование метода flatten() заканчивает создание копии.
Есть ли способ сделать это?
Если вы хотите, чтобы произвести все суммы сразу, то вы будете нуждаться в 6GB памяти в любом случае, поэтому на самом деле выиграть нечего, откладывая это. Просто убедитесь, что суммирование на месте, с '+ ='! Кстати, ваша реализация плитки очень умна и эффективна, я не думаю, что вы можете получить что-то получше: я попробовал кормить 'csr_matrix' вид вектора, преобразованного с' as_strided', чтобы иметь 500000 строк, и это заняло гораздо больше времени, чем ваш подход, я думаю, что внутренне массив копируется, нарушая магию. Ваш второй подход, как вы заметили, не может быть выполнен с помощью numpy. – Jaime
CSR-матрицы не могут быть изменены на месте, к сожалению (+ = повышает NotImplemented). Поэтому я предполагаю, что я застрял с использованием в 3 раза больше памяти, чем мне (теоретически), что является болезненным, поскольку я приближаюсь к пределам моего (щедрого) 32 ГБ. –