Matlab Histc с векторными бинами - PullRequest
3 голосов
/ 30 ноября 2011

Если у меня есть две матрицы A и B размером [mxn] и [pxn], и я хочу найти количество раз, которое каждая строка B появляется в A, например:

>> A = rand(5,3)

A =

    0.1419    0.6557    0.7577
    0.4218    0.0357    0.7431
    0.9157    0.8491    0.3922
    0.7922    0.9340    0.6555
    0.9595    0.6787    0.1712

>> B = [A(2,:); A(1,:); A(2,:); A(3,:); A(3,:); A(4,:); A(5,:)] 

B =

    0.4218    0.0357    0.7431
    0.1419    0.6557    0.7577
    0.4218    0.0357    0.7431
    0.9157    0.8491    0.3922
    0.9157    0.8491    0.3922
    0.7922    0.9340    0.6555
    0.9595    0.6787    0.1712

с ответом в этом случае

ans =

     1     2     2     1     1

, хотя, в отличие от этого примера, в общем случае m >> p

Если бы A и B были векторами, Gistc Matlab сделал бы эту работу, нокажется, что не существует эквивалента, если ячейки являются векторами.

В настоящее время я делаю это с помощью:

for i=1:length(B)
    indices(i) = find(abs(A/B(i,:)-1) < 1e-15); 
    % division requires a tolerance due to numerical issues
end
histc(indices, 1:size(A,1))

ans =

     1     2     2     1     1

, но поскольку у меня много таких матриц B, а также A и Bбольшие, это ужасно медленно.Любые идеи, как улучшить это?

РЕДАКТИРОВАТЬ:

Глядя на методы до сих пор, у меня есть следующие данные:

A                    7871139x3                188907336  double                       
B                        902x3                    21648  double                       

Чтобы сделать вещи быстрее, я 'Я просто собираюсь использовать первые 10 строк B

B = B(1:10,:);

Обратите внимание, что для полного приложения у меня (в настоящее время) есть> 10 ^ 4 таких матриц (в конечном итоге это будет> 10 ^ 6 ....)

Мой первый метод:

tic, C = get_vector_index(A,B); toc
Elapsed time is 36.630107 seconds.

Метод bdecaf (можно уменьшить до ~ 25 секунд, удалив оператор if и используя расстояние L1 вместо расстояния L2)

>> tic, C1 = get_vector_index(A,B); toc
Elapsed time is 28.957243 seconds.
>> isequal(C, C1) 

ans =

     1

метод oli's pdist2

>> tic, C2 = get_vector_index(A,B); toc
Elapsed time is 7.244965 seconds.

>> isequal(C,C2)

ans =

     1

метод нормализации oli

>> tic, C3 = get_vector_index(A,B); toc
Elapsed time is 3.756682 seconds.

>> isequal(C,C3)

ans =

     1

Наконец я нашел другой метод, где я ищу первый столбец, затем я ищу второйстолбец в пределах попаданий первого столбца, повторяющийся до тех пор, пока столбцы не будут исчерпаны.Пока это самый быстрый ...

N = size(A,2);
loc = zeros(size(B,1),1);
for i=1:size(B,1)
    idx{1} = find(A(:,1)==B(i,1));
    for k=2:N, 
        idx{k} = idx{k-1}(find(A(idx{k-1},k)==B(i,k))); 
    end
    loc(i) = idx{end};
end
C = histc(loc, 1:size(A,1));

, что приводит к:

>> tic, C4 = get_vector_index(A,B); toc
Elapsed time is 1.314370 seconds.

>> isequal(C, C4)

ans =

     1

Также обратите внимание, что использование intersect намного медленнее:

>> tic, [~,IA] = intersect(A,B,'rows'); C5 = histc(IA,1:size(A,1)); toc
Elapsed time is 44.392593 seconds.

>> isequal(C,C5)

ans = 

    1

Ответы [ 4 ]

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

Я бы решил это так:

indices = zeros(size(A,1),1);
for i=1:size(B,1)
    distances = sum( ( repmat(B(i,:),size(A,1),1)-A ).^2 ,2);
    [md,im]=min(distances);
    if md < 1e-9
      indices(im) = indices(im)+1;
    end
end

если вы удалите if, он будет просто отсортирован в ближайший контейнер.

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

На самом деле, более простой способ сделать это:

sum(10e-9>pdist2(A',B'),2)

он вычисляет все попарные расстояния, пороговое значение и счет.

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

Может быть, вы могли бы нормализовать их так, чтобы вы проверяли, что их точечное произведение равно 1

A = rand(5,3);
B = [A(2,:); A(1,:); A(2,:); A(3,:); A(3,:); A(4,:); A(5,:)];
A2=bsxfun(@times,A,1./sqrt(sum(A.^2,2))); %%% normalize A
B2=bsxfun(@times,B,1./sqrt(sum(B.^2,2))) %%% normalize B
sum(A2*B2'>1-10e-9,2) %%% check that the dotproduct is close to 1

ans =

     1
     2
     2
     1
     1

Если вам нужно что-то еще более быстрое, но приближенное, я рекомендую вам использовать библиотеку flann, которая предназначена дляБыстро приближенный ближайший сосед:

http://www.cs.ubc.ca/~mariusm/index.php/FLANN/FLANN

0 голосов
/ 15 декабря 2011

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

N = size(A,2);
loc = zeros(size(B,1),1);
for i=1:size(B,1)
    idx{1} = find(A(:,1)==B(i,1));
    for k=2:N, 
        idx{k} = idx{k-1}(find(A(idx{k-1},k)==B(i,k))); 
    end
    loc(i) = idx{end};
end
C = histc(loc, 1:size(A,1));

, что приводит к:

>> tic, C4 = get_vector_index(A,B); toc
Elapsed time is 1.314370 seconds.

>> isequal(C, C4)

ans =

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