2009-04-23 96 views
14

Tôi đã có mã MATLAB chèn điểm n-chiều (n> 1) vào ma trận (myPointMatrix) và đang có suy nghĩ về cách chèn điểm đầu tiên.Gắn thêm vectơ vào ma trận MATLAB trống

Hiện tại, chương trình kiểm tra kích thước của myPointMatrix trước khi chèn điểm. Nếu nó là 1x1, myPointMatrix được đặt bằng điểm hiện tại. Nếu không, điểm hiện tại sẽ được thêm vào. Điều này if -statement chỉ đúng một lần, nhưng được đánh giá mỗi lần tôi chèn một điểm, mà là rất rất thường xuyên.

Xóa if và cố gắng thêm vào myPointMatrix làm cho MATLAB dễ hiểu phàn nàn về kích thước ma trận không nhất quán. Xóa cả hai mã if và cách gọi là myPointMatrix = 0 khiến MATLAB tìm thấy myPointMatrix chưa được xác định. Cũng dễ hiểu.

Làm cách nào để khởi tạo myPointMatrix để tôi có thể xóa số if? Hoặc là có một số giải pháp thông minh khác?

myPointMatrix = 0; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      tempPoint = [x y z]; 
      if (length(myPointMatrix) == 1) 
       myPointMatrix = tempPoint; 
      else 
       myPointMatrix = [myPointMatrix; tempPoint]; 
      end 
     end 
    end 
end 

Trả lời

13

Sử dụng myPointMatrix = []; để khởi tạo ma trận.

Lớn hơn myPointMatrix là, phần bổ sung sẽ chậm hơn. Nó sẽ chậm hơn và chậm hơn, vì mỗi lần bạn chắp thêm một điểm MATLAB sẽ phân bổ một ma trận mới có kích thước mới và sao chép thông tin từ ma trận cũ của bạn + điểm mới của bạn vào ma trận mới.

Sau đó tốt hơn là khởi tạo MyPointMatrix với kích thước cuối cùng và chèn các điểm vào các vị trí nhất định trong ma trận.

+2

+1 cho câu cuối cùng của bạn. Đó là cách hiệu quả nhất để khởi tạo ma trận trong MATLAB. –

3

Tùy chọn tốt nhất của bạn là định vị lại ma trận và sử dụng biến vòng lặp. Điều này sẽ nhanh hơn đáng kể.

limit = 9; 
myPointMatrix = nan((limit+1)^3,3); 

loopVar = 1; 
for x=0:limit 
    for y=0:limit 
     for z=0:limit 
      myPointMatrix(loopVar,:) = [x y z]; 
      loopVar = loopVar + 1; 
     end 
    end 
end 
0

Tôi tin rằng giải pháp bạn đang tìm kiếm là để khởi tạo myPointMatrix để một ma trận với 0 dòng và 3 cột, tức là

myPointMatrix = zeros(0, 3); 

Sau đó, việc chuyển nhượng đầu tiên

myPointMatrix = [myPointMatrix; tempPoint]; 

sẽ làm việc một cách chính xác, cũng như những cái tiếp theo. Một cách tương đương để viết sự phân công là

myPointMatrix(end+1,:) = tempPoint; 

Tuy nhiên cần lưu ý hơn phát triển một ma trận như đó không phải là hiệu quả và, như AnnaR nói, khởi myPointMatrix với kích thước cuối cùng IFS, nếu biết, là một giải pháp tốt hơn.

28

Có một số cách để nối thêm ma trận hoặc vectơ vào bất kỳ ma trận nào, trống hay không. Phần lớn phụ thuộc vào kích thước của ma trận, và tần suất bạn sẽ làm phụ thêm. (Lưu ý rằng ma trận thưa thớt là một động vật hoàn toàn khác nhau. Chúng cần phải được xử lý riêng.)

Giản đồ đơn giản sẽ sử dụng nối. Ví dụ, tôi sẽ tạo một mảng ngẫu nhiên. Trong khi tôi biết rằng một trong những cuộc gọi đến rand sẽ là giải pháp thích hợp ở đây, tôi đang làm nó chỉ cho mục đích so sánh.

n = 10000; 
tic 
A = []; 
for i = 1:n 
    Ai = rand(1,3); 
    A = [A;Ai]; 
end 
toc 

Elapsed time is 9.537194 seconds. 

Xem thời gian cần thiết là hợp lý, cao hơn nhiều so với tôi vừa gọi trực tiếp.

tic,rand(n,3);toc 
Elapsed time is 0.008036 seconds. 

Các cách khác để chắp thêm tương tự đúng lúc. Ví dụ, bạn có thể nối thêm bằng cách lập chỉ mục.

A = []; 
A(end+1,:) = rand(1,3); 
A 
A = 
     0.91338  0.63236  0.09754 

Điều này sẽ tương tự về thời gian để nối thêm thông qua nối. Một điều thú vị cần hiểu là việc thêm các hàng mới vào một mảng là khác nhau một cách tinh tế so với việc thêm các cột mới. Phải mất thêm một chút thời gian để nối thêm một hàng so với một cột. Điều này là do cách các phần tử được lưu trữ trong MATLAB. Việc thêm một hàng mới có nghĩa là các phần tử phải thực sự được xáo trộn trong bộ nhớ.

A = zeros(10000,3); 
B = zeros(3,10000); 

tic,for i = 1:100,A(end+1,:) = rand(1,3);end,toc 
Elapsed time is 0.124814 seconds. 

tic,for i = 1:100,B(:,end+1) = rand(3,1);end,toc 
Elapsed time is 0.116209 seconds. 

Vấn đề với bất kỳ hoạt động nối thêm nào là MATLAB phải tái phân bổ bộ nhớ cần thiết cho A và làm như vậy MỌI lần ma trận tăng kích thước. Do kích thước của A tăng tuyến tính, nên tổng thời gian bắt buộc tăng theo bậc hai với n. Vì vậy, chúng tôi đã tăng gấp đôi kích thước của n, A phát triển động sẽ mất bốn lần để xây dựng. Hành vi bậc hai này là lý do tại sao mọi người nói với bạn trước khi phân bổ mảng MATLAB của bạn khi chúng sẽ được phát triển động. Trong thực tế, nếu bạn nhìn vào các lá cờ mlint trong trình soạn thảo, MATLAB cảnh báo bạn khi nó thấy điều này xảy ra.

Một giải pháp tốt hơn, nếu bạn biết kích thước cuối cùng của A, là phân bổ trước A cho kích thước cuối cùng của nó. Sau đó chỉ cần chỉ mục trong.

tic 
A = zeros(n,3); 
for i = 1:n 
    A(i,:) = rand(1,3); 
end 
toc 

Elapsed time is 0.156826 seconds. 

Trong khi điều này là tốt hơn nhiều so với mảng động phát triển, nó vẫn còn FAR tồi tệ hơn việc sử dụng vectorized của rand. Vì vậy, bất cứ nơi nào có thể, sử dụng các dạng vector hóa các chức năng như thế này.

Vấn đề là, đôi khi bạn chỉ đơn giản là không biết có bao nhiêu yếu tố bạn sẽ kết thúc với. Vẫn còn một số thủ thuật có thể sử dụng để tránh sự tăng trưởng bậc hai khó chịu.

Một mẹo là đoán ở kích thước cuối cùng của A. Bây giờ, hãy sử dụng chỉ mục để chèn giá trị mới vào A, nhưng hãy cẩn thận xem khi nào các mục mới sẽ tràn qua các giới hạn của A. Khi đây chỉ là xảy ra, DOUBLE kích thước của A, nối thêm một khối lớn các số 0 vào cuối. Bây giờ trở lại để lập chỉ mục các phần tử mới vào A. Giữ một số lượng riêng biệt về số lượng phần tử đã được "nối thêm". Vào cuối quá trình này, xóa các phần tử không sử dụng. Điều này tránh được nhiều hành vi bậc hai khó chịu, vì chỉ một vài bước chắp thêm sẽ được thực hiện. (Hãy nhớ rằng, bạn đang tăng gấp đôi kích thước của A khi bạn phải làm một phụ thêm.)

Bí quyết thứ hai là sử dụng con trỏ. Trong khi MATLAB không thực sự cung cấp nhiều khả năng theo cách của con trỏ, một mảng tế bào là một bước theo hướng đó.

tic 
C = {}; 
for i = 1:n 
    C{end+1} = rand(1,3); 
end 
A = cat(1,C{:}); 
toc 

Elapsed time is 3.042742 seconds. 

Điều này mất ít thời gian hơn để hoàn thành hơn mảng được phát triển. Tại sao? Chúng tôi chỉ xây dựng một loạt các con trỏ tới các ô. Một điều tốt đẹp về điều này là nếu mỗi bước chắp thêm có một số hàng biến, nó vẫn hoạt động độc đáo.

Một vấn đề với mảng ô, là nó không phải là khủng khiếp hiệu quả khi có hàng triệu yếu tố để nối thêm. Nó vẫn là một hoạt động bậc hai sau khi tất cả, bởi vì chúng tôi đang phát triển mảng các con trỏ ở mỗi bước.

Giải pháp cho vấn đề đó là sử dụng một hỗn hợp của hai kiểu được hiển thị ở trên. Do đó, xác định từng ô của mảng ô có kích thước vừa phải lớn.Bây giờ, hãy sử dụng lập chỉ mục để thêm các hàng mới của A vào ô. Khi ô hiện tại phải được phát triển lớn hơn bởi bước chắp thêm tiếp theo, chỉ cần thêm một ô mới vào mảng ô.

Một vài năm trước, cuộc thảo luận này xuất hiện trên nhóm tin MATLAB và một số giải pháp dọc theo các dòng này đã được đề xuất. Tôi đã đăng các giải pháp growdata & growdata2 dưới dạng tệp trên MATLAB Central File Exchange. Hàm xử lý chức năng được sử dụng của Growdata2 để giải quyết vấn đề:

tic 
Ahandle = growdata2; 
for i = 1:n 
    Ahandle(rand(1,3)) 
end 
% unpack the object into a normal array 
A = Ahandle(); 
toc 

Elapsed time is 1.572798 seconds. 

Vào thời điểm đó, đó là cách tiếp cận hơi nhanh hơn để sử dụng biến cố định.

tic 
growdata 
for i = 1:n 
    growdata(rand(1,3)) 
end 
A = growdata; 
toc 

Elapsed time is 2.048584 seconds. 

Kể từ đó việc thực hiện xử lý chức năng đã được cải thiện rõ ràng trong MATLAB, do đó, chức năng xử lý hiện nhanh hơn.

Một ưu điểm của các đề án này là chúng sẽ không có hình phạt hiệu suất bậc hai, đồng thời cho phép hàng triệu bước chắp thêm.

Ồ, đây chắc chắn là thông tin nhiều hơn so với yêu cầu ban đầu khi câu hỏi được hỏi. Có lẽ ai đó sẽ nhận được một cái gì đó ra khỏi nó mặc dù.

0

Đây là những gì bạn cần

myPointMatrix=[]; 
for x=0:limit 
for y=0:limit 
for x=0:limit 
    myPointMatrix(:,end+1)=[x y z]; 
end 
end 
end 

nhưng chỉ trong trường hợp đó bạn làm một số hoạt động phi tuyến với [x y z], trước khi bạn gán nó. Nếu không được thì bạn có thể viết những dòng trên như sau:

myPointMatrix=[]; 
myPointMatrix(1,:)=kron([1:limit],ones(1,limit^2)); 
myPointMatrix(2,:)=kron([1:limit^2],ones(1,limit)); 
myPointMatrix(3,:)=kron(ones(1,limit^2),[1:limit]); 

Ở trên là vectorised đầy đủ, mặc dù người ta có thể muốn edit kron.m và thay thế một số find với logical ... nhưng bạn có thể làm điều đó cho mình Tôi cho rằng .. .: D

0
%appending to matlab array "f": 

lfg=[697 770 852 941]; 
hfg=[1209 1336 1477]; 
f=[]; 
for i=1:4, 
    for j=1:3, 
     %f = [ f [lfg(i);hfg(j)] ]; 
     append(f , [lfg(i);hfg(j)]); 
    end 
end 
f 
Các vấn đề liên quan