2013-07-12 6 views
3

Допустим, у меня есть два вектора A и B с различной длиной Length(A) is not equal to Length(B) и значения в векторе A, не такие же, как в векторе B. Я хочу сравнить каждое значение B со значениями A (Сравнить означает, что значение B (я) почти такое же значение A(1:end), например B(i)-Tolerance<A(i)<B(i)+Tolerance.Matlab: Сравнение двух векторов разной длины и разных значений?

Как я могу сделать это без использования for loop, так как данные огромны?

Я знаю ismember(F), пересекается, repmat, найти, но не из тех функций могут действительно помогите мне

+0

Значит, вы сравниваете «A (i)» с «B (i)»? Почему бы не опубликовать существующий код цикла, и люди могут предлагать улучшения оттуда. – weston

+0

Вот решение для члена с допуском. Это примерно в два раза медленнее, чем решение, отправленное @ondav, но более точно справляется с допуском. http://www.mathworks.com/matlabcentral/fileexchange/23294-ismember/content/ismemberf.m –

ответ

2

Похоже, что вы пытаетесь сделать, это ismember для использования на реальных оцененных данных.

То есть, проверить для каждого значения B(i) в вашем векторе B ли B(i) находится в пределах порога допуска T по меньшей мере, одного значения в вашем векторе A

Это работает что-то вроде следующего:

tf = false(1, length(b)); %//the result vector, true if that element of b is in a 
t = 0.01; %// the tolerance threshold 
for i = 1:length(b) 
    %// is the absolute difference between the 
    %//element of a and b less that the threshold? 
    matches = abs(a - b(i)) < t; 

    %// if b(i) matches any of the elements of a 
    tf(i) = any(matches); 
end 

Или, короче говоря:

t = 0.01; 
tf = arrayfun(@(bi) any(abs(a - bi) < t), b); 

Регар ding, избегая цикла for: в то время как это может выиграть от векторизации, вы также можете рассмотреть возможность поиска параллелизма, если ваши данные , что огромный. В этом случае использование цикла for, как в моем первом примере, может быть удобно, поскольку вы можете легко выполнить базовую версию параллельной обработки, изменив for на parfor.

+0

Мне это нравится, это очень приятно и понятно и решает задачу. Единственная проблема заключается в линейном поиске в 'any' - см. Мое решение с сравнением времени выполнения. – ondrejdee

1

Это полностью вектологизированное решение. Обратите внимание, что я бы рекомендовал решение, данное @Alan, поскольку мой вряд ли будет работать для больших наборов данных.

[X Y]=meshgrid(A,B) 
M=abs(X-Y)<tolerance 

Теперь логический индекс элементов в том, что находится в пределах допуска, может быть получен с any(M) и индексом B находится на any(M,2)

1

bsxfun на помощь

>> M = abs(bsxfun(@minus, A, B')); %//' difference 
>> M < tolerance 
+1

Приятно, но он явно хранит различия в парах элементов - сложность памяти 'M * N'. – ondrejdee

3

Вы может попробовать решение по этим линиям:

tol = 0.1; 

N = 1000000; 

a = randn(1, N)*1000; % create a randomly 

b = a + tol*rand(1, N); % b is "tol" away from a 

a_bin = floor(a/tol); 
b_bin = floor(b/tol); 

result = ismember(b_bin, a_bin) | ... 
     ismember(b_bin, a_bin-1) | ... 
     ismember(b_bin, a_bin+1); 

find(result==0) % should be empty matrix. 

Идея состоит в том, чтобы дискретизировать переменные a и b в ячейках размером tol. Затем вы спрашиваете, найден ли b в том же ящике, что и любой элемент из a, или в корзине слева от него, или в корзине справа от него.

Преимущество: Я считаю ismember умно внутри, сначала сортируют элементы a, а затем выполняют сублинейный (журнал (N)) для каждого элемента поиска б. Это не похоже на подходы, которые явно строят различия каждого элемента в b с элементами из a, то есть сложность линейна по числу элементов в a.

Сравнение: для N=100000 это работает 0.04s на моей машине, по сравнению с 20 с использованием линейного поиска (приурочен с использованием приятного и лаконичного решения tf = arrayfun(@(bi) any(abs(a - bi) < tol), b); Алана).

Недостатки: это приводит к тому, что фактический допуск - это что-то среднее между tol и 1.5 * tol. Зависит от вашей задачи, можете ли вы с этим жить (если единственная проблема - сравнение с плавающей запятой, вы можете).

Примечание: зависит ли это от жизнеспособного подхода от диапазонов a и b и значения tol. Если a и b могут быть очень большими, а tol очень мал, a_bin и b_bin не смогут разрешить отдельные ячейки (тогда вам придется работать со встроенными типами, снова тщательно проверяя, что их диапазоны достаточно). Решение с петлями является более безопасным, но если вам действительно нужна скорость, вы можете инвестировать в оптимизацию представленной идеи. Другим вариантом, конечно же, было бы написать расширение mex.

+0

Не уверен, что он будет делать с производительностью, но считал ли вы комбинацией a_bin + -1, так что вам нужен только один участник? –

+0

Да, и я считаю, что это ускорит еще больше, потому что будет только один внутренний вид. Хороший совет! – ondrejdee

+0

@DennisJaheruddin Пробовал - да, это сокращает время от 0,05 до 0,04. – ondrejdee

0

Другой способ сделать то, что вы хотите, с логическим выражением.
Так как А и В являются векторами разных размеров, вы не можете просто вычитать и искать значения, которые меньше, чем допуск, но вы можете сделать следующее:

Lmat = sparse((abs(repmat(A,[numel(B) 1])-repmat(B',[1 numel(A)])))<tolerance); 

и вы получите редкую логическую матрицу с таким количеством в нем равных элементов (в пределах толерантности). Затем можно посчитать, сколько из тех элементов, которые вы должны в письменной форме:

Nequal = sum(sum(Lmat)); 

Вы также мог бы получить индексы соответствующих элементов в письменной форме:

[r,c] = find(Lmat); 

то следующий код будет верно (для все J в numel(r)):

B(r(j))==A(c(j)) 

Наконец, следует отметить, что в этом случае вы получите несколько счетчиков в случае, если есть повторяющиеся записи в А или в В. это может быть advisab le для использования функции unique. Например:

A_new = unique(A); 
Смежные вопросы