Saya memiliki dua array 3D:

bentuk adalah larik 240 x 121 x 10958
luas adalah larik 240 x 1 x 10958

Nilai dari array bertipe double. Keduanya memiliki NaN sebagai nilai isian di mana tidak ada data yang relevan.

Untuk setiap halaman [240 x 121] larik bentuk, ada beberapa elemen yang diisi dengan nomor yang sama. Misalnya, akan ada blok 1s, blok 2s, dll. Untuk setiap halaman yang sesuai dari larik area ada satu kolom dengan nilai numerik sepanjang 240 baris. Yang perlu saya lakukan adalah secara bertahap menelusuri setiap halaman larik bentuk (bergerak sepanjang sumbu ke-3, panjang 10958) dan mengganti setiap elemen bernomor di halaman itu dengan nomor yang mengisi baris nomor yang cocok dalam larik area.

Misalnya, jika saya melihat shape(:,:,500), saya ingin mengganti semua angka 8 di halaman itu dengan area(8,1,500). Saya perlu melakukan ini untuk nomor 1 hingga 20, dan saya perlu melakukannya untuk semua 10958 halaman array.

Jika saya mengekstrak satu halaman dan hanya mengganti satu nomor, saya bisa membuatnya berfungsi:

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

Ini melakukan persis apa yang saya butuhkan untuk satu halaman dan untuk satu nomor. Melewati angka 1-20 dengan for loop sepertinya tidak menjadi masalah, tetapi saya tidak dapat menemukan cara vektor untuk melakukan ini untuk semua halaman array 3D asli. Faktanya, saya bahkan tidak dapat membuatnya berfungsi untuk satu halaman tanpa mengekstrak halaman itu sebagai matriksnya sendiri seperti yang saya lakukan di atas. Saya mencoba hal-hal seperti ini tetapi tidak berhasil:

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

Jika saya tidak bisa melakukannya untuk satu halaman, saya bahkan lebih bingung bagaimana melakukannya sekaligus. Tapi saya tidak berpengalaman dalam MATLAB, dan saya pikir saya hanya mengabaikan sintaks yang tepat.

Sebagai gantinya, saya akhirnya menggunakan array sel dan loop for bersarang yang sangat tidak efisien berikut ini:

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

Ini menyelesaikan pekerjaan, dan saya dapat dengan mudah mengubahnya kembali ke array, tetapi sangat lambat, dan saya yakin ada jauh cara vektorisasi yang lebih baik. Saya akan menghargai bantuan atau tip apa pun. Terima kasih sebelumnya.

1
Archimedes 9 Juli 2020, 01:53

1 menjawab

Jawaban Terbaik

Untuk membuat vektorisasi operasi pemetaan, kita dapat menggunakan shape sebagai indeks ke dalam area. Tetapi karena pemetaan berbeda untuk setiap bidang, kita perlu mengulang bidang untuk mencapai ini. Singkatnya, itu akan terlihat seperti ini:

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

Di atas hanya berfungsi jika shape hanya berisi nilai integer dalam rentang [1,N], di mana N = size(area,1). Artinya, untuk nilai lain di shape kita akan melakukan pengindeksan yang salah. Kami perlu memperbaiki shape untuk menghindari hal ini. Pertanyaannya di sini adalah, apa yang ingin kita lakukan dengan nilai-nilai di luar jangkauan itu?

Sebagai contoh, mempersiapkan shape untuk menangani nilai NaN:

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

Ini menggantikan semua nilai NaN di shape dengan nilai code, yang lebih besar dari nilai kode apa pun yang kami petakan. Kemudian, kami memperluas area untuk memiliki satu nilai lagi, nilai untuk input code. Nilai yang kita isi di sini adalah nilai output test_result dimana shape adalah NaN. Dalam hal ini, kami menulis NaN, sehingga NaN di input memetakan ke NaN di output.

Hal serupa dapat dilakukan dengan nilai di bawah 0 dan di atas 240 (shape(shape<1 | shape>240) = code), atau dengan nilai bukan bilangan bulat (shape(mod(shape,1)~=0) = code).

1
Cris Luengo 9 Juli 2020, 22:17