How do I split a matrix into an array based on the elements in a single column without iterating through each row?

3 views (last 30 days)
The matrix has the form:
0.1, 1, 0.2, 0.3, 0.4, 0.5
0.1, 1, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 3, 0.2, 0.3, 0.4, 0.5
0.1, 3, 0.2, 0.3, 0.4, 0.5
0.1, 3, 0.2, 0.3, 0.4, 0.5
0.1, 4, 0.2, 0.3, 0.4, 0.5
I want to create an array with all rows that have the same element for the second column, into a different layer. For example:
Array(:, :, 2) should = [0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5];
and
Array(:, :, 4) should = [0.1, 4, 0.2, 0.3, 0.4, 0.5];
However, I have 100,000s of rows in the matrix and so have to be as efficient as possible (and so not iterate through all rows of the matrix more than once). I am trying to understand how to approach this problem conceptually. I tried several approaches with my novice experience handling MATLAB. I tried using bsxfun(@eq…) in a loop from 1:4 to find the rows whose second column equal the number being iterated. I tried to get the number of rows with each number into an array (‘array_number_of_rows’) (example: there are 4 rows with ‘2’ in the second column above) and then using this to trying to create an array. Example:
array_number_of_rows = [1 2
2 4
3 3
4 1];
Then I’d loop from 1:4, trying to assign rows from the matrix:
count = 1;
for i=1:4
Array(:, :, i) = [matrix(count: array_number_of_rows(i, 2), :];
count = count + array_number_of_rows(i, 2);
end
(note: this isn’t the actual code I used) I think that the problem is that the number of rows for each number isn’t the same.
I also tried using the Boolean values from bsxfun as indices for the matrix and failed horribly (dimension issues again – I tried to counter this by using logical(), and filling with ones/zeroes and even by reshaping the matrices in the loop).
After several hours, I ultimately figured that I've got my core understanding of the problem wrong. Would someone mind clarifying whether my approaches were in the right direction, or whether I am missing some simple solution to the problem? Thank you for your time!
  2 Comments
Ingrid
Ingrid on 11 Feb 2016
I think you have partially answered your own question. The matrices do not have the same dimension so you cannot store them in the same array as you want. I think you might want to go into the direction of a cell array such that
Array{2} should = [0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5
0.1, 2, 0.2, 0.3, 0.4, 0.5];
and
Array{4} should = [0.1, 4, 0.2, 0.3, 0.4, 0.5];
does this help you any further?

Sign in to comment.

Accepted Answer

Matt J
Matt J on 11 Feb 2016
Edited: Matt J on 11 Feb 2016
As Ingrid commented, you have no choice but to accept a cell array as a way of storing these differently sized arrays. You can construct such a cell array as follows,
[~,~,j]=unique(A(:,2));
Array = accumarray(j,(1:length(j)).', [], @(k) {A(k,:)})
where A is your original matrix.

More Answers (1)

Jos (10584)
Jos (10584) on 11 Feb 2016
A single line of code using arrayfun:
Array = arrayfun(@(k) A(A(:,2)==k,:), unique(A(:,2)), 'un', 0)
  2 Comments
Guillaume
Guillaume on 11 Feb 2016
Edited: Guillaume on 11 Feb 2016
Another option is to use the findgroup and splitapply workflow introduced in 2015b:
Array = splitapply(@(m) {m}, A, findgroups(A(:, 2))
This is probably the slowest solution of them all (but possibly the easiest to read).
I suspect that accumarray is possibly the fastest. The arrayfun solution has the downside that you're scanning the grouping column multiple times (once in the call to unique and then once for each unique value)
TribalPrince
TribalPrince on 13 Feb 2016
Thank you very much, everyone! I accepted the accumarray answer because it indeed was the fastest (about 8x). For splitapply, it was about 9x.

Sign in to comment.

Categories

Find more on Matrices and Arrays 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!