pick random numbers in certain range from vector - matlab

how would you use randperm to randomly pick three numbers out of a range of 5 in a vector?
i have a vector like this:
A = [1 2 3 4 5 6 7 8 9 10]
now from every 5 consecutive values i want to randomly pick 3 of them:
A_result = [1 3 5 6 7 9]
any help is appreciated!

This one uses different random indices in every 5-group.
A = [1 2 3 4 5 6 7 8 9 10]
B = reshape(A,5,[]) % (5 x 2)
ind = cell2mat(arrayfun(#(x)sort(randperm(5,3))',1:size(B,2),'UniformOutput',false)) % (3 x 2), row indices into B
ind = bsxfun(#plus,ind,size(B,1)*(0:size(B,2)-1)) % (3 x 2), linear indices into B
C = B(ind) % (3 x 2) result
C(:)' % result vector
Every sort(randperm(5,3))' call generates a random column vector with 3 ascending numbers from 1 to 5, like [1;3;4] or [2;4;5]. arrayfun with the dummy argument x calls this 2 times in this example, because A consists of 2 sub-vectors of length 5. With the argument 'Uniform output' set to false, it generates a cell array of these random vectors, and cell2mat converts it to the (3 x 2)-matrix ind. The bsxfun call converts the values in the matrix ind to a matrix of linear indices into matrix B or A.
For your (900 x 25)-matrix, do
A = rand(900,25); % (900 x 25)
B = A'; % (25 x 900)
ind = cell2mat(arrayfun(#(x)sort(randperm(25,17))',1:size(B,2),'UniformOutput',false)); % (17 x 900), row indices into B
ind = bsxfun(#plus,ind,size(B,1)*(0:size(B,2)-1)); % (17 x 900), linear indices into B
C = B(ind); % (17 x 900), result

You can use reshape and randsample
rA = reshape( A, 5, [] ); % groups of 5 in a a row
A_result = rA( randsample( 5, 3, false ), : );
A_result = reshape( A_result, 1, [] );

You can pre-generate all possible picking patterns, and then randomly select one such pattern for each group. This approach is suitable for small group sizes, otherwise it may use a lot of memory.
A = 1:10; %// example data
n = 5; %// group size. Assumed to divide numel(A)
k = 3; %// how many to pick from each group
S = numel(A);
patterns = nchoosek(1:n, k); %// all possible picking patterns
K = size(patterns, 1);
p = randi(K, S/n, 1); %// generate random indices for patterns
pick = bsxfun(#plus, patterns(p,:).', (0:n:S-1)); %'// to linear indices
A_result = A(pick(:));

Related

Matlab - how to create matrix from two or more vectors, which represents every combination of a single element from each vector [duplicate]

This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 3 years ago.
I'm new to matlab and have a question on how to efficiently create a matrix from two or more vectors, where every combination of a single element from each vector is represented in a resulting matrix.
For example, say we have vectors:
x = [1 2 3 4]; y = [5 6 7 8];
I'd like to get the following result in matrix ans:
ans = [1 5; 1 6; 1 7; 1 8; 2 5; 2 6; 2 7; ... 4 7; 4 8]
The above example is for two-dimensions (two input vectors), however it would be ideal if the solution is for d-dimensions (d-number of input vectors). Thanks!
[X,Y] = ndgrid(x,y);
desiredOutput = [X(:),Y(:)];
Here is the solution for d dimensions.
%% Input.
x = [1 2 3 4];
y = [5 6 7 8];
%% Fixed 2d solution as provided by Alex.
[X, Y] = ndgrid(x, y);
desiredOutput = [X(:), Y(:)]
%% Arbitrary dimension solution.
% Store all input vectors in cell array.
vectors{1} = x;
vectors{2} = y;
% Initialize output for ndgrid.
VECTORS = cell(numel(vectors), 1);
% Call ndgrid with arbitrary number of vectors.
[VECTORS{:}] = ndgrid(vectors{:});
% Convert VECTORS.
VECTORS = cellfun(#(x) x(:), VECTORS, 'UniformOutput', false);
% Output.
desiredOutput = [VECTORS{:}]
%% Expanded input.
z = [9 10 11 12];
vectors{3} = z;
VECTORS = cell(numel(vectors), 1);[VECTORS{:}] = ndgrid(vectors{:});
VECTORS = cellfun(#(x) x(:), VECTORS, 'UniformOutput', false);
desiredOutput = [VECTORS{:}]

Convert a cell containing matrices to a 2d matrix

I want to find easy way to convert a 1x324 cell array which contains matrices to a 2-dimensional matrix.
Each of the cell array's elements is a matrix of size 27x94, so they contain 2538 different values. I want to convert this cell array of matrices to a 324x2538 matrix - where the rows of the output contain each matrix (as a row vector) from the cell array.
To clarify what my data looks like and what I'm trying to create, see this example:
matrix1 = [1,2,3,4,...,94 ; 95,96,97,... ; 2445,2446,2447,...,2538]; % (27x94 matrix)
% ... other matrices are similar
A = {matrix1, matrix2, matrix3, ..., matrix324}; % Matrices are in 1st row of cell array
What I am trying to get:
% 324x2538 output matrix
B = [1 , 2 , ..., 2538 ; % matrix1
2539 , 2540, ..., 5076 ; % matrix2
...
819775, 819776, ..., 822312];
The cell2mat function does exactly that. The doc example:
C = {[1], [2 3 4];
[5; 9], [6 7 8; 10 11 12]};
A = cell2mat(C)
A =
1 2 3 4
5 6 7 8
9 10 11 12
You have your matrix now, so just rework it to contain rows:
B = rand(27,302456); % your B
D = reshape(B,27,94,324); % stack your matrices to 3D
E = reshape(D,1, 2538,324); % reshape each slice to a row vector
E = permute(E,[3 2 1]); % permute the dimensions to the correct order
% Based on sizes instead of fixed numbers
% D = reshape(B, [size(A{1}) numel(A)]);
% E = reshape(D,[1 prod(size(A{1})) numel(A)]);
% E = permute(E,[3 2 1]); % permute the dimensions to the correct order
Or, to one line it from your B:
B = reshape(B,prod(size(A{1})),numel(A)).'
One way to write this would be using cellfun to operate on each element of the cell, then concatenating the result.
% Using your input cell array A, turn all matrices into column vectors
% You need shiftdim so that the result is e.g. [1 2 3 4] not [1 3 2 4] for [1 2; 3 4]
B = cellfun(#(r) reshape(shiftdim(r,1),[],1), A, 'uniformoutput', false);
% Stack all columns vectors together then transpose
B = [B{:}].';
Now I found the solution and I will add it here if anyone have similar problems in future:
for ii = 1:length(A)
B{ii} = A{ii}(:);
end
B = cell2mat(B).';

Find a pair of numbers in a matrix in Matlab

Given the matrix A = [6 4 1; 1 4 3; 3 4 2;7 6 8] and the array of pairs b = [4 6; 4 1; 1 6], I want to find the pairs given in b in the rows of A without a for loop.
For example, the first pairs is (4,6) or (6,4) , which occurs in the first row of A.
Assuming, you want to find the rows of A which contain the exact pairs given in b, this is how you can do it without a loop:
% Create a matrix of pairs in A
pairs = cat(3, A(:, 1:end-1), A(:, 2:end));
% Reshape b to use bsxfun
b_ = reshape(b', [1 1 size(b')]);
% Get the matches for the pairs and for the flipped pairs
indices = all( bsxfun(#eq, pairs, b_), 3) | all( bsxfun(#eq, pairs, flip(b_,3)), 3);
% Find the indices of the rows with a match
row_indices = find(squeeze(any(any(indices,4),2)));
Please refer to the reference on vectorization for more information on how to make fast computations in Matlab without loops.

Matrix with sliding window elements

I have time series, and I applying some user defined function to every W elements in time series.
Right now I am just using for loop, slide window of size W an apply my function to elements in a window at every iteration.
I am using Matlab and it is very inefficient with a "for loops" so I would love to vectorize this operation.
As a solution I see transforming signal with length N to a matrix with size (N - 1, W) where each row is time series in different windows and applying function to this matrix.
So, my questions are:
How to transform my initial time series to such a matrix?
Let's say I am sliding window with step X. So that not (N - 1, W) matrix will appear, but ((N - 1) / X, W). (Every Xth row of the matrix in [1])
Example:
Let's say my time series is:
T = [1, 5, 6, 8, 10, 14, 22]
W = 3
X = 1
=> I would love to get
[[1, 5, 6],
[5, 6, 8],
[6, 8, 10],
[8, 10, 14],
[10, 14, 22]]
If
W = 3
X = 2
=> I would love to get
[[1, 5, 6],
[6, 8, 10],
[10, 14, 22]]
Creating the right indices with bsxfun should most certainly help:
ind = bsxfun(#plus, 1:W, (0:X:numel(T)-W).');
out = T(ind);
Creating the right indices is the first step, delineated by the first line of code. What this code does is that it creates a 2D matrix where each row are the elements to access per window of interest. If you want to gain intuition on how the code generates the indices, look specifically at the first case where X = 1; and W = 3;.
We can see that the first row consists of accessing elements 1, 2, 3. The second row consists of accessing elements 2, 3, 4... up until the last row, which is 5, 6, 7. We can see that we have to access neighbouring elements in a window, and so the base indices need to go from 1, 2, 3, or in general from 1 to W. We now need to offset these indices so that they are centred at the right elements in T per window. The offset for the first window is simply 0, the next offset for the second window is simply 1 up until the last row which is 3. We see that for each row, we add 1 more to the base indices as the rows increase. Therefore, we add 1 to each base index for the second row, then 2 for each base index in the third row and so on. If you add the base indices with the offset indices, you thus finally get the correct indices to access the right elements in T.
Similarly if X = 2; and W = 3;, we see that we still have base indices of 1, 2, 3. However, the right elements to access now are 1, 2, 3 for the first row, then 3, 4, 5 for the second row then 5, 6, 7 for the third row. For each row, we now offset the base indices by 2 instead of 1 now. Therefore the second row we add 2 to each base index, then we add 4 to each base index for the third row and so on.
In general, the base indices are created using a vector 1:W and the offset indices are created using a vector 0:X:numel(T)-W. The subtraction of W is required so that we don't go out of bounds when sampling the signal as per the requirement. To create these indices that we just talked about, bsxfun handles this for us.
We create a row vector of 1:W which corresponds to the base indices and a column vector of (0:X:numel(T)-W).' which corresponds to the offsets per window. Note that the first offset starts at 0, then we increment by X amount to ensure that the correct centre is calculated to place our base indices at. We stop until we hit numel(T)-W elements, which is the condition you have stated. By using bsxfun, two temporary 2D matrices are created where the row vector is duplicated for as many rows as there are rows as there are in the column vector and the column vector is duplicated for as many columns as there are in the row vector. Once you add these two matrices together, you get the resulting index matrix.
Running the code with W = 3; and X = 1; gives:
>> T = [1, 5, 6, 8, 10, 14, 22];
>> X = 1;
>> W = 3;
>> ind = bsxfun(#plus, 1:W, (0:X:numel(T)-W).')
ind =
1 2 3
2 3 4
3 4 5
4 5 6
5 6 7
Similarly if W = 3; and X = 2; we also get:
>> T = [1, 5, 6, 8, 10, 14, 22];
>> X = 2;
>> W = 3;
>> ind = bsxfun(#plus, 1:W, (0:X:numel(T)-W).')
ind =
1 2 3
3 4 5
5 6 7
You can verify for yourself that these indices correspond to the correct elements in T to create your desired matrix in this case.
We finally use this to index into our matrix to grab the right elements:
out = T(ind);
Doing this for X = 1; and W = 3; gives:
>> out = T(ind)
out =
1 5 6
5 6 8
6 8 10
8 10 14
10 14 22
Similarly for X = 2; and W = 3; gives:
>> out = T(ind)
out =
1 5 6
6 8 10
10 14 22
Based on rayryeng's answer I wrote a function that does exactly this, plus some additional functionality. It's designed for generating indices for autoregression on a univariate time series. It can easily be used for the multivariate case by simply using the same indices and concatenating the referenced data.
It returns the indices to the predictor variable X (as per your request) and for the regressors y as well. In addition you have the option of applying a 'mask' to the predictor variables X while sliding the window. For example, with a window of 21 steps, you can select [T-2 T-3 T-5 T-8 T-13 T-21] for X and T for y
You can also change the prediction horizon - how many steps into the future the indices for y are. For example X = [T-1 T-2] and y = T+2
Hopefully someone else will find this useful.
% get_Sliding_Indexes:
% Useful for autoregression on a univariate time series.
% Returns the indexes for the predictor and response variables
% according to a sliding window.
%
% Copyright (C) 20016 Florin Schimbinschi
%
% Parameters:
% numRecords - the number of records in the dataset
%
% windowLag - number of past samples to take - it will be equal to
% the size of the predictor vector X. Default 10
%
% predHorizon - the prediction horizon is the number of steps into
% the future that predictions are to be made. Default 1
%
% windowPattern - by default the window will take all consecutive
% values in the past over the window lag size, however it is
% possible to sample using a custom pattern.
% For example taking every second value can be done by setting
% this parameter to 1:2:5. Default 1:windowLag
%
% stepSize - number of steps taken when window is moved. Default 1
%
% Returns:
% indX - predictor variable indexes
% indY - response variable indexes
%
%
% windowPattern = 1:2:9 __ structure between [] is moved to
% / \ / the right by stepSize units
% >------[(9-7-5-3-1)---(y)]--------------->
% \_______/ \_/
% X = [13579] predHorizon = 3
%
%
% Example on a multivariate time series (two) with 6 records:
%
% data2d = [ .1 .2 .3 .4 .5 .6
% .11 .22 .33 .44 .55 .66]';
%
% [X, y] = getSlidingIndexes(size(data2d,1), 4)
% X =
% 1 2 3 4
% 2 3 4 5
% y =
% 5
% 6
%
% Assuming we are interested in the second series (column):
%
% series2 = data2d(:,2);
%
% series2(X)
% ans =
% 0.1100 0.2200 0.3300 0.4400
% 0.2100 0.3300 0.4400 0.5500
%
% series2(y)
% ans =
% 0.5500
% 0.6600
%
function [indX, indY] = get_Sliding_Indexes(numRecords, ...
windowLag, predHorizon, windowPattern, stepSize)
if ~exist('numRecords','var') || isempty(numRecords)
error('The number of records in the dataset is not specified');
end
if ~exist('stepSize','var') || isempty(stepSize)
stepSize = 1; % steps taken when moving the window
end
if ~exist('predHorizon','var') || isempty(predHorizon)
predHorizon = 1; % aiming to predict this many steps in the future
end
if ~exist('windowLag','var') || isempty(windowLag)
windowLag = 10; % number of time steps to look back
end
if exist('windowLag','var') && (windowLag > numRecords)
error('The size of the window is larger than the number of observations');
end
if ~exist('windowPattern','var') || isempty(windowPattern)
windowPattern = 1:windowLag; % pattern of sampling data
end
if exist('windowPattern','var') && windowPattern(end) > windowLag
error('The window pattern must stop at the window lag specified');
end
% the number of samples in the window
maxSample = max(windowPattern);
indX = bsxfun(#plus, windowPattern, ...
(0:stepSize:(numRecords - maxSample - predHorizon))');
indY = bsxfun(#plus, max(windowPattern) + predHorizon, ...
(0:stepSize:(numRecords - maxSample - predHorizon))');
end
You can also find the code here: https://au.mathworks.com/matlabcentral/fileexchange/58730-get-sliding-indexes-numrecords--windowlag--predhorizon--windowpattern--stepsize-

MATLAB/OCTAVE Extracting elements from different sized vectors in a cell array

I have a simple question but I can't figure it out or find it anywhere.
I have a cell array where c{1} is a vector and c{2} is a vector but of different lengths, up to c{i}. What I want is one vector that is [c{1};c{2};c{3}...c{i}]. What is the most efficient way to do this?
The following one-liner even works for completely inconsistent inputs:
result = [cell2mat(cellfun(#(x) x(:), A, 'uni', 0)')]'
Example:
for:
A{1} = [1, 2, 3, 4, 5];
A{2} = [6; 7; 8; 9];
A{3} = [10, 12; 11, 13];
it returns:
result =
1 2 3 4 5 6 7 8 9 10 11 12 13
Matlab/Octave allows this king of really-not-efficient but very-convenient notation, assuming a is a structure only containing column-vectors:
x = []; #% A fresh new vector/matrix/tensor, who knows?
for i=1:numel(a) #% parse container item by item
x = [x;a{i}]; #% append container item a{i} to x in a column-fashion way
end
This will works but it is bloody inefficient since it will reallocate x each for step and it is not bulletproof (no error handling, no type checking): therefore it will fail if it encounters anything (matrix, string, row vector) but column vector which are likely to be found in such containers.
Anyway, it will ease a not-so-stringent-and-heuristic design, but please consider reimplementing when robust design is needed.
You can padding each cell with zeros, and align the lengths to the longest cell vector. It is done in a loop by iterating each cell vector.
This depends on whether the vectors in c are row or column vectors. But usually the fastest and most compact ways are:
c={[1 2 3], [4 5 6 7 8], [9 10]}
cell2mat(c)
cat(2, c{:})
or
c={[1 2 3]', [4 5 6 7 8]', [9 10]'}
% cell2mat(c) % Doesn't work.
cat(1, c{:})
so personally, I prefer cat.
In Matlab; without loops:
If the cell array contains column vectors and you want to arrange them into one big column vector:
result = vertcat(c{:}); %// vertically concat all vectors
Example:
>> c = {[1;2], [1;2;3]};
>> result = vertcat(c{:})
result =
1
2
1
2
3
If the cell array contains row vectors, you can arrange them as rows of a matrix, filling non-existent values with NaN (or any other value):
M = max(cellfun(#numel, c)); %// max length of vectors
c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0); %// fill with NaN
result = vertcat(c2{:}); %// concat all equal-size row vectors into a matrix
Example:
>> c = {[1 2], [1 2 3]};
>> M = max(cellfun(#numel, c));
>> c2 = cellfun(#(row)[row NaN(1,M-numel(row))], c, 'uni', 0);
>> result = vertcat(c2{:})
result =
1 2 NaN
1 2 3