Repeat each row of a matrix - matlab

I have variable A of size m by n. I want to generate B of size m by m*n, such as below example.
Example:
A = [1 2 3;
4 5 6;
7 8 9]
Should result with
B = [1 2 3 4 5 6 7 8 9;
1 2 3 4 5 6 7 8 9;
1 2 3 4 5 6 7 8 9]
Is there any way to do that without using loop? m and n is variable.

You should use the repmat Matlab funtion:
B = repmat(A,M,N) creates a large matrix B consisting of an M-by-N
tiling of copies of A. The size of B is [size(A,1)*M, size(A,2)*N].
The statement repmat(A,N) creates an N-by-N tiling.
For your specific case one solution may be:
A=A';
B=repmat(A(:)',3,1);
And for the general case one solution may be:
A_aux=reshape(A',1,size(A,1)*size(A,2));
B=repmat(A_aux,size(A,1),1);

Repmat is indeed the way to go here, as mentioned by #Nerea. This solution should give the same answer as his, but personally I consider it to be a bit more elegant:
B=repmat(reshape(A',1,[]),size(A,1),1);

To include a quite fast bsxfun solution:
A = [1 2 3 4;
5 6 7 8;
9 10 11 12]
A = A.' %'
B = bsxfun(#plus,zeros(size(A,2),1),A(:).')
or use kron, but its surely slower:
A = A.'
B = kron(A(:),ones(1,size(A,2))).'
B =
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12
1 2 3 4 5 6 7 8 9 10 11 12

No repmats
[m n] = size(A);
B = ones(m,1) * reshape( A.', 1, [] );

One approach
with repmat, reshape and permute combo!
out = repmat(reshape(permute(A,[3 2 1]),1,[]),size(A,1),1,1);
or Another approach without reshape but becomes a 2 liner
out1 = permute(A,[3 2 1]);
out = repmat(out1(:).',size(A,1),1,1);

Related

Reshape 59x16 double into 236x4?

How can I reshape a matrix in MATLAB, preferably using reshape?
A simple matrix setup:
A = [1 4 7 10; 2 5 8 11; 3 6 9 12]
that I want to reshape into
B = [1 4; 2 5; 3 6; 7 10; 8 11; 9 12]
I've tried numerous settings of reshape, but I cannot figure it out.
1 2 3 4
5 6 7 8
reshaped into
1 2
5 6
3 4
7 8
You can use reshape and permute:
reshape(permute(reshape(A,size(A,1),2,[]),[1 3 2]),[],2)
Thanks to #LuisMendo that suggests a modification to the answer to avoid depending on the size of A.
If I understand the transformation properly it is:
A = [1 4 7 10; 2 5 8 11; 3 6 9 12]
B = A(:,1:end/2);
B = [B;A(:,end/2+1:end)];
Is this correct?
EDIT:
Or the general case:
function [B] = elefaaant(A,n)
[a,b] = size(A);
if mod(b,n) ~= 0
error('Cannot reshape')
end
B = zeros(a*n,b/n);
fac = b/n;
for i = 1:n
B((i-1)*a+1:i*a,:) = A(:,(i-1)*fac+1:i*fac);
end
B = A(:,1:end/2);
B = [B;A(:,end/2+1:end)];
C = B(:,1:end/2);
C = [C;B(:,end/2+1:end)];
Maybe it can be done in a simpler way, but seems to work.

How to align vectors with asynchronous time stamp in matlab?

I would like to align and count vectors with different time stamps to count the corresponding bins.
Let's assume I have 3 matrix from [N,edges] = histcounts in the following structure. The first row represents the edges, so the bins. The second row represents the values. I would like to sum all values with the same bin.
A = [0 1 2 3 4 5;
5 5 6 7 8 5]
B = [1 2 3 4 5 6;
2 5 7 8 5 4]
C = [2 3 4 5 6 7 8;
1 2 6 7 4 3 2]
Now I want to sum all the same bins. My final result should be:
result = [0 1 2 3 4 5 6 7 8;
5 7 12 16 ...]
I could loop over all numbers, but I would like to have it fast.
You can use accumarray:
H = [A B C].'; %//' Concatenate the histograms and make them column vectors
V = [unique(H(:,1)) accumarray(H(:,1)+1, H(:,2))].'; %//' Find unique values and accumulate
V =
0 1 2 3 4 5 6 7 8
5 7 12 16 22 17 8 3 2
Note: The H(:,1)+1 is to force the bin values to be positive, otherwise MATLAB will complain. We still use the actual bins in the output V. To avoid this, as #Daniel says in the comments, use the third output of unique (See: https://stackoverflow.com/a/27783568/2732801):
H = [A B C].'; %//' stupid syntax highlighting :/
[U, ~, IU] = unique(H(:,1));
V = [U accumarray(IU, H(:,2))].';
If you're only doing it with 3 variables as you've shown then there likely aren't going to be any performance hits with looping it.
But if you are really averse to the looping idea, then you can do it using arrayfun.
rng = 0:8;
output = arrayfun(#(x)sum([A(2,A(1,:) == x), B(2,B(1,:) == x), C(2,C(1,:) == x)]), rng);
output = cat(1, rng, output);
output =
0 1 2 3 4 5 6 7 8
5 7 12 16 22 17 8 3 2
This can be beneficial for particularly large A, B, and C variables as there is no copying of data.

how to split a matrix of size 88x88 in 4 parts in matlab

so far i have done
Declare a random Matrix M of size 88 x 88
Type of M should be uint8 (all values should be between 0 to 255).
Spilt the Matrix into 4 parts: p1, p2, p3, p4
Transpose all parts
Concatenate all these four parts into new matrix N
Approach #1
If you have the Image Processing Toolbox, you can use blockproc for a pretty straight-forward solution to this -
fun = #(block_struct) transpose(block_struct.data);
N = blockproc(M, [size(M,1)/2 size(M,2)/2], fun)
Approach #2
Let's suppose you have an input matrix of size m x n and you would like to partition it into dim1p parts along the rows and dim2p parts along the columns, so that each block is of size m/dim1p x n/dim2p and you would like transpose them and finally concatenate them back to form a 2D array. This could be thought of as a general case of what you had proposed in the question.
To solve such a case with performance in mind, you can use this -
[m,n] = size(M); %// Get size
dim1p = 2; %// number of parts to be partitioned along dimension-1 (rows)
dim2p = 2; %// number of parts to be partitioned along dimension-2 (columns)
%// Split and transpose, resulting in a 3D array
A = reshape(permute(reshape(M, m, n/dim2p, []), [2 1 3]), n/dim2p, m/dim1p, []);
%// Join the 3D slices back into a 2D array for the desired output
nrows = n*dim1p/dim2p;
N = reshape(permute(reshape(permute(A,[1 3 2]),nrows,dim2p,[]),[1 3 2]),nrows,[])
Sample run (assuming M as 9 x 8 sized and partitioning it into 3 and 4 parts along the rows and columns respectively so that each block is of size 3 x 2) -
M =
5 6 2 6 4 2 1 3
2 8 8 1 3 8 3 7
5 1 6 8 4 1 6 8
6 5 7 3 3 6 7 1
4 3 9 3 2 2 5 3
4 9 5 7 6 2 2 1
7 6 2 5 9 3 5 6
8 9 5 6 9 6 7 1
1 1 3 3 4 9 1 3
dim1p =
3
dim2p =
4
N =
5 2 5 2 8 6 4 3 4 1 3 6
6 8 1 6 1 8 2 8 1 3 7 8
6 4 4 7 9 5 3 2 6 7 5 2
5 3 9 3 3 7 6 2 2 1 3 1
7 8 1 2 5 3 9 9 4 5 7 1
6 9 1 5 6 3 3 6 9 6 1 3
You are not much clear in the question, Maybe this helps,
M = uint8(randi([0 255],[88 88]));
p1 = M(1:end/2 ,1:end/2 );
p2 = M(1:end/2 ,end/2+1:end);
p3 = M(end/2+1:end,1:end/2 );
p4 = M(end/2+1:end,end/2+1:end);
N = [p1' p2';p3' p4'];
Another approach would be to use mat2cell to split up the matrix into a 2 x 2 grid of cells, transpose each of the cell's contents using cellfun, then piece them all together using cell2mat. Therefore:
[rows, cols] = size(M);
C = mat2cell(M, [rows/2, rows/2], [cols/2, cols/2]);
D = cellfun(#transpose, C, 'uni', 0);
out = cell2mat(D);
Minor note: This only works when the rows and columns are both even.

matlab: dividing vector into overlapping chunks of fixed size

I've a vector that I would like to split into overlapping subvectors of size cs in shifts of sh. Imagine the input vector is:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
given a chunksize of 4 (cs=4) and shift of 2 (sh=2), the result should look like:
[1 2 3 4]
[3 4 5 6]
[5 6 7 8]
[7 8 9 10]
[9 10 11 12]
note that the input vector is not necessarily divisible by the chunksize and therefore some subvectors are discarded. Is there any fast way to compute that, without the need of using e.g. a for loop?
In a related post I found how to do that but when considering non-overlapping subvectors.
You can use the function bsxfun in the following manner:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
A = v(bsxfun(#plus,(1:cs),(0:sh:length(v)-cs)'));
Here is how it works. bsxfun applies some basic functions on 2 arrays and performs some repmat-like if the sizes of inputs do not fit. In this case, I generate the indexes of the first chunk, and add the offset of each chunck. As one input is a row-vector and the other is a column-vector, the result is a matrix. Finally, when indexing a vector with a matrix, the result is a matrix, that is precisely what you expect.
And it is a one-liner, (almost) always fun :).
Do you have the signal processing toolbox? Then the command is buffer. First look at the bare output:
buffer(v, 4, 2)
ans =
0 1 3 5 7 9 11
0 2 4 6 8 10 12
1 3 5 7 9 11 13
2 4 6 8 10 12 0
That's clearly the right idea, with only a little tuning necessary to give you exactly the output you want:
[y z] = buffer(v, 4, 2, 'nodelay');
y.'
ans =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
That said, consider leaving the vectors columnwise, as that better matches most use cases. For example, the mean of each window is just mean of the matrix, as columnwise is the default.
I suppose the simplest way is actually with a loop.
A vectorizes solution can be faster, but if the result is properly preallocated the loop should perform decently as well.
v = 1:13
cs = 4;
sh = 2;
myMat = NaN(floor((numel(v) - cs) / sh) + 1,cs);
count = 0;
for t = cs:sh:numel(v)
count = count+1;
myMat(count,:) = v(t-cs+1:t);
end
You can accomplish this with ndgrid:
>> v=1:13; cs=4; sh=2;
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1)
>> chunks = X+Y
chunks =
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 11 12
The nice thing about the second syntax of the colon operator (j:i:k) is that you don't have to calculate k exactly (e.g. 1:2:6 gives [1 3 5]) if you plan to discard the extra entries, as in this problem. It automatically goes to j+m*i, where m = fix((k-j)/i);
Different test:
>> v=1:14; cs=5; sh=2; % or v=1:15 or v=1:16
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1); chunks = X+Y
chunks =
1 2 3 4 5
4 5 6 7 8
7 8 9 10 11
10 11 12 13 14
And a new row will form with v=1:17. Does this handle all cases as needed?
What about this? First I generate the starting-indices based on cs and sh for slicing the single vectors out of the full-length vector, then I delete all indices for which idx+cs would exceed the vector length and then I'm slicing out the single sub-vectors via arrayfun and afterwards converting them into a matrix:
v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;
idx = 1:(cs-sh):length(v);
idx = idx(idx+cs-1 <= length(v))
A = arrayfun(#(i) v(i:(i+cs-1)), idx, 'UniformOutput', false);
cell2mat(A')
E.g. for cs=5; sh=3; this would give:
idx =
1 3 5 7
ans =
1 2 3 4 5
3 4 5 6 7
5 6 7 8 9
7 8 9 10 11
Depending on where the values cs; sh come from, you'd probably want to introduce a simple error-check so that cs > 0; as well as sh < cs. sh < 0 would be possible theoretically if you'd want to leave some values out in between.
EDIT: Fixed a very small bug, should be running for different combinations of sh and cs now.

What is the simplest way to create a weight matrix bases on how frequent each element appear in the matrix?

This is the input matrix
7 9 6
8 7 9
7 6 7
Based on the frequency their appearance in the matrix (Note. these values are for explanation purpose. I didn't pre-calculate them in advance. That why I ask this question)
number frequency
6 2
7 4
8 1
9 2
and the output I expect is
4 2 2
1 4 2
4 2 4
Is there a simple way to do this?
Here's a three-line solution. First prepare the input:
X = [7 9 6;8 7 9;7 6 7];
Now do:
[a m n] = unique(X);
b = hist(X(:),a);
c = reshape(b(n),size(X));
Which gives this value for c:
4 2 2
1 4 2
4 2 4
If you also wanted the frequency matrix, you can get it with this code:
[a b']
Here is a code with for-loop (a is input matrix, freq - frequency matrix with 2 columns):
weight = zeros(size(a));
for k = 1:size(freq,1)
weight(a==freq(k,1)) = freq(k,2);
end
Maybe it can be solved without loops, but my code looks like:
M = [7 9 6 ;
8 7 9 ;
7 6 7 ;];
number = unique(M(:));
frequency = hist(M(:), number)';
map = containers.Map(number, frequency);
[height width] = size(M);
result = zeros(height, width); %allocate place
for i=1:height
for j=1:width
result(i,j) = map(M(i,j));
end
end