Как векторизовать условный тройной вложенный для l oop - MATLAB - PullRequest
1 голос
/ 09 июля 2020

У меня есть два 3D-массива:

форма - это 240 x 121 x 10958 массив
площадь это 240 x 1 x 10958 массив

Значения массивов имеют тип double. Оба имеют NaN в качестве значений заполнения там, где нет соответствующих данных.

Для каждой [240 x 121] страницы массива shape есть несколько элементов, заполненных одним и тем же номером. Например, будет блок из 1, блок из 2 и т. Д. c. Для каждой соответствующей страницы массива area есть один столбец числовых c значений длиной 240 строк. Что мне нужно сделать, так это постепенно go через каждую страницу массива shape (перемещаясь по 3-й оси длиной 10958) и заменить каждый пронумерованный элемент на этой странице номером, который заполняет строку совпадающее число в массиве area .

Например, если я смотрю на shape(:,:,500), я хочу заменить все восьмерки на этой странице на area(8,1,500). Мне нужно сделать это для чисел от 1 до 20, и мне нужно сделать это для всех 10958 страниц массива.

Если я извлекаю одну страницу и заменяю только одно число, я могу заставить ее работать:

shapetest = shape(:,:,500);
shapetest(shapetest==8)=area(8,1,500);

Это именно то, что мне нужно для одной страницы и одного номера. Переход по номерам 1-20 с l oop не кажется проблемой, но я не могу найти векторизованный способ сделать это для всех страниц исходного 3D-массива. Фактически, я не мог даже заставить его работать для одной страницы, не извлекая эту страницу как отдельную матрицу, как я сделал выше. Я пробовал такие вещи, но безрезультатно:

shape(shape(:,:,500)==8)=area(8,1,500);

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

Вместо этого я использовал массив ячеек и следующие очень неэффективные вложенные циклы for:

MyCell=num2cell(shape,[2 1]);
shapetest3=reshape(MyCell,1,10958);

for w=1:numel(shapetest3)
     test_result{1,w}=zeros(121,240)*NaN;
end  
 
for k=1:10958
    for i=1:29040 % 121 x 240
        for n=1:20
            if shapetest3{1,k}(i)==n
                test_result{1,k}(i)=area(n,1,k);
            end
        end
    end
end

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

1 Ответ

0 голосов
/ 09 июля 2020

Чтобы векторизовать операцию сопоставления, мы можем использовать shape в качестве индекса в area. Но поскольку отображение разное для каждой плоскости, нам нужно l oop над плоскостями, чтобы выполнить sh этого. Вкратце, это будет выглядеть так:

test_result = zeros(size(shape)); % pre-allocate output
for k=1:size(area,3)              % loop over planes
   lut = area(:,1,k);
   test_result(:,:,k) = lut(shape(:,:,k));
end

Вышеупомянутое работает, только если shape содержит только целые значения в диапазоне [1, N], где N = size(area,1). То есть для других значений в shape мы будем делать неправильную индексацию. Чтобы этого избежать, нам нужно исправить shape. Вопрос здесь в том, что мы хотим делать с этими значениями, выходящими за пределы диапазона?

Например, подготовка shape для работы со значениями NaN:

code = size(area,1) + 1; % this is an unused code word
shape(isnan(shape)) = code;
area(code,1,:) = NaN;

Это заменяет все значения NaN в shape значением code, которое на единицу больше любого отображаемого нами кодового значения. Затем мы расширяем area, чтобы получить еще одно значение, значение для входа code. Значение, которое мы здесь заполняем, - это значение, которое будет иметь результат test_result, где shape - NaN. В этом случае мы пишем NaN, так что NaN на входе отображается на NaN на выходе.

Нечто подобное можно сделать со значениями ниже 0 и выше 240 (shape(shape<1 | shape>240) = code) или с нецелыми значения (shape(mod(shape,1)~=0) = code).

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