Matlab: converting a matrix to a 1D array with overlapping elements added together

Here's an example of a matrix:

x=[1,2,3,4,5;6,7,8,9,10;11,12,13,14,15]'; % 1:5 in 1st column, 6:10 in 2nd etc

      

so I:

x=
1 6  11
2 7  12
3 8  13
4 9  14
5 10 15

      

I want to align the top half of the items in a given column (not including the middle item) with the bottom half of the previous column by adding items to the overlap. The first and last column will obviously be an exception (the first column has no previous column and does not add anything to the last column)

in the simplified example above, I rewrote the line to show which numbers overlap for clarity:

x=[1,2,3,4,5;
         6,7,8,9,10;
               11,12,13,14,15]';

      

hence, I want the result to be:

y=[1;2;3;4+6;5+7;8;9+11;10+12;13;14;15];

      

Now this is just a very simple example. The resulting code should scale well and work efficiently with big data. The matrix size will probably be roughly 120000x600 and I think the resulting 1D array will be roughly 37000000x1

+3


source to share


4 answers


Answer to original question (add shifted lines):

This can be done as follows:

code:



n = ceil(size(x,2)/2);
ind = bsxfun(@plus, 1:size(x,2), (0:size(x,1)-1).'*n); %'// step 1. Valid for any x
y = accumarray(ind(:), x(:));                          % // step 2. Depends on x

      

Answer to editable question (add shifted columns):

Move x

and proceed as follows:

x = x.';
n = ceil(size(x,2)/2);
ind = bsxfun(@plus, 1:size(x,2), (0:size(x,1)-1).'*n);for any x
y = accumarray(ind(:), x(:));

      

+5


source


Additions can be calculated by adding one matrix, after which you reorder the result.

The addition of the matrix matrix has the form

x = [1  2  3  4  5;
     6  7  8  9  10;
     11 12 13 14 15];

A = [4 5; 9 10] + [6 7; 11 12]

      

The first and last rows and middle column are unchanged. This gives the following code:



x=[1,2,3,4,5;6,7,8,9,10;11,12,13,14,15]';

x = x.';

n = ceil(size(x,2)/2);
m = floor(size(x,2)/2);

A = [x(1:(end-1),(m+1):n) x(2:end,1:m)+x(1:(end-1),(n+1):end)]';

y = [x(1,1:m) A(:)' x(end,(m+1):end)];

      

Result y = 1 2 3 10 12 8 20 22 13 14 15

For x=rand(120000,600)

it takes 1.3 seconds
+1


source


This could be one approach -

%// Get size
[n,m] = size(x)

%// Indices of first overlapping elements and its length
first_overlap = ceil(n/2)+1:n
overlap_len = numel(first_overlap)

%// Store the last elements of overlapping length to be appended at final stage
rem_ele = x(end-numel(first_overlap)+1:end)

%// Indices of overlapping elements across all columns
idx = bsxfun(@plus,first_overlap(:),[0:m-2]*n)

%// Do summations of overlaps and store back tto the next group of overlaps
x(idx(:)+overlap_len) = x(idx(:)) + x(idx(:)+overlap_len)

%// Remove elements from the previous overlaps
x(end-overlap_len+1:end,:)=[]

%// Output array after appending rem_ele to column vector version of modified x
out = [x(:) ; rem_ele(:)]

      

0


source


This is probably not the most scalable solution, but probably readable and intuitive:

% Split the matrix into three parts
left  = x(:,1:floor(end/2));
mid   = x(:,floor(end/2)+1:ceil(end/2));
right = x(:,ceil(end/2)+1:end);

% Extend the middle part by one, note that this works even if mid is empty
mid(end+1,:) = nan;

% Construct a new matrix by summing up left and right parts
X = [left(1,:); ...
     left(2:end,:) + right(1:end-1,:); ...
     right(end,:)];

% Add the midpoints back
X=[X, mid].';

% Reshape into vector and remove the possible extra mid point 
y = X(1:end-~isempty(mid));

      

0


source







All Articles