2013-04-07 2 views
2

Есть ли хорошо векторизованный способ взять произведение всех ненулевых элементов в каждом столбце разреженной матрицы в октаве (или в матрице) (возвращая строку -проектор продуктов)?Возьмите произведение всех ненулевых элементов в каждом столбце разреженной матрицы

ответ

4

Я бы объединить find с accumarray:

%# create a random sparse array 
s = sprand(4,4,0.6); 

%# find the nonzero values 
[rowIdx,colIdx,values] = find(s); 

%# calculate product 
product = accumarray(colIdx,values,[],@prod) 

Некоторые альтернативы (которые могут быть менее эффективными, вы можете их профиль)

%# simply set the zero-elements to 1, then apply prod 
%# may lead to memory issues 
s(s==0) = 1; 
product = prod(s,1); 

.

%# do "manual" accumarray 
[rowIdx,colIdx,values] = find(s); 

product = zeros(1,size(s,2)); 
uCols = unique(colIdx); 

for col = uCols(:)' 
    product(col) = prod(values(colIdx==col)); 
end 
+0

Спасибо, я не знал о накопителе. Вы знаете, есть ли способ, который не связан с передачей функции? – dspyz

+0

@dspyz: что вы имеете в виду с «передачей функции»? – Jonas

+0

@dspyz Предполагая, что, когда вы говорите «избегать передачи функции», вы ссылаетесь на аргумент '@ prod' на' accumarray' - вот как 'tankarray' знает, какую функцию применить к массиву. Это типичный, предполагаемый синтаксис. Почему вы хотите избежать этого? – tmpearce

0

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

Просто возьмите журнал всех ненулевых элементов, а затем просуммировать столбцы , Затем возьмем exp полученного результирующего вектора:

function [r] = prodnz(m) 
    nzinds = find(m != 0); 
    vals = full(m(nzinds)); 
    vals = log(vals); 
    m(nzinds) = vals; 
    s = full(sum(m)); 
    r = exp(s); 
endfunction 
Смежные вопросы