2011-10-28 58 views
11

Có cách nào để "vectơ" gán một mảng cấu trúc hay không.Mảng cấu trúc Matlab: Phân bổ nhanh

Hiện nay tôi có thể

edges(1000000) = struct('weight',1.0); //This really does not assign the value, I checked on 2009A. 
for i=1:1000000; edges(i).weight=1.0; end; 

Nhưng đó là chậm, tôi muốn làm một cái gì đó giống như

edges(:).weight=[rand(1000000,1)]; //with or without the square brackets. 

Bất kỳ ý tưởng/đề xuất để vectorize nhiệm vụ này, do đó nó sẽ nhanh hơn.

Xin cảm ơn trước.

+2

bài đăng này có thể trợ giúp: http://stackoverflow.com/questions/4166438/how-do-i-define-a-structure-in-matlab/4169216#4169216 – Amro

Trả lời

8

Bạn có thể thử sử dụng chức năng Matlab deal, nhưng tôi thấy nó cần phải tinh chỉnh đầu vào một chút (sử dụng câu hỏi này: In Matlab, for a multiple input function, how to use a single input as multiple inputs?), có thể có điều gì đó đơn giản hơn.

n=100000; 
edges(n)=struct('weight',1.0); 
m=mat2cell(rand(n,1),ones(n,1),1); 
[edges(:).weight]=deal(m{:}); 

Ngoài ra tôi thấy rằng đây không phải là gần càng nhanh càng tốt cho vòng lặp trên máy tính của tôi (~ 0.35s cho thỏa thuận so với ~ 0.05s cho vòng lặp) có lẽ vì các cuộc gọi đến mat2cell. Sự khác biệt về tốc độ bị giảm nếu bạn sử dụng nhiều hơn một lần nhưng nó vẫn có lợi cho vòng lặp for.

+0

Thats tuyệt vời, cảm ơn. – sumodds

+2

Đây là thời gian của tôi. Trên Octave: .17s cho 100K và 1.57s cho 1mil cho phương pháp này và phải mất bao giờ nếu tôi sử dụng cho vòng lặp, như 230s cho 100K. MATLAB 2009B (máy khác/hệ điều hành): 5s/49s sử dụng ở trên và .22s/2.2s sử dụng cho vòng lặp. – sumodds

2

Có điều gì đó yêu cầu bạn đặc biệt sử dụng cấu trúc theo cách này không?

Cân nhắc thay thế mảng cấu trúc của bạn bằng một mảng riêng biệt cho từng thành viên của cấu trúc.

weights = rand(1, 1000); 

Nếu bạn có một thành viên struct đó là một mảng, bạn có thể làm thêm một chiều hướng:

matrices = rand(3, 3, 1000); 

Nếu bạn chỉ muốn giữ cho mọi thứ gọn gàng, bạn có thể đặt những mảng vào một cấu trúc:

edges.weights = weights; 
edges.matrices = matrices; 

Nhưng nếu bạn cần phải giữ một mảng của cấu trúc, tôi nghĩ bạn có thể làm

[edges.weight] = rand(1, 1000); 
+0

Cả hai đều giống nhau. Nhưng, tôi nghĩ rằng tôi cần nó để được mảng của các cấu trúc (có nghĩa là các đối tượng của mảng) và không cấu trúc của mảng (cấu trúc lớn duy nhất của một mảng lớn). Sự khác biệt giữa hai trong MATLAB là gì? Có nghĩa là phân bổ bộ nhớ và nếu vậy, ý nghĩa của nó là gì? – sumodds

+0

Cảm ơn mọi người. :) – sumodds

+1

Sự khác biệt là trong Matlab, một mảng cấu trúc ("struct-organize") là không hiệu quả vì mỗi struct lưu trữ từng trường trong một mảng riêng biệt, vì vậy bạn không thể thực hiện các hoạt động được vector hóa trên chúng. Một cấu trúc của mảng ("tổ chức phẳng") như của Brian sẽ lưu trữ từng trường của nó trong các mảng nguyên thủy tiếp giáp trong bộ nhớ, và các hàm Matlab (nhanh) được vectơ hóa sẽ hoạt động. Đó là một cấu trúc tốt hơn cho Matlab, và thành ngữ hơn. –

7

Bạn chỉ có thể viết:

edges = struct('weight', num2cell(rand(1000000,1))); 
13

Đây là nhanh hơn nhiều so với thỏa thuận hoặc một vòng (ít nhất là trên hệ thống của tôi):

N=10000; 
edge(N) = struct('weight',1.0); % initialize the array 
values = rand(1,N); % set the values as a vector 

W = mat2cell(values, 1,ones(1,N)); % convert values to a cell 
[edge(:).weight] = W{:}; 

Sử dụng dấu ngoặc nhọn bên phải đưa ra một dấu phẩy tách ra giá trị danh sách của tất cả các giá trị trong W (tức là N kết quả đầu ra) và sử dụng dấu ngoặc vuông trên bên phải gán các đầu ra N cho N giá trị trong cạnh (:).

+0

Đẹp! Về mặt thống kê và thực dụng thanh lịch! Sẽ tốt hơn nếu cú ​​pháp Matlab cho phép mở rộng các mảng thành một chuỗi đối số, giống như '{values} {:}'.Đã cố gắng tạo ra một hàm để lấy một danh sách giá trị ô, nhưng dường như nó không giống như gán cho 'varargout' theo cùng cách mà' deal() 'thực hiện haha. – eacousineau

+0

Rất tiếc, tôi đã sử dụng 'mat2cell()' thay vì 'num2cell()'. Đây là hàm: ['cellexpand()'] (https://gist.github.com/eacousineau/9699289#file-cellexpand-m). – eacousineau

+0

Bạn cũng có thể sử dụng các tay cầm ẩn danh: 'cellexpand = @ (x) x {:}; numexpand = @ (x) cellexpand (num2cell (x)); '. Một ví dụ: '[a, b] = numexpand ([1, 2]);'. Ví dụ cụ thể hơn: '[edge.weight] = numexpand ([cạnh.weight] + 50);' – eacousineau

1

Lý do cấu trúc trong ví dụ của bạn không được khởi tạo đúng cách là cú pháp bạn đang sử dụng chỉ địa chỉ phần tử cuối cùng trong mảng cấu trúc. Đối với mảng không tồn tại, phần còn lại của chúng được lấp đầy hoàn toàn bằng các cấu trúc có giá trị mặc định là [] trong tất cả các trường của chúng.

Để làm cho hành vi này rõ ràng, hãy thử làm một mảng ngắn với clear edges; edges(1:3) = struct('weight',1.0) và xem từng ảnh edges(1), edges(2)edges(3).Các yếu tố edges(3)1.0 trong trọng lượng của nó như bạn muốn; những người khác có [].

Cú pháp để khởi tạo hiệu quả một mảng cấu trúc là một trong số các cấu trúc này.

% Using repmat and full assignment 
edges = repmat(struct('weight', 1.0), [1 1000]); 

% Using indexing 
% NOTE: Only correct if variable is uninitialized!!! 
edges(1:1000) = struct('weight', 1.0); % QUESTIONABLE 

Lưu ý 1:1000 thay vì chỉ 1000 khi lập chỉ mục vào mảng cạnh chưa được khởi tạo.

Có sự cố với biểu mẫu edges(1:1000): nếu edges đã được khởi chạy, cú pháp này sẽ chỉ cập nhật giá trị của các phần tử đã chọn. Nếu các cạnh có hơn 1000 phần tử, các phần tử khác sẽ không thay đổi và mã của bạn sẽ bị lỗi. Hoặc nếu edges là một loại khác, bạn có thể gặp lỗi hoặc hành vi lạ tùy thuộc vào loại dữ liệu hiện có của nó. Để an toàn, bạn cần phải thực hiện clear edges trước khi khởi tạo bằng cú pháp lập chỉ mục. Vì vậy, tốt hơn là chỉ thực hiện chuyển nhượng đầy đủ với biểu mẫu repmat.

NHƯNG: Bất kể bạn khởi tạo nó như thế nào, một mảng cấu trúc như thế này sẽ luôn chạy chậm để làm việc với các tập dữ liệu lớn hơn. Bạn không thể thực hiện các hoạt động "vectorized" thực sự trên nó vì các mảng nguyên thủy của bạn được chia thành các mxArrays riêng biệt bên trong mỗi phần tử struct. Điều đó bao gồm việc phân công trường trong câu hỏi của bạn - không thể vector hóa điều đó. Thay vào đó, bạn nên chuyển đổi một struct-of-array như câu trả lời của Brian L gợi ý.

0

Bạn có thể sử dụng một cấu trúc đảo ngược và sau đó làm tất cả những hoạt động mà không cần bất kỳ lỗi nào như thế này

x.E(1)=1; 
x.E(2)=3; 
x.E(2)=8; 
x.E(3)=5; 

và sau đó hoạt động như sau

x.E 

ans = 

    3  8  5 

hay như thế này

x.E(1:2)=2 

x = 

    E: [2 2 5] 

hoặc có thể là

này
x.E(1:3)=[2,3,4]*5 

x = 

    E: [10 15 20] 

Nó thực sự nhanh hơn for_loop và bạn không cần các chức năng lớn khác để làm chậm chương trình của bạn.

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