Scipy: Разреженная матрица индикатора из массива (ов) - PullRequest
0 голосов
/ 16 февраля 2019

Каков наиболее эффективный способ вычисления разреженной логической матрицы I из одного или двух массивов a,b, где I[i,j]==True, где a[i]==b[j]?Следующее является быстрым, но неэффективным для памяти:

I = a[:,None]==b

Следующее является медленным и все еще неэффективным для памяти при создании:

I = csr((a[:,None]==b),shape=(len(a),len(b)))

Следующее дает как минимум строки, столбцы для лучшегоcsr_matrix инициализация, но она по-прежнему создает полную плотную матрицу и одинаково медленная:

z = np.argwhere((a[:,None]==b))

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

Один из способов сделать это состоит в том, чтобы сначала идентифицировать все различные элементы, которые a и b имеют общее, используя set s.Это должно хорошо работать, если для значений в a и b не очень много разных возможностей.Тогда нужно будет только циклически перебирать различные значения (ниже в переменной values) и использовать np.argwhere для определения индексов в a и b, где эти значения встречаются.2D индексы разреженной матрицы могут затем быть построены с использованием np.repeat и np.tile:

import numpy as np
from scipy import sparse

a = np.random.randint(0, 10, size=(400,))
b = np.random.randint(0, 10, size=(300,))

## matrix generation after OP
I1 = sparse.csr_matrix((a[:,None]==b),shape=(len(a),len(b)))

##identifying all values that occur both in a and b:
values = set(np.unique(a)) & set(np.unique(b))

##here we collect the indices in a and b where the respective values are the same:
rows, cols = [], []

##looping over the common values, finding their indices in a and b, and
##generating the 2D indices of the sparse matrix with np.repeat and np.tile
for value in values:
    x = np.argwhere(a==value).ravel()
    y = np.argwhere(b==value).ravel()    
    rows.append(np.repeat(x, len(x)))
    cols.append(np.tile(y, len(y)))

##concatenating the indices for different values and generating a 1D vector
##of True values for final matrix generation
rows = np.hstack(rows)
cols = np.hstack(cols)
data = np.ones(len(rows),dtype=bool)

##generating sparse matrix
I3 = sparse.csr_matrix( (data,(rows,cols)), shape=(len(a),len(b)) )

##checking that the matrix was generated correctly:
print((I1 != I3).nnz==0)

Синтаксис для генерации матрицы CSR взят из документации .Тест на равенство разреженной матрицы взят из этого поста .

Старый ответ :

Я не знаю о производительности, но по крайней мереВы можете избежать построения полной плотной матрицы, используя простое выражение генератора.Вот некоторый код, который использует два 1d массива случайных целых чисел, чтобы сначала сгенерировать разреженную матрицу способом, которым разместил OP, а затем использует выражение генератора для проверки всех элементов на равенство:

import numpy as np
from scipy import sparse

a = np.random.randint(0, 10, size=(400,))
b = np.random.randint(0, 10, size=(300,))

## matrix generation after OP
I1 = sparse.csr_matrix((a[:,None]==b),shape=(len(a),len(b)))

## matrix generation using generator
data, rows, cols = zip(
    *((True, i, j) for i,A in enumerate(a) for j,B in enumerate(b) if A==B)
)
I2 = sparse.csr_matrix((data, (rows, cols)), shape=(len(a), len(b)))

##testing that matrices are equal
## from https://stackoverflow.com/a/30685839/2454357
print((I1 != I2).nnz==0)  ## --> True

Я думаю, что нетв обход двойной петли, и в идеале это должно быть вставлено в numpy, но по крайней мере с генератором петли несколько оптимизированы ...

0 голосов
/ 16 февраля 2019

Вы можете использовать numpy.isclose с небольшим допуском:

np.isclose(a,b)

или pandas.DataFrame.eq:

a.eq(b)

Обратите внимание на этовозвращает массив True False.

...