Saya memiliki 4 vektor kolom n-oleh-1 di mana berbagi nomor indeks yang sama berarti mereka memiliki stempel waktu yang sama. Saya ingin menghapus "baris" yang identik dengan "baris" sebelumnya dan bayangkan ini dilakukan secara rekursif hingga tidak ada perubahan.

Sebagai contoh, misalkan 4 vektor adalah

C1=[1;1;3;3;1;1];
C2=[2;2;4;4;2;2];
C3=[0;0;0;0;0;0];
C4=[5;5;6;6;5;5];

Keluaran yang diinginkan adalah

ans=[1;3;5];

Karena [C1(ans),C2(ans),C3(ans),C4(ans)] adalah larik tanpa baris yang identik dengan baris sebelumnya. Pada contoh di atas, vektor yang dihasilkan terlihat seperti:

C1=[1;3;1];
C2=[2;4;2];
C3=[0;0;0];
C4=[5;6;5];

"Baris" seperti pada baris ketika melihat vektor yang digabungkan berdasarkan kolom dengan [C1,C2,C3,C4].

Pertanyaan:

  • Saya mengerti bagaimana melakukannya dengan loop. Bagaimana Anda melakukannya dengan fungsi Matlab asli?

Beberapa catatan:

Alasan saya memulai dengan 4 vektor kolom terpisah adalah sebagai berikut:

  1. Saya memiliki satu vektor n-oleh-1 lainnya dengan elemen unik di mana saya akan menghapus "baris" yang sama berdasarkan indeks yang dihapus untuk 4 vektor lainnya;

  2. dalam aplikasi saya, data diambil dari tempat lain dan disimpan ke dalam tipe data Maltab elemen demi elemen untuk diproses lebih lanjut dan saya menemukan keuntungan kinerja dengan menyimpan ke 4 N-oleh-1 ganda menjadi 1 N-kali-4 ganda. N ini ada dalam ratusan ribu atau jutaan.

N biasanya hanya beberapa ribu pada satu waktu tetapi saya memiliki kebutuhan untuk meminimalkan waktu yang dibutuhkan setiap penyaringan sebanyak dalam 1 detik dan sekecil mungkin.

(Saya ingin mempelajari metode menggunakan fungsi asli dan membandingkan kinerja.)


Catatan tentang kinerja

Agak sulit untuk menunjukkan perbedaan kinerja yang satu ini karena data acak tidak cocok dan data yang terlalu spesifik tidak cocok. (Dengan susah payah, maksud saya sulit untuk dilakukan dengan cepat.)

Tetapi jika ada yang tertarik, dengan tabel ~164k baris dan hanya ~1k baris "unik", ("" di sekitar baris juga,) hasil dari timeit() adalah sebagai berikut.

  • Metode diff or Cris: 0,0028 detik

  • Metode unique Wolfie: 0,0142 detik

  • Metode arrayfun Wolfie: 0.3912s

  • Metode diff*ones Thomas: 0,0057s

  • Metode rekursi Thomas: Tidak dapat menyelesaikan. Ini meledakkan permintaan RAM Matlab menjadi ~70GB dalam satu menit eksekusi di bawah timeit() dan menyebabkan UI membeku pada mesin Win 10 saya meskipun mesin memiliki banyak CPU yang tidak digunakan.

  • Loop (tetapi dengan varargin pada jumlah kolom): 3.6313s

Fungsi pengujian termasuk menggabungkan jika tidak secara langsung memproses kolom.

Versi loopnya adalah:

function varargout = accum(varargin)

    for i=1:numel(varargin)
        varargout{i}=varargin{i}(1);    % assuming single column
    end

    for i=2:numel(varargin{1})  % assuming equal length
        TF=false;
        for j=1:numel(varargin)
            TF=TF||varargin{j}(i)~=varargin{j}(i-1);
        end
        if TF
            for j=1:numel(varargin)
                varargout{j}=[varargout{j};varargin{j}(i)];
            end
        end
    end

end

Jika Anda menulis jawaban lain dan membutuhkan data sampel, beri tahu saya. Kalau tidak, saya akan melewatkannya, melihat sedikit gunanya melakukannya.

2
Argyll 20 Desember 2020, 23:11

3 jawaban

Jawaban Terbaik

Saya pikir yang berikut ini memberikan hasil yang diinginkan (tidak diuji):

find([1; diff(C1) | diff(C2) | diff(C3) | diff(C4)])

diff bukan nol di mana dua elemen berikutnya berbeda. Menggunakan logika OR kita mensyaratkan bahwa salah satu vektor memiliki perbedaan pada satu posisi. Elemen pertama selalu menjadi bagian dari output. find mengembalikan indeks elemen bukan nol.

4
Cris Luengo 20 Desember 2020, 20:37

Berikut adalah opsi menggunakan nilai logika untuk mensubset baris dalam matriks

C([true; abs(C(2:end,:)-C(1:end-1,:))*ones(size(C,2),1)>0],:)

Yang memberikan

ans =

   1   2   0   5
   3   4   0   6
   1   2   0   5

Jika Anda tidak keberatan menggunakan metode fungsi pengguna, di bawah ini mungkin merupakan opsi lain, di mana myfun menghitung baris "unik" secara rekursif

function y = myfun(x)
  if size(x,1)==1
    y = x;
  else
    v = x(end,:);
    y = myfun(x(1:(end-1),:));
    if ~all(y(end,:)==v)
      y = [y;v];
    end
   end
end

Seperti yang

>> z = myfun(C)
z =

   1   2   0   5
   3   4   0   6
   1   2   0   5

Dimana C = [C1,C2,C3,C4]

2
ThomasIsCoding 20 Desember 2020, 23:42

Anda dapat menggunakan pendekatan serupa dengan jawaban yang diberikan oleh Cris (find(diff(...)))), tetapi buatlah lebih umum menggunakan unique.

Penyiapan:

C1=[1;1;3;3;1;1];
C2=[2;2;4;4;2;2];
C3=[0;0;0;0;0;0];
C4=[5;5;6;6;5;5];

C = [C1,C2,C3,C4];

Metode satu:

[~,~,iu] = unique( C, 'rows' );
idx = find( [1; diff(iu)] );

Atau, Anda dapat mengulang (disingkat dengan arrayfun) untuk menemukan baris di mana setiap elemen berbeda dari baris sebelumnya

Metode dua:

idx = find( [1, arrayfun( @(ii) any(C(ii,:) ~= C(ii-1,:)), 2:size(C,1) )] )
0
Wolfie 21 Desember 2020, 10:18