Sushil Surwase
Sushil Surwase

Reputation: 35

How to get multiple rows from a column in efficient way?

(Want an efficient alternative for the following Matlab code.) I want to obtain a matrix 'data' of size (N-60*60) from the below mentioned Matlab code. With for-loop and N with a very large value, it takes high computational time. Could someone please recommend the faster way to obtain the data matrix.

N=10000;
a = randn(N,1);
order = 60;
for i=order:length(a)
    data(i-order+1,:) = a([i:-1:i-order+1])';
end

Thanks!

Upvotes: 0

Views: 92

Answers (1)

SamDickinson
SamDickinson

Reputation: 33

As Sardar said pre-allocating data will give you the largest improvement. However you can also remove the for loop using clever indexing. The comments should explain most of what I did.

n = 1e6;
% Modified a to be a incrementing list to better understand how data is
% constructed
a = (1:n)';
order = 60;

%% Original code with pre allocation added
data = zeros(n-order+1, order);
for i = order:length(a)
    data(i-order+1,:) = a([i:-1:i-order+1])';
end

%% Vectorized code
% The above code was vectorized by building a large array to index into
% the a vector with.

% Get the indicies of a going down the first column of data
%   Went down the column instead of across the row to avoid a transpose
%   after the reshape function
idx = uint32(order:n);

% As we go across the columns we use the same indexing but -1 as we move to
% the right so create the simple offset using 0:-1:1-order. Then expand to
% the correct number of elements using kron
offset = kron(uint32(0:-1:1-order), ones(1, n-order+1, 'uint32'));

% Replicate the column indexing for how many columns we have and add the
% offset
fullIdx = repmat(idx, 1, order) + offset;

% Then use the large indexing array to get all the data as a large vector
% and then reshape it to the matrix
data2 = reshape(a(fullIdx), n-order+1, order);

% idx, offset, and fullIdx will take up a fair amount of memory so it is
% probably best to clear them
clear idx offset fullIdx;

assert(isequal(data, data2));

Note: The use of uint32 is not strictly necessary however it does save on memory usage and does give a small performance improvement.

Upvotes: 0

Related Questions