4
votes

I have a matrix which has the following form:

M = 
[1 4 56 1;
 1 3 5  1;
 1 3 6  4;
 2 3 5  0;
 2 0 0  0;
 3 1 2  3;
 3 3 3  3]

I want to split this matrix based on the number given in the first column. So I want to split the matrix into this:

A = 
[1 4 56 1;
 1 3 5  1;
 1 3 6  4]

B = 
[2 3 5  0;
 2 0 0  0]

C =
[3 1 2  3;
 3 3 3  3]

I tried this by making the following loop, but this gave me the desired matrices with rows of zeros:

for i = 1:length(M)
    if (M(i,1) == 1)
        A(i,:) = M(i,:);
    elseif (M(i,1) == 2)
        B(i,:) = M(i,:);
    elseif (M(i,1) == 3)
        C(i,:) = M(i,:);
    end
end

The result for matrix C is then for example:

C = 
[0 0 0 0;
 0 0 0 0;
 0 0 0 0;
 2 3 5 0;
 2 0 0 0]

How should I solve this issue?

Additional information:
The actual data has a date in the first column in the form yyyymmdd. The data set spans several years and I want to split this dataset in matrices for each year and after that for each month.

2

2 Answers

8
votes

You can use arrayfun to solve this task:

M = [
1 4 56 1;
 1 3 5  1;
 1 3 6  4;
 2 3 5  0;
 2 0 0  0;
 3 1 2  3;
 3 3 3  3]


A = arrayfun(@(x) M(M(:,1) == x, :), unique(M(:,1)), 'uniformoutput', false)

The result A is a cell array and its contents can be accessed as follows:

>> a{1}

ans =

     1     4    56     1
     1     3     5     1
     1     3     6     4

>> a{2}

ans =

     2     3     5     0
     2     0     0     0

>> a{3}

ans =

     3     1     2     3
     3     3     3     3

To split the data based on an yyyymmdd format in the first column, you can use the following:

yearly = arrayfun(@(x) M(floor(M(:,1)/10000) == x, :), unique(floor(M(:,1)/10000)), 'uniformoutput', false)

monthly = arrayfun(@(x) M(floor(M(:,1)/100) == x, :), unique(floor(M(:,1)/100)), 'uniformoutput', false)
2
votes

If you don't know how many outputs you'll have, it is most convenient to put the data into a cell array rather than into separate arrays. The command to do this is MAT2CELL. Note that this assumes your data is sorted. If it isn't use sortrows before running the code.

%# count the repetitions
counts = hist(M(:,1),unique(M(:,1));

%# split the array
yearly = mat2cell(M,counts,size(M,2))

%# if you'd like to split each cell further, but still keep
%# the data also grouped by year, you can do the following
%# assuming the month information is in column 2
yearByMonth = cellfun(@(x)...
    mat2cell(x,hist(x(:,2),unique(x(:,2)),size(x,2)),...
    yearly,'uniformOutput',false);

You'd then access the data for year 3, month 4 as yearByMonth{3}{4}

EDIT If the first column of your data is yyyymmdd, I suggest splitting it into three columns yyyy,mm,dd, like below, to facilitate grouping afterward:

ymd = 20120918;
yymmdd = floor(ymd./[10000 100 1])
yymmdd(2:3) = yymmdd(2:3)-100*yymmdd(1:2)