মাতলাব ভেক্টরাইজেশন - কোষে কোনও শূন্য ম্যাট্রিক্স সারি সূচক নয়


10

আমি মতলবকে নিয়ে কাজ করছি।

আমার একটি বাইনারি স্কোয়ার ম্যাট্রিক্স রয়েছে। প্রতিটি সারির জন্য, এখানে এক বা একাধিক এন্ট্রি রয়েছে। আমি এই ম্যাট্রিক্সের প্রতিটি সারি পেরিয়ে and 1 এস এর সূচকটি ফিরিয়ে আনতে এবং সেগুলি একটি ঘরে প্রবেশের মাধ্যমে সঞ্চয় করতে চাই।

আমি ভাবছিলাম যে এই ম্যাট্রিক্সের সমস্ত সারিটি লুপ না করে এটি করার কোনও উপায় আছে কারণ মতলবটিতে লুপটি আসলেই ধীর।

উদাহরণস্বরূপ, আমার ম্যাট্রিক্স

M = 0 1 0
    1 0 1
    1 1 1 

তারপরে অবশেষে আমি এমন কিছু চাই want

A = [2]
    [1,3]
    [1,2,3]

সুতরাং Aএকটি সেল হয়।

ফলাফলটি আরও দ্রুত গণনার লক্ষ্য নিয়ে লুপ ব্যবহার না করে এই লক্ষ্য অর্জনের কোনও উপায় আছে কি?


আপনি কি ফলাফলটি দ্রুত হোক বা ফলাফলটি forলুপগুলি এড়ানোর জন্য চান ? এই সমস্যার জন্য, ম্যাটল্যাবের আধুনিক সংস্করণগুলি সহ, আমি দৃ strongly়ভাবে সন্দেহ করি যে একটি forলুপটি দ্রুততম সমাধান হতে পারে। আপনার যদি পারফরম্যান্স সমস্যা হয় তবে আমার সন্দেহ হয় আপনি পুরানো পরামর্শের ভিত্তিতে সমাধানের জন্য ভুল জায়গায় খুঁজছেন।
উইল

@ আমি চাই ফলাফলগুলি দ্রুত হোক। আমার ম্যাট্রিক্স অনেক বড়। লুপ ব্যবহার করে আমার কম্পিউটারে রান সময় প্রায় 30s এর কাছাকাছি। আমি জানতে চাই যে এখানে কিছু চতুর ভেক্টরাইজেশন অপারেশন বা ম্যাপ্রেডস ইত্যাদি রয়েছে যা গতি বাড়িয়ে তুলতে পারে।
ftxx

1
আমার সন্দেহ, আপনি পারবেন না। ভেক্টরাইজেশন সঠিকভাবে বর্ণিত ভেক্টর এবং ম্যাট্রিকগুলিতে কাজ করে তবে আপনার ফলাফলটি বিভিন্ন দৈর্ঘ্যের ভেক্টরগুলিকে মঞ্জুরি দেয়। সুতরাং, আমার ধারণাটি হ'ল, আপনার কাছে সর্বদা কিছু স্পষ্ট লুপ বা কিছু লুপ-ইন-ছদ্মরূপ থাকবে cellfun
হংসহিরসে

@ftxx কত বড়? এবং 1একটি সাধারণ সারিতে কতগুলি ? findশারীরিক স্মৃতিতে ফিট করার জন্য পর্যাপ্ত পরিমাণের জন্য 30 এর কাছাকাছি কোনও লুপ নিয়ে যাওয়ার আমি আশা করব না ।
উইল

@ ফটিক্স দয়া করে আমার আপডেট হওয়া উত্তরটি দেখুন, আমি সম্পাদনা করেছি যেহেতু এটি একটি স্বল্প পারফরম্যান্স উন্নতির সাথে গৃহীত হয়েছিল
ওল্ফি

উত্তর:


11

এই উত্তরের নীচে কিছু বেঞ্চমার্কিং কোড রয়েছে, যেহেতু আপনি স্পষ্ট করেছিলেন যে আপনি নির্বিচারে forলুপগুলি এড়িয়ে চলার চেয়ে কার্য সম্পাদনে আগ্রহী ।

আসলে, আমি মনে করি forলুপগুলি এখানে সম্ভবত সবচেয়ে পারফরম্যান্ট বিকল্প। যেহেতু "নতুন" (2015 বি) জেআইটি ইঞ্জিনটি চালু হয়েছিল ( উত্স ) forলুপগুলি অন্তর্নিহিতভাবে ধীর নয় - বাস্তবে তারা অভ্যন্তরীণভাবে অনুকূলিত হয়।

আপনি বেঞ্চমার্ক থেকে দেখতে পারেন যে এখানেmat2cell টমাসসকোডিংয়ের দেওয়া বিকল্পটি খুব ধীর ...

তুলনা 1

যদি আমরা স্কেলটিকে আরও পরিষ্কার করার জন্য সেই লাইনটি থেকে মুক্তি পাই তবে আমার splitapplyপদ্ধতিটি মোটামুটি ধীর, অবচার্ডনের যথার্থ বিকল্পটি কিছুটা ভাল তবে দ্রুত (এবং তুলনীয়) বিকল্পগুলি হয় arrayfun(থমাসের পরামর্শ অনুসারে) বা forলুপ ব্যবহার করছে। নোট করুন যে arrayfunমূলত forবেশিরভাগ ব্যবহারের ক্ষেত্রে ছদ্মবেশে লুপ হয়, সুতরাং এটি কোনও আশ্চর্যজনক টাই নয়!

তুলনা 2

forকোডের পঠনযোগ্যতা এবং সেরা পারফরম্যান্সের জন্য আপনাকে একটি লুপ ব্যবহার করার পরামর্শ দিচ্ছি ।

সম্পাদনা করুন :

যদি আমরা ধরে নিই যে লুপিং দ্রুততম পদ্ধতির হয় তবে আমরা findকমান্ডটি ঘিরে কিছু আশাবাদী করতে পারি ।

বিশেষভাবে

  • Mযৌক্তিক করুন । নীচের প্লটটি দেখায় যে, এটি তুলনামূলকভাবে ছোটের জন্য দ্রুততর হতে পারে Mতবে বড়দের জন্য ধরণের রূপান্তরকরণের ধীরে ধীরে ধীর হতে পারে M

  • Mকোনও অ্যারে 1:size(M,2)ব্যবহারের পরিবর্তে সূচকে যুক্তিযুক্ত ব্যবহার করুন find। এটি লুপের সবচেয়ে ধীরতম অংশ ( findকমান্ড) এড়িয়ে চলে এবং ধরণের রূপান্তর ওভারহেডকে ছাড়িয়ে যায়, এটি দ্রুত বিকল্প হিসাবে তৈরি করে।

এখানে সেরা অভিনয়ের জন্য আমার প্রস্তাবনাটি দেওয়া হল:

function A = f_forlooplogicalindexing( M )
    M = logical(M);
    k = 1:size(M,2);
    N = size(M,1);
    A = cell(N,1);
    for r = 1:N
        A{r} = k(M(r,:));
    end
end

আমি এটি নীচের মানদণ্ডে যুক্ত করেছি, এখানে লুপ-স্টাইল পদ্ধতির তুলনা করা হল:

তুলনা 3

বেঞ্চমার্কিং কোড:

rng(904); % Gives OP example for randi([0,1],3)
p = 2:12; 
T = NaN( numel(p), 7 );
for ii = p
    N = 2^ii;
    M = randi([0,1],N);

    fprintf( 'N = 2^%.0f = %.0f\n', log2(N), N );

    f1 = @()f_arrayfun( M );
    f2 = @()f_mat2cell( M );
    f3 = @()f_accumarray( M );
    f4 = @()f_splitapply( M );
    f5 = @()f_forloop( M );
    f6 = @()f_forlooplogical( M );
    f7 = @()f_forlooplogicalindexing( M );

    T(ii, 1) = timeit( f1 ); 
    T(ii, 2) = timeit( f2 ); 
    T(ii, 3) = timeit( f3 ); 
    T(ii, 4) = timeit( f4 );  
    T(ii, 5) = timeit( f5 );
    T(ii, 6) = timeit( f6 );
    T(ii, 7) = timeit( f7 );
end

plot( (2.^p).', T(2:end,:) );
legend( {'arrayfun','mat2cell','accumarray','splitapply','for loop',...
         'for loop logical', 'for loop logical + indexing'} );
grid on;
xlabel( 'N, where M = random N*N matrix of 1 or 0' );
ylabel( 'Execution time (s)' );

disp( 'Done' );

function A = f_arrayfun( M )
    A = arrayfun(@(r) find(M(r,:)),1:size(M,1),'UniformOutput',false);
end
function A = f_mat2cell( M )
    [i,j] = find(M.');
    A = mat2cell(i,arrayfun(@(r) sum(j==r),min(j):max(j)));
end
function A = f_accumarray( M )
    [val,ind] = ind2sub(size(M),find(M.'));
    A = accumarray(ind,val,[],@(x) {x});
end
function A = f_splitapply( M )
    [r,c] = find(M);
    A = splitapply( @(x) {x}, c, r );
end
function A = f_forloop( M )
    N = size(M,1);
    A = cell(N,1);
    for r = 1:N
        A{r} = find(M(r,:));
    end
end
function A = f_forlooplogical( M )
    M = logical(M);
    N = size(M,1);
    A = cell(N,1);
    for r = 1:N
        A{r} = find(M(r,:));
    end
end
function A = f_forlooplogicalindexing( M )
    M = logical(M);
    k = 1:size(M,2);
    N = size(M,1);
    A = cell(N,1);
    for r = 1:N
        A{r} = k(M(r,:));
    end
end

1
ইতিমধ্যে দেখেছি এবং upvated। :-) এখনও লুইসের অপেক্ষায়; তার জন্য অবশ্যই তার কিছু কালো ম্যাটল্যাব যাদু রয়েছে।
হংসহিরসে

@ હંস হাহ হ্যাঁ যদিও তার স্বাভাবিক ট্র্যাকের ব্যাগ (অন্তর্নিহিত সম্প্রসারণ, চতুর সূচিকর্ম, ...) জিনিসগুলি সাধারণত ম্যাট্রিক হিসাবে রাখে, এখানকার বাধাটি কোষগুলিতে সংক্ষিপ্তসার হিসাবে
দেখছে

1
নোট করুন যে এই সময়গুলি স্পর্শের উপর দৃ strongly়ভাবে নির্ভরশীল M। উদাহরণস্বরূপ, যদি মাত্র 5% উপাদান জনবসতিযুক্ত হয় M = randi([0,20],N) == 20;তবে forলুপটি এখন পর্যন্ত সবচেয়ে ধীর এবং আপনার arrayfunপদ্ধতিটি জিততে পারে।
উইল

@ হ্যান্সহির্স :-) আমার দৃষ্টিভঙ্গিটি accumarrayছাড়াই হত ind2subতবে এটি forলুপের চেয়ে ধীর
লুইস মেন্ডো

2

আপনি arrayfunনীচের মতো চেষ্টা করতে পারেন যা সারিগুলির মধ্যে দিয়ে যায়M

A = arrayfun(@(r) find(M(r,:)),1:size(M,1),'UniformOutput',false)

A =
{
  [1,1] =  2
  [1,2] =

     1   3

  [1,3] =

     1   2   3

}

বা (এর দ্বারা ধীর পদ্ধতির mat2cell)

[i,j] = find(M.');
A = mat2cell(i,arrayfun(@(r) sum(j==r),min(j):max(j)))

A =
{
  [1,1] =  2
  [2,1] =

     1
     3

  [3,1] =

     1
     2
     3

}

1
যদিও arrayfunমূলত একটি লুপ-ইন-ছদ্মবেশ রয়েছে, সুতরাং এটি 1 এর উভয় ফ্রন্টে ব্যর্থ হতে পারে) লুপগুলি এড়ানো এবং 2) দ্রুত হওয়া, ওপি দ্বারা প্রত্যাশিত হিসাবে
ওল্ফি

2

সম্পাদনা : আমি একটি মানদণ্ড যুক্ত করেছি, ফলাফলগুলি দেখায় যে লুপের চেয়ে একটি আরও দক্ষaccumarray


আপনি ব্যবহার করতে পারেন findএবং accumarray:

[c, r] = find(A');
C = accumarray(r, c, [], @(v) {v'});

ম্যাট্রিক্স স্থানান্তরিত হয় ( A') কারণ findকলাম অনুসারে গোষ্ঠীগুলি।

উদাহরণ:

A = [1 0 0 1 0
     0 1 0 0 0
     0 0 1 1 0
     1 0 1 0 1];

%  Find nonzero rows and colums
[c, r] = find(A');

%  Group row indices for each columns
C = accumarray(r, c, [], @(v) {v'});

% Display cell array contents
celldisp(C)

আউটপুট:

C{1} = 
     1     4

C{2} = 
     2

C{3} =
     3     4

C{4} = 
     1     3     5

মাপকাঠি:

m = 10000;
n = 10000;

A = randi([0 1], m,n);

disp('accumarray:')
tic
[c, r] = find(A');
C = accumarray(r, c, [], @(v) {v'});
toc
disp(' ')

disp('For loop:')
tic
C = cell([size(A,1) 1]);
for i = 1:size(A,1)
    C{i} = find(A(i,:));
end
toc

ফলাফল:

accumarray:
Elapsed time is 2.407773 seconds.

For loop:
Elapsed time is 1.671387 seconds.

লুপের জন্য একটি এর চেয়ে বেশি দক্ষ accumarray...


এটি ইতিমধ্যে অবচার্ডন দ্বারা প্রস্তাবিত পদ্ধতিটি কি না?
ওল্ফি

হ্যাঁ, আমি কিছুটা ধীর ছিলাম, আমি আমার পোস্ট পোস্ট করার পরে তার উত্তরটি দেখেছি।
এলিয়াহু হারুন

2

স্বীকৃতি ব্যবহার করে :

M = [0 1 0
     1 0 1
     1 1 1];

[val,ind] = find(M.');

A = accumarray(ind,val,[],@(x) {x});

1
লুটের মতো ল্যাপের জন্য অক্টাভে এবং এমএটিএলবি অনলাইনে কার্যকর সময় প্রায় 2x MM{I} = find(M(I, :))
হংসহিরসে

2
@Hans তোমাকে দেখতে চাই পারে আমার উত্তর
Wolfie

হ্যাঁ, যেহেতু প্রতিটি ঘরের আকার এক নয়, এই সমস্যাটি সম্পূর্ণ ভেক্টরাইজ করা যায় না (বা এমন কোনও কৌশল আছে যা আমি দেখিনি)। এটি কেবলমাত্র একটি সমাধান যা লুপটির জন্য আড়াল করে।
ওচার্ডন

প্রয়োজন নেই ind2sub:[ii, jj] = find(M); accumarray(ii, jj, [], @(x){x})
লুইস মেন্ডো

@ লুইস মেন্ডো ধন্যবাদ, আমি আমার উত্তরটি সম্পাদনা করেছি।
ওচার্ডন

2

আপনি স্ট্রফাইন্ড ব্যবহার করতে পারেন :

A = strfind(cellstr(char(M)), char(1));

আমি (অলসভাবে) এমনকি ডক্সগুলিতেও নজর রাখিনি, তবে এটি কি stringচরগুলির পরিবর্তে প্রকৃত প্রকারগুলি ব্যবহার করা আরও দ্রুত হবে ? সেখানে অত: পর কেন তারা অস্তিত্ব, স্ট্রিং জন্য optimisations প্রচুর আছে ...
Wolfie

@ ওল্ফী আমি মনে করি যে স্ট্রিংয়ের তুলনায় সংখ্যাযুক্ত অ্যারে চর অ্যারের সাথে অনেক বেশি মিলছে তাই সংখ্যার অ্যারে অক্ষরের অ্যারেতে রূপান্তরকরণের চেয়ে স্ট্রিংতে রূপান্তরকরণের চেয়ে আরও সোজা হওয়া উচিত।
rahnema1
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.