How do I efficiently create a matrix that combines specific columns from pairs of odd and even rows into one, while excluding all columns with NaN values?

2 views (last 30 days)
I have a matrix of the format:
[(time 1) (number of pairs in time 1)
(pair 1x) (pair 1y) (pair 2x) (pair 2y) (pair 3x) (pair 3y)
(time 2) (number of pairs in time 2)
(pair 1x) (pair 1y) (pair 2x) (pair 2y)]
where the time increases with a set interval. It should be noted that NaN’s fill up the ‘elements’ that do not have numerical data points. So, a sample matrix would look like:
[1, 3, NaN, NaN, NaN, NaN;
1, 50, 20, 35, 3, 26;
2, 2, NaN, NaN, NaN, NaN;
2, 55, 21, 36, NaN, NaN]
The matrix I want has the format:
(pair 1x) (pair 1y) (time 1)
(pair 2x) (pair 2y) (time 1)
(pair 3x) (pair 3y) (time 1)
(pair 1x) (pair 1y) (time 2)
(pair 2x) (pair 2y) (time 2)
I essentially get the data from each even row in the original matrix and insert each pair of data AND the time from the row above it into a new 3-column matrix. The NaN’s aren’t included. So, for the example above, I have:
[1, 50, 1;
20, 35, 1;
3, 26, 1;
2, 25, 2;
21, 36, 2]
I managed to get this done using two for loops, but that method is REALLY inefficient as I have 1000s of rows of data in a 44-column matrix. The function that I have is:
function [prepared_matrix_with_x_y_t] = prepare_matrix(data)
number_of_columns_in_odd_rows = 2; %to delete NaN columns after extracting odd rows
column_with_number_of_pairs = 2; %the column number of the column that has the number of pairs
coordinates = data(2:2:end,:);
x = coordinates(:,1:2:end);
y = coordinates(:,2:2:end);
number_of_columns_in_odd_rows_plus_one = number_of_columns_in_odd_rows + 1;
time_and_number_of_pairs = data(1:2:end,:);
time_and_number_of_pairs(:, number_of_columns_in_odd_rows_plus_one:end) = [];
size_of_time_and_number_of_pairs = size(time_and_number_of_pairs);
number_of_time_intervals = size_of_time_and_number_of_pairs(1); % can make MORE efficient, but using time_and_number_of_pairs below anyway
prepared_matrix_with_x_y_t = [];
for i=1:number_of_time_intervals
number_of_pairs = time_and_number_of_pairs(i, column_with_number_of_pairs);
for j=1:number_of_pairs
xj = x(i, j);
yj = y(i, j);
if (isnan(xj) || isnan(yj))
continue;
else
row_to_add = [xj yj i];
prepared_matrix_with_x_y_t = [prepared_matrix_with_x_y_t; row_to_add];
end
end
end
end
Do you have any suggestions on how I can effectively handle this problem? I am new to MATLAB (as you may be able to tell), and I am certain that I am missing out on something very simple. Additionally, playing around with arrayfun and reshape got me nowhere. Thank you for your time!

Accepted Answer

Guillaume
Guillaume on 13 Feb 2016
It's actually extremely easy:
  1. reshape the pair rows into a two column matrix
  2. remove the rows with nan
  3. repelem the 1st column of the time rows using the 2nd column of the time row
  4. concatenate the two results
m = [1, 3, NaN, NaN, NaN, NaN;
1, 50, 20, 35, 3, 26;
2, 2, NaN, NaN, NaN, NaN;
2, 55, 21, 36, NaN, NaN];
pairs = reshape(m(2:2:end, :)', 2, [])'; %have to transpose the matrix before and after the reshape since matlab works columnwise
pairs(any(isnan(pairs), 2), :) = [];
times = repelem(m(1:2:end, 1), m(1:2:end, 2));
out = [pairs, times]

More Answers (0)

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!