2009-05-06 17 views
9

Giả sử, trong MATLAB, rằng tôi có một ma trận, A, mà yếu tố này là 0 hoặc 1.Biến một ma trận nhị phân thành một vector của các chỉ số khác không cuối cùng trong một nhanh, thời trang vectorized

Làm thế nào để tôi nhận được một vectơ của chỉ số của phần tử khác không phải của mỗi cột theo cách nhanh hơn, được vector hóa?

tôi có thể làm

[B, I] = max(cumsum(A));

và sử dụng I, nhưng là có một cách nhanh hơn? (Tôi giả sử cumsum sẽ chi phí một chút thời gian ngay cả khi tổng hợp 0 ​​và 1).

Edit: Tôi đoán rằng tôi vectorized thậm chí nhiều hơn tôi cần nhanh chóng - loop ông Fooz' là rất tốt nhưng mỗi vòng lặp trong MATLAB dường như chi phí tôi rất nhiều trong thời gian ngay cả khi nó là nhanh chóng gỡ lỗi.

Trả lời

7

Như được hiển thị bởi Mr Fooz, đối với các vòng lặp có thể khá nhanh ngay bây giờ với các phiên bản MATLAB mới hơn. Tuy nhiên, nếu bạn thực sự muốn có mã vectorized nhỏ gọn, tôi sẽ đề nghị cố gắng này:

[B,I] = max(flipud(A)); 
I = size(A,1)-I+1; 

Đây là câu trả lời nhanh hơn CUMSUM dựa trên của bạn, nhưng vẫn không khá nhanh như tùy chọn lặp lại của ông Fooz.

Hai điều bổ sung để xem xét:

  • gì kết quả nào bạn muốn nhận được cho một cột mà không có người ở trong đó ở tất cả? Với tùy chọn ở trên tôi đã cung cấp cho bạn, tôi tin rằng bạn sẽ nhận được chỉ mục có kích thước là (A, 1) (tức là số hàng trong A) trong trường hợp này. Đối với lựa chọn của bạn, tôi tin rằng bạn sẽ nhận được 1 trong trường hợp này, trong khi tùy chọn lồng vào vòng lặp từ Mr Fooz sẽ cung cấp cho bạn 0,

  • Tốc độ tương đối của các tùy chọn này sẽ thay đổi tùy theo kích thước của A và số lượng không phải số không bạn mong đợi.

+0

Ý tưởng thông minh. Thật không may, đó là khoảng 5x chậm hơn so với vòng lặp và tìm thấy. –

+0

Đó là kinda kết quả tôi mong đợi: nhanh hơn CUMSUM nhưng vẫn chậm hơn looping ... mặc dù tất cả vẫn còn phụ thuộc vào kích thước và điền phần A (mà OP đã không thực sự xác định). – gnovice

10

Nhanh chóng là những gì bạn nên lo lắng, không nhất thiết phải vector hóa đầy đủ. Các phiên bản gần đây của Matlab là nhiều hơn thông minh hơn về việc xử lý vòng lặp hiệu quả. Nếu có một cách vectorized nhỏ gọn để thể hiện một cái gì đó, nó thường là nhanh hơn, nhưng vòng lặp không nên (luôn luôn) được lo sợ như họ từng là.

clc 

A = rand(5000)>0.5; 
A(1,find(sum(A,1)==0)) = 1; % make sure there is at least one match 

% Slow because it is doing too much work 
tic;[B,I1]=max(cumsum(A));toc 

% Fast because FIND is fast and it runs the inner loop 
tic; 
I3=zeros(1,5000); 
for i=1:5000 
    I3(i) = find(A(:,i),1,'last'); 
end 
toc; 
assert(all(I1==I3)); 

% Even faster because the JIT in Matlab is smart enough now 
tic; 
I2=zeros(1,5000); 
for i=1:5000 
    I2(i) = 0; 
    for j=5000:-1:1 
    if A(j,i) 
     I2(i) = j; 
     break; 
    end 
    end 
end 
toc; 
assert(all(I1==I2)); 

Trên R2008a, Windows, x64, phiên bản cumsum mất 0,9 giây. Vòng lặp và tìm phiên bản mất 0,02 giây. Phiên bản vòng lặp đôi chỉ mất 0,001 giây.

EDIT: Cách nào nhanh nhất phụ thuộc vào dữ liệu thực tế. Vòng lặp kép mất 0,05 giây khi bạn thay đổi 0,5 đến 0,999 (vì phải mất nhiều thời gian hơn để đạt đến điểm ngắt; trung bình). cumsum và vòng lặp & tìm việc triển khai có tốc độ phù hợp hơn.

CHỈNH SỬA 2: Giải pháp lật ngược của gnovice rất thông minh. Thật không may, trên máy thử nghiệm của tôi phải mất 0,1 giây, do đó, nó nhanh hơn nhiều so với cumsum, nhưng chậm hơn so với các phiên bản looped.

+0

Chà, chất lượng của vòng lặp của bạn làm cho vòng lặp nhanh hơn hoặc lặp lại như vậy sẽ là cách nhanh nhất để thực hiện bất kỳ hoạt động tương tự nào? –

+1

Khi tôi bắt đầu viết các ví dụ, tôi dự kiến ​​vòng lặp kép sẽ chậm nhất và lặp lại và tìm nhanh nhất. Khi vòng lặp bên trong phải chạy để hoàn thành, nó hơi chậm (xem chỉnh sửa 2). Những ngày này, Matlab thực hiện việc biên dịch chính xác mọi chức năng. Điều này làm cho vòng lặp nhanh hơn nhiều (nhưng có một số hậu quả bất ngờ cho những người thích sử dụng EVAL). Nói chung, vectorization vẫn còn tốt hơn để sử dụng nếu bạn có thể làm điều đó mà không làm thêm công việc (các giải pháp flipud và cumsum được vectorized nhưng làm thêm). –

+0

Một điều thú vị cần lưu ý là trong nhiều trường hợp các phiên bản gần đây của Matlab là thông minh về phân tích biểu thức. E = A. * B. * C. * D; sẽ được thực hiện mà không có thêm thời gian, yếu tố-by-element, tương tự như cách bạn sẽ làm điều đó nếu bằng tay viết các hoạt động trong C. Với hỗ trợ đa lõi kích hoạt, Matlab cố gắng tìm các phần tách rời của hoạt động và trang trại chúng ra khác nhau Lõi CPU. Tôi không biết nếu nó đủ thông minh để phân chia lặp lặp lại độc lập giữa các cuộc gọi. Đối với các bài kiểm tra tôi đã làm, tôi đã sử dụng một Core 2 Duo proc. –

Các vấn đề liên quan