Слияние двух матриц разной размерности в Matlab?

Вопрос:

У меня есть две матрицы A и B в Matlab. A имеет размерность mx6, например

A=[  1     1     1     1   |  1     0;
1     1     1     2   |  1     0;
1     1     1     3   |  1     0;
1     1     1     4   |  1     0;
1     2     3     2   |  1     0;
1     2     3     3   |  1     0;
1     2     3     4   |  1     0]

B имеет размерность nx6, например

B=[  1     1     1     1   |  1     1;
1     2     3     1   |  1     1]

Я хочу объединить A и B и создать матрицу C после этих шагов без использования циклов:

1) Рассмотрим B(i,1:4); если существует j такое, что A(j,1:4) равно B(i,1:4) [это может произойти не более одного j], а затем C(i,:)=[B(i,1:4) A(j,5)+B(i,5) A(j,6)+B(i,6)]. Сделайте это для всех i=1,...,n.

2) Заполните оставшиеся строки C строками A и B, которые не могут быть сопоставлены в соответствии с шагом 1).

В примере

C=[  1     1     1     1   |  2     1;  %Step 1) above
------------------------------------
1     1     1     2   |  1     0;  %Step 2) above
1     1     1     3   |  1     0;  %firstly rows from A
1     1     1     4   |  1     0;
1     2     3     2   |  1     0;
1     2     3     3   |  1     0;
1     2     3     4   |  1     0;
1     2     3     1   |  1     1]  %lastly rows from B

Моя попытка с использованием циклов:

%STEP 1
for i=1:size(B,1)
for j=1:size(A,1)
if all(B(i,1:4)==A(j,1:4),2)
C(i,:)=[B(i,1:4) A(j,5)+B(i,5) A(j,6)+B(i,6)]
end
end
end



%STEP 2


C=[ C; A(logical(1-ismember(A(:,1:4), B(:,1:4),'rows')),:)];
C=[ C; B(logical(1-ismember(B(:,1:4), A(:,1:4),'rows')),:)];

Лучший ответ:

Это довольно легко, используя комбинацию unique и accumarray. unique работает, предоставляя вам матрицу вывода, в которой удаляются все повторяющиеся записи. Это будет хорошо работать, когда речь идет о играх с A и B.

Просто объедините A и B вместе в единую консолидированную матрицу, затем используйте unique с первыми четырьмя столбцами и назначьте каждой строке этой усеченной матрицы уникальный идентификатор. Третий вывод unique даст вам этот идентификатор, и если вы хотите узнать, какой идентификатор соответствует той строке, которая выводится из первого вывода unique, где каждая строка вывода дает вам идентификатор, который соответствует к.

Вы должны использовать флаг 'rows' и 'stable', чтобы убедиться, что мы смотрим на каждую строку, а не на каждый отдельный элемент в матрице и с флагом 'stable', мы присваиваем идентификаторы на основе того, когда мы сталкиваемся с уникальным начиная с начала (сверху) до финиша (снизу). Если вы не поместили флаг 'stable', он бы сортировал строки внутри, а затем присваивал идентификаторы, начиная с верхней части этого списка.

Если вы хотите достичь желаемого результата, вы должны использовать 'stable'. Когда вы найдете эти идентификаторы, используйте accumarray дважды на пятом и шестом столбцах соответственно и примените отдельную сумму и объедините результаты вместе. accumarray работает, предоставляя набор идентификаторов или ключей, а для каждого ID/ключа – выходное значение, связанное с этим ключом. Вы группируете все значения, которые используют один и тот же ключ, и делайте что-то для каждой группы. В нашем случае мы будем применять accumarray дважды, где первый набор выходных значений поступает из пятого столбца, а второй набор выходных значений – из шестого столбца. Поведение по умолчанию с accumarray равно sum всем значениям, принадлежащим одной и той же группе, которые вы хотели.

Вывод accumarray в нашем случае будет единственным вектором столбца, до тех пор, пока общее число уникальных идентификаторов, сгенерированных на первом этапе, с unique. Вы делаете это для пятого и шестого столбцов отдельно, затем для получения окончательной матрицы просто объедините первый вывод unique, а также два выхода accumarray в одну матрицу, чтобы, наконец, получить выход.

Что-то вроде этого:

%// Your data
A=[  1     1     1     1     1     0;
1     1     1     2     1     0;
1     1     1     3     1     0;
1     1     1     4     1     0;
1     2     3     2     1     0;
1     2     3     3     1     0;
1     2     3     4     1     0];
B=[  1     1     1     1     1     1;
1     2     3     1     1     1];

%// Solution
[cols,~,id] = unique([A(:,1:4); B(:,1:4)], 'rows', 'stable');
out = accumarray(id, [A(:,5); B(:,5)]);
out2 = accumarray(id, [A(:,6); B(:,6)]);
final = [cols out out2];

Это наш вывод:

final =

     1     1     1     1     2     1
     1     1     1     2     1     0
     1     1     1     3     1     0
     1     1     1     4     1     0
     1     2     3     2     1     0
     1     2     3     3     1     0
     1     2     3     4     1     0
     1     2     3     1     1     1

Ответ №1

Вот решение без использования цикла. Тем не менее, я не совсем уверен, что это будет быстрее, чем цикл.

ind = 1:size(B,1);

[indA, indA_true] = ismember(A(:,1:4),B(:,1:4),'rows');

indB = indA_true(find(indA_true));

C = [A(indA,1:4), A(indA,5:6) + B((indB),5:6)];

C = [C; A(~indA,:); B(~ismember(ind',indB,'rows'),:)];

Оцените статью
TechArks.Ru
Добавить комментарий