Independent random selection with replacement of elements per column in a matrix - matlab

I have a matrix A which is of size r1 x c. I'm trying to create a matrix B which is of size r2 x c where for each individual column, I would like to randomly sample with replacement.
I wrote this code that does what I am looking for:
%// Define a random index :
RO = randi(r1,r2,c);
%// Define an output matrix
B = zeros(r2,c);
%// Perform selection
for i1 = 1:c
for i2 = 1:r2
B(i2,i1) = A(RO(i2,i1),i1);
end
end
Is there an easier and/or faster way to do this in MATLAB without loops?

If I am interpreting this code correctly, you have a matrix and for each column, you consider this to be an individual signal and you want to randomly sample r2 elements from each signal to create another r2 signal that possibly has duplicates. You wish to stack these columns horizontally to generate an output matrix. A property with this matrix is that for each column, this random sampling is applied only for the corresponding column in the input matrix.
You can certainly do this vectorized. The matrix RO would be used as row coordinates and the column coordinates, which we will call RC, would simply be matrix of enumerations where each row is the linear range 1:c and there are r2 of these stacked on top of each other. This can be achieved with repmat.
First obtain the linear indices of the row and column coordinates via sub2ind then use this to index into your input matrix A.
RO = randi(r1,r2,c);
RC = repmat(1:c,r2,1);
ind = sub2ind(size(A), RO, RC);
B = A(ind);
To show that this works, I've created the following data:
rng(123);
r1 = 5;
r2 = 10;
c = 3;
A = randi(10, r1, c);
Running your code above gives me:
>> B
B =
6 10 8
7 10 5
7 10 4
3 10 4
3 5 5
6 5 1
8 7 4
6 7 8
6 7 5
6 7 4
Using the same matrix RO that was generated, the more optimized code that I wrote also gives:
>> B
B =
6 10 8
7 10 5
7 10 4
3 10 4
3 5 5
6 5 1
8 7 4
6 7 8
6 7 5
6 7 4

Related

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.

Two simple examples on vectorizing for loops in matlab

Unfortunately my programming skills are not that advanced and I really need to vectorize some loops to finish my thesis.
I tried to make things really clear and simple and I have the following two questions in matlab:
1.
If we have a 5x5 matrix A and we want to set the diagonal elements of this matrix to the diagonal of a matrix B, apart from diag(A)=diag(B) we could use :
for i=1:5
B(i,i)=A(i,i)
end
Now if I want to vectorize this I can not use:
i=1:5
B(i,i)=A(i,i)
In that way we assign each combination from 1:5. So, in the end we asign each element of A equal to B and not the diagonal.
Is there some way that we could assign each identical pair of (i,i)?
I tried :
i=1:5
j=1:5
B(i,find(j==i))=A(i,find(j==i))
But still does not work. I repeat I know the diag property but Im only interested on the particular problem.
2.
A similar problem is the fillowing.
b=[ones(2,2) ones(2,2)*2 ones(2,2)*3 ones(2,2)*4] ;
a = zeros(8,12);
for i=1:4
a((i-1)*2+1:(i)*2,(i-1)*3+1:(i)*3) = [8*ones(2,1) b(:,[2*(i-1)+1 2*i])];
end
Thank you for your time and for your help.
Let's bring some mask magic, shall we!
Problem #1
mask = eye(size(A))==1
A(mask) = B(mask)
For creating the mask, you can also use bsxfun -
N = size(A,1)
bsxfun(#eq,[1:N]',1:N)
Or finally, you can use linear indexing -
N = size(A,1)
A(1:N+1:N^2) = B(1:N+1:N^2)
Sample run -
>> A
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
>> B
B =
5 5 2 8 2
1 1 6 5 2
7 8 5 4 4
1 8 9 8 8
1 7 6 1 8
>> mask = eye(size(A))==1;
>> A(mask) = B(mask)
A =
5 2 9 6 5
9 1 6 2 2
9 7 5 3 9
4 5 8 8 7
7 5 8 1 8
Problem #2
%// Append 8's at the start of every (2,2) block in b
b1 = reshape([8*ones(2,4) ; reshape(b,4,[])],2,[])
%// Mask where b1 values are to be put in an otherwise zeros filled array
mask = kron(eye(4,4),ones(2,3))==1
%// Initialize output arraya and set values from b1 into masked places
out = zeros(size(mask))
out(mask) = b1
For your first problem. Use logical indexing:
index = diag(ones(1,size(B,1))
B(index) = A(index)

reconstruct time series from given matrix

suppose that we are creating following matrix from given signal
function [ x ]=create_matrix1(b,l)
n = length(b);
m = n-l+1;
x = zeros(m,l);
for i=1:m
x(i,:)=b(i:i+l-1);
end;
end
with some window length,for example
X=[2;1;3;4;5;7]
X =
2
1
3
4
5
7
>> B=create_matrix1(X,3)
B =
2 1 3
1 3 4
3 4 5
4 5 7
if we have given matrix and windows length ,how can i reconstruct original signal?let say i know that windows length is 3,thanks in advance,i think i should sum elements on anti diagonal and divide by number of elements in this anti diagonal ,but how can i do it by code?thanks in advance
Your original vector is located along the top and right edge of your matrix B and can be reconstructed like so:
>> X_reconstructed = [B(1,1:end-1).'; B(:,end)]
X_reconstructed =
2
1
3
4
5
7
In case the matrix B is some noisy matrix and you actually want to do the averages along the diagonals:
>> BB = fliplr(B);
>> X_mean = arrayfun(#(i) mean(diag(BB,i)), size(B,2)-1:-1:-size(B,1)+1).'
X_mean =
2
1
3
4
5
7

MATLAB: Keeping a number of random rows in a matrix which satisfy certain conditions

I have a matrix in Matlab which looks similar to this, except with thousands of rows:
A =
5 6 7 8
6 1 2 3
5 1 4 8
5 2 3 7
5 8 7 2
6 1 3 8
5 2 1 6
6 3 2 1
I would like to get out a matrix that has three random rows with a '5' in the first column and three random rows with a '6' in the first column. So in this case, the output matrix would look something like this:
A =
5 6 7 8
6 1 2 3
5 2 3 7
6 1 3 8
5 2 1 6
6 3 2 1
The rows must be random, not just the first three or the last three in the original matrix.
I'm not really sure how to begin this, so any help would be greatly appreciated.
EDIT: This is the most successful attempt I've had so far. I found all the rows with a '5' in the first column:
BLocation = find(A(:,1) == 5);
B = A(BLocation,:);
Then I was trying to use 'randsample' like this to find three random rows from B:
C = randsample(B,3);
But 'randsample' does not work with a matrix.
I also think this could be done a little more efficiently.
You need to run randsample on the row indices that satisfy the conditions, i.e. equality to 5 or 6.
n = size(A,1);
% construct the linear indices for rows with 5 and 6
indexA = 1:n;
index5 = indexA(A(:,1)==5);
index6 = indexA(A(:,1)==6);
% sample three (randomly) from each
nSamples = 3;
r5 = randsample(index5, nSamples);
r6 = randsample(index6, nSamples);
% new matrix from concatenation
B = [A(r5,:); A(r6,:)];
Update: You can also use find to replace the original index construction, as yuk suggested, which proves to be faster (and optimized!).
Bechmark (MATLAB R2012a)
A = randi(10, 1e8, 2); % 10^8 rows random matrix of 1-10
tic;
n = size(A,1);
indexA = 1:n;
index5_1 = indexA(A(:,1)==5);
toc
tic;
index5_2 = find(A(:,1)==5);
toc
Elapsed time is 1.234857 seconds.
Elapsed time is 0.679076 seconds.
You can do this as follows:
desiredMat=[];
mat1=A(A(:,1)==5,:);
mat1=mat1(randperm(size(mat1,1)),:);
desiredMat=[desiredMat;mat1(1:3,:)];
mat1=A(A(:,1)==6,:);
mat1=mat1(randperm(size(mat1,1)),:);
desiredMat=[desiredMat;mat1(1:3,:)];
The above code uses logical indexing. You can also do this with find function (logical indexing is always faster than find).

matlab. copy values from one matrix based on values of another matrix

I have matrix a <500 x 500> and matrix b <500 x 2>.
Matrix b contains two types of values which are row and column coordinates for matrix a. I would like to use the values in matrix b to to copy all the values that fall on the row and column coordinates of matrix a.
see example below
matrix a matrix b output
1 2 3 4 5 1 5 1 2 3 4 5
6 7 8 9 10 2 5 7 8 9 10
11 12 13 14 15 1 3 11 12 13
Because every row will have a different length you'll need to save the values into a cell array.
Something like this should work:
output = cell( size(b,1),1);
for i = 1:size(a,1)
output{i} = a(i, b(i,1):b(i,2) )
end