Использование unique () для реструктуризации вектора в MATLAB - PullRequest
3 голосов
/ 01 февраля 2011

Скажем, A - это массив из 200 элементов, содержащий 4 разные строки (каждая имеет 50 повторений).B - это вектор из 200 элементов с некоторыми целыми числами.

Я использую [cellNos cellStartInd enumCells ] = unique(A) и получаю, какой элемент в A равен одной из уникальных строк (enumCells - это массив, содержащий целые числа 1-4, вроде перечисления строк).

Я хочу использовать эту информацию для создания матрицы значений 4x50 из B, чтобы в каждом столбце были значения для конкретной уникальной строки.Другими словами, я хочу преобразовать B в матрицу, в которой столбцы были расположены в соответствии с каждой уникальной строкой в ​​A.

Ответы [ 4 ]

4 голосов
/ 01 февраля 2011

Предполагая, что вы уже знаете, сколько будет повторений, и что все строки повторяются с одинаковой частотой, вы можете сделать следующее:

%# sort to find where the entries occur (remember: sort does stable sorting)
[~,sortIdx] = sort(enumCells);

%# preassign the output to 50-by-4 for easy linear indexing
newB = zeros(50,4);

%# fill in values from B: first the 50 ones, then the 50 2's etc
newB(:) = B(sortIdx);

%# transpose to get a 4-by-50 array
newB = newB';

Или, более компактным способом (спасибо @Rich C)

[~,sortIdx] = sort(enumCells);
newB = reshape(B(sortIdx),50,4)';
3 голосов
/ 01 февраля 2011

Для общего случая, когда у вас есть N разных строк и каждая из этих строк встречается разное число раз M_i, тогда каждый соответствующий набор значений в B будет иметь различную длину, и вы не будете быть в состоянии объединить наборы вместе в числовой массив. Вместо этого вам придется хранить наборы в N -элементе массиве ячеек , и вы можете сделать это, используя функции UNIQUE и ACCUMARRAY :

>> A = {'a' 'b' 'b' 'c' 'a' 'a' 'a' 'c' 'd' 'b'};  %# Sample array A
>> B = 1:10;                                       %# Sample array B
>> [uniqueStrings,~,index] = unique(A)
>> associatedValues = accumarray(index(:),B,[],@(x) {x})

associatedValues = 

    [4x1 double]    %# The values 1, 5, 6, and 7
    [3x1 double]    %# The values 2, 3, and 10
    [2x1 double]    %# The values 4 and 8
    [         9]    %# The value 9

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

associatedValues = [associatedValues{:}];


ПРИМЕЧАНИЕ: Поскольку ACCUMARRAY не гарантирует сохранение относительного порядка элементов, которые он накапливает, порядок элементов в ячейках associatedValues может не соответствовать относительному порядку, который они имели в вектор B. Один из способов обеспечить сохранение исходного относительного порядка в B - изменить вызов на ACCUMARRAY следующим образом:

 associatedValues = accumarray(index(:),1:numel(B),[],@(x) {B(sort(x))});

Или вы можете отсортировать входные данные по ACCUMARRAY , чтобы получить тот же эффект:

[index,sortIndex] = sort(index);
associatedValues = accumarray(index(:),B(sortIndex),[],@(x) {x});
0 голосов
/ 01 февраля 2011

Этот метод будет работать, если количество записей в строке одинаково, если они различаются, см. Решение @gnovice.

NumStrings = numel(CellNos);
M = zeros(size(B,1)/NumStrings,NumStrings);
for i = 1:NumStrings
    M(:,i) = B(strcmp(B,CellNos{i}));
end

Кроме того, если вы знаете, что уникальные строки опережают время (например, CellNos}), это позволяет вам пропустить уникальный вызов, который является относительно дорогим.

0 голосов
/ 01 февраля 2011

Если я правильно понимаю ваш вопрос, это можно сделать с помощью функции поиска. http://www.mathworks.com/help/techdoc/ref/find.html

Чтобы создать свою матрицу, просто напишите:

M(:,1) = B(find(enumCells==1));
M(:,2) = B(find(enumCells==2));
M(:,3) = B(find(enumCells==3));
M(:,4) = B(find(enumCells==4));

Возможно, есть более элегантный способ сделать это, но это должно сработать.

РЕДАКТИРОВАТЬ: Вы можете попробовать использовать "сортировать", чтобы сделать это. Функция сортировки может выдавать перестановки сортировки в качестве вывода. Попробуйте:

[s perm] = sort(enumCells);
M = reshape(B(perm),50,4);
...