Clear Filters
Clear Filters

How can I split a matrix into N different parts?

33 views (last 30 days)
I have a 120x30 matrix of data points, how can I split the matrix into nine equal parts of 400 data chunks and store them as separate matrices?
  2 Comments
Stephen23
Stephen23 on 20 Jul 2017
Edited: Stephen23 on 20 Jul 2017
"how can I split the matrix into nine equal parts of 400 data chunks and store them as separate matrices?"
While this is possible it would make your code slow, buggy, inefficient, hard to read, hard to debug, etc, etc. Here is what the MATLAB documentation says about magically creating variable names like that: "A frequent use of the eval function is to create sets of variables such as A1, A2, ..., An, but this approach does not use the array processing power of MATLAB and is not recommended. The preferred method is to store related data in a single array."
As you can read, the much better alternative is use one array and indexing. Indexing is simple, very efficient, neat, easy to read, easy to debug, etc, etc.
You can read more explanations and discussions here:
Just use indexing: simple, efficient, neat, easy to debug, easy to understand,... Or you could split the array into a cell array of numeric arrays: see mat2cell and num2cell.
Stephen23
Stephen23 on 24 Jul 2017
Edited: Stephen23 on 24 Jul 2017
Note to browsers of this thread: If you want to write fast, neat, efficient, and robust code then scroll down to Jan Simon's answer. It is not required to use slow and buggy code to solve this task.

Sign in to comment.

Accepted Answer

John BG
John BG on 20 Jul 2017
Edited: John BG on 20 Jul 2017
Hi matlabkid602
to split 120x30 matrix into chunks of 400 pixels, there are many different ways, like for instance selecting 400 random points and removing the just selected points from the matrix iterating until no points left, or using masks or patterns for similar elimination.
One can also sequentially pull strings of 400 pixels at a time, like Jan has concisely shown above, with a resulting cell.
For rectangular matrices, it is reasonable to aim at splitting the matrix into smaller rectangle chunks.
The following splits your 3600 points matrix into sub-rectangles of 400 points each
1.
loading example matrix
clear all;clc;close all
A=imread('001.jpg');
imshow(A)
2.
Scaling down to 120x30 pixels
the rulers are in pixels
.
.
3.
Simplifying to single RGB layer, made available in attached image 003.jpg
A=imread('003.jpg')
A=A(:,:,1);
fh=figure(1);imshow(A);ax=gca
fh.MenuBar='none'
fh.ToolBar='none'
fh.Position=[500 500 1440 360]
ax.OuterPosition=[0 0 1 1]
.
3.
Finding out how many rectangle chunks have 400 pixels area
L1=120 % x, horizontal
L2=30 % y, vertical
A0=400 % target area
K=L1*L2/A0 % how many equal area chunks, K is your N
x=[1:10]
y=[1:10]
[X,Y]=meshgrid(x,y)
L=(L1./X).*(L2./Y);
figure(4);S=surf(L)
.
N1=find(S.ZData==A0)'
% N1 =
% 9 23 81
It turns out vertical and horizontal slicing may also be possible
L(N1)
% =
% 400 400 400
% the slicing
a=X(N1)
% =
% 1 3 9
b=Y(N1)
% =
% 9 3 1
But since it's reasonable to assume that data points cannot be split, for the case pixels, the horizontal and vertical slicing cases a=1 b=9, a=9 a=1 have to be excluded.
Choosing the elements that are neither 1 or K
a=3;b=3
4.
Generating variable containing the rectangles
La=[1:L1/a:L1];
Lb=[L2:L2/b:L2];
D=zeros(L2/b,L1/a,K);
s=1
for j=1:1:b
for i=1:1:a
n2=[(j-1)*L2/b+[1:1:L2/b]]
n1=[(i-1)*L1/a+[1:1:L1/a]]
D(:,:,b*(j-1)+i)=A(n2,n1);
end
end
D=uint8(D) % for imshow to work correctly
close all;
for s=1:1:K
figure(s);imshow(D(:,:,s));
fh=figure(s);imshow(D(:,:,s));ax=gca
fh.MenuBar='none'
fh.ToolBar='none'
fh.Position=[500 500 480 120]
ax.OuterPosition=[0 0 1 1]
end
fh=figure(10)
for s=1:1:K
subplot(b,a,s);imshow(D(:,:,s))
end
.
5.
Dynamic generation of variables
Some people like the dynamic generation of variables with for instance command e evalin, some other people don't like such approach.
evalin is a very powerful command and I am using it here to generate the separate matrices you have asked for
.
str1=repmat('Chunk_',K,1) % building strings for evalin
N0=num2str(100+[1:1:K]');N0(:,1)=[]
N1=repmat('=D(:,:,',K,1)
N2=repmat(')',K,1)
str2=[str1 N0 N1 num2str([1:1:K]') N2]
for s=1:1:K % running evalin
L2=str2(s,:);
evalin('base',L2);
end
.
Now you have a list of smaller matrices containing the rectangular chunks
Chunk_01
Chunk_02
Chunk_03
Chunk_04
Chunk_05
Chunk_06
Chunk_07
Chunk_08
Chunk_09
if you find this answer useful would you please be so kind to consider marking my answer as Accepted Answer?
To any other reader, if you find this answer useful please consider clicking on the thumbs-up vote link
thanks in advance
John BG
  1 Comment
Jan
Jan on 22 Jul 2017
Edited: Jan on 22 Jul 2017
The shown code works in the command window only, because evalin('base') creates the variables in the Base-WorkSpace. Hundreds of threads in this forum explain the drawbacks of the dynamic creation of variables exhaustively. See Stephen's comment above.

Sign in to comment.

More Answers (2)

Jan
Jan on 20 Jul 2017
Edited: Jan on 22 Jul 2017
Storing in separate matrices might be a bad idea. Why not using the matrix itself?
data = rand(120, 30);
data9 = reshape(data, [], 9);
dataC = cell(1, 9);
for iC = 1:9
dataC{iC} = data9(:, iC);
end
Here you get the different vectors as a cell array. But I'd prefer to work with data9: The i.th block is data9(:, i).
[EDITED] You can split the matrix to a 3x3 set uf submatrices efficiently without nested loops by:
sM = size(M);
c = reshape(M, sM(1) / 3, 3, sM(2) / 3, 3);
M33 = permute(reshape(c, 4, 3, 3, 3), [1, 3, 2, 4]);
M9 = reshape(M33, [4, 3, 9]);
Now the matrix is divived in 3 x 3 submatrices of the same size, which can be addressed by M9(:, :, i) with the index 1 to 9 or by using M33(:, :, x, y) with x and y going from 1 to 3.
This is much faster then nested loops.
  2 Comments
Kodavati Mahendra
Kodavati Mahendra on 17 Jan 2018
Edited: Kodavati Mahendra on 17 Jan 2018
regarding the edit you made, c has more than 4*3*3*3 elements.
sM = size(M);
M33 = permute(reshape(M,sM(1)/3,3,sM(2)/3,3),[1,3,2,4]);
M9 = reshape(M33, [sM(1)/3,sM(2)/3,9]);
Is this the correct code or did I misunderstand it?
Jan
Jan on 17 Jan 2018
@Kodavati Mahendra: This looks fine.

Sign in to comment.


Image Analyst
Image Analyst on 22 Jul 2017
You didn't specify how you wanted the matrix split up, since neither 120 nor 30 is a multiple of 9. So I just made 9 vectors taking the data column by column from upper left to lower right. Try this:
data = rand(120,30); % Sample data
% Now split up into 9 row vectors.
m1 = data(1:1*400);
m2 = data(1*400+1 : 2*400);
m3 = data(2*400+1 : 3*400);
m4 = data(3*400+1 : 4*400);
m5 = data(4*400+1 : 5*400);
m6 = data(5*400+1 : 6*400);
m7 = data(6*400+1 : 7*400);
m8 = data(7*400+1 : 8*400);
m9 = data(8*400+1 : 9*400);
If those aren't the 9 arrays you were thinking of them clarify the location of where the elements for each matrix are supposed to come from.

Categories

Find more on Variables 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!