Числовые массивы со смешанными изменяемыми и неизменяемыми значениями - PullRequest
5 голосов
/ 06 ноября 2011

Меня интересует лучший / быстрый способ выполнения операций с массивами (точка, внешний, сложение и т. Д.) При игнорировании некоторых значений в массиве.В основном меня интересуют случаи, когда некоторые (может быть, 50% -30%) значений игнорируются и фактически равны нулю при умеренно больших массивах, возможно, от 100 000 до 1 000 000 элементов.Есть несколько решений, о которых я могу подумать, но ни одно из них, похоже, действительно не извлекает выгоду из возможных преимуществ возможности игнорировать некоторые ценности.Например:

import numpy as np
A = np.ones((dim, dim)) # the array to modify
B = np.random.random_integers(0, 1, (dim, dim)) # the values to ignore are 0
C = np.array(B, dtype = np.bool)
D = np.random.random((dim, dim)) # the array which will be used to modify A

# Option 1: zero some values using multiplication.
# some initial tests show this is the fastest
A += B * D

# Option 2: use indexing
# this seems to be the slowest
A[C] += D[C]

# Option 3: use masked arrays
A = np.ma.array(np.ones((dim, dim)), mask = np.array(B - 1, dtype = np.bool))
A += D

edit1:

Как предлагает Киборг, разреженные массивы могут быть другим вариантом.К сожалению, я не очень знаком с пакетом и не могу получить преимущества в скорости, которые я мог бы иметь.Например, если у меня есть взвешенный граф с ограниченной связностью, определяемой разреженной матрицей A, другой разреженной матрицей B, которая определяет связность (1 = подключен, 0 = не соединен), и плотной матрицей C,Я хотел бы иметь возможность сделать что-то вроде A = A + B.multiply(C) и воспользоваться преимуществами A и B, являющимися разреженными.

1 Ответ

1 голос
/ 06 ноября 2011

С разреженной матрицей вы можете получить улучшение, если плотность составляет менее 10%.Разреженная матрица может быть быстрее, в зависимости от того, включено ли время, необходимое для построения матрицы.

import timeit

setup=\
'''
import numpy as np
dim=1000
A = np.ones((dim, dim)) # the array to modify
B = np.random.random_integers(0, 1, (dim, dim)) # the values to ignore are 0
C = np.array(B, dtype = np.bool)
D = np.random.random((dim, dim)) # the array which will be used to modify A
'''

print('mult    '+str(timeit.timeit('A += B * D', setup, number=3)))

print('index   '+str(timeit.timeit('A[C] += D[C]', setup, number=3)))

setup3 = setup+\
''' 
A = np.ma.array(np.ones((dim, dim)), mask = np.array(B - 1, dtype = np.bool))
'''
print('ma      ' + str(timeit.timeit('A += D', setup3, number=3)))

setup4 = setup+\
''' 
from scipy import sparse
S = sparse.csr_matrix(C)
DS = S.multiply(D)
'''
print('sparse- '+str(timeit.timeit('A += DS', setup4, number=3)))

setup5 = setup+\
''' 
from scipy import sparse
'''
print('sparse+ '+str(timeit.timeit('S = sparse.csr_matrix(C); DS = S.multiply(D); A += DS', setup4, number=3)))

setup6 = setup+\
'''
from scipy import sparse
class Sparsemat(sparse.coo_matrix):
    def __iadd__(self, other):
        self.data += other.data
        return self
A = Sparsemat(sparse.rand(dim, dim, 0.5, 'coo')) # the array to modify
D = np.random.random((dim, dim)) # the array which will be used to modify A
anz = A.nonzero()
'''
stmt6=\
'''
DS = Sparsemat((D[anz[0],anz[1]], anz), shape=A.shape) # new graph based on random weights
A += DS
'''
print('sparse2 '+str(timeit.timeit(stmt6, setup6, number=3)))

Вывод:

mult    0.0248420299535
index   0.32025789431
ma      0.1067024434
sparse- 0.00996273276303
sparse+ 0.228869672266
sparse2 0.105496183846

Изменить: Вы можетеиспользуйте код выше (setup6) для расширения scipy.sparse.coo_matrix.Сохраняет разреженный формат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...