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ù.
+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. –