sveer
sveer

Reputation: 472

Get submatrix made from random rows and columns of large matix

I would like to extract (square) sub-matrices from a matrix, randomly with a size between some min and max values.

I would also like to retain the row and column indices which were selected.

Are there any built-in functions for this purpose? I would appreciate any general algorithm to achieve the desired results.

Just for an example without considering the square matrix constraint:

Input:

  | 1 2 3 4 5 6 7 8 <- column indices
--+----------------
1 | 4 3 1 4 0 1 0 1
2 | 2 0 1 5 6 3 2 0
3 | 5 5 0 6 7 8 9 0
4 | 2 3 5 6 7 9 0 1
^
Row indices

Output sample:

  | 1 4 5 7 8 <- column indices
--+----------
1 | 4 4 0 0 1
2 | 2 5 6 2 0
4 | 2 6 7 0 1
^
Row indices

Edit: I would like to have a function like this

matrixsample(numberOfSamples, minSize, maxSize, satisfyingFunction)

the samples should vary their size between the minSize and maxSize.

If numberOfSamples = 10, minSize = 2 and maxSize = 6 then output should be randomly selected rows and columns like:

sampleMatrix1 2x2 sampleMatrix2 3x3 sampleMatrix3 5x5 ... sampleMatrix7 6x6 ... sampleMatrx10 4x4

satisfyingFunction could test any attribute of the matrix; like being non-singular, rank > x, etc.

Upvotes: 1

Views: 745

Answers (2)

Wolfie
Wolfie

Reputation: 30146

In MATLAB, you will find the randperm function useful for selecting random rows/columns.

To get a randomly sized sub-matrix, use randi([minVal, maxVal]) to get a random integer between minVal and maxVal.

Getting a submatrix from random (ordered) combination of rows and columns:

M = randi([0,9],4,8); % 4x8 matrix of random 1 digit integers, your matrix here!

nRows = randi([2, 4]); % The number of rows to extract, random between 2 and 4
nCols = randi([5, 7]); % The number of columns to extract, random between 5 and 7

idxRows = sort(randperm(size(M,1), nRows)); % Random indices of rows
idxCols = sort(randperm(size(M,2), nCols)); % Random indices of columns

output = M(idxRows, idxCols); % Select the sub-matrix


If you want to make the sub-matrix square then simply use the same value for nRows and nCols.


Showing this method works with your example input/output values:

M = [4 3 1 4 0 1 0 1; 2 0 1 5 6 3 2 0; 5 5 0 6 7 8 9 0; 2 3 5 6 7 9 0 1];
idxRows = [1 2 4]; idxCols = [1 4 5 7 8];
output = M(idxRows, idxCols)
% >>  4     4     0     0     1
%     2     5     6     2     0
%     2     6     7     0     1

Edit in response to extended question scope:

You can package the above up into a short function, which returns the row and column indices, as well as the submatrix.

function output = getsubmatrix(M, nRows, nCols)
    % Get a submatrix of random rows/columns
    idxRows = sort(randperm(size(M,1), nRows)); 
    idxCols = sort(randperm(size(M,2), nCols)); 
    submatrix = M(idxRows, idxCols); 
    output = {submatrix, idxRows, idxCols};
end

Then you can use this in some sampling function as you described:

function samples = matrixsample(matrix, numberOfSamples, minSize, maxSize, satisfyingFunction)
    % output SAMPLES which contains all sample matrices, with row & column indices w.r.t MATRIX
    samples = cell(numberOfSamples,1);
    % maximum iterations trying to satisfy SATISFYINGCONDITION
    maxiters = 100;
    for ii = 1:numberOfSamples        
        iters = 0; submatrixfound = false; % reset loop exiting conditions
        nRows = randi([minSize, maxSize]); % get random submatrix size
        nCols = nRows;                     % Square matrix
        while iters < maxiters && submatrixfound == false
            % Get random submatrix, and the indices
            submatrix = getsubmatrix(matrix, nRows,nCols);
            % satisfyingFunction MUST RETURN BOOLEAN
            if satisfyingFunction(submatrix{1})
                samples{ii} = submatrix; % If satisfied, assign to output
                submatrixfound = true;   % ... and move on!
            end
            iters = iters + 1;
        end
    end
end

Test example:

s = matrixsample(magic(10), 5, 2, 8, @(M)max(M(:)) < 90)

Upvotes: 2

OmG
OmG

Reputation: 18838

If the table is given, you will do it by randsample:

 minRowVal = 3;
 maxRowVal = 4;
 minColVal = 2;
 maxColVal = 4;     
 kRow = randi([minRowVal maxRowVal]) ;
 kCol = randi([minColVal maxColVal]);
table(sort(randsample(size(table,1),kRow)),sort(randsample(size(table,2),kCol))

choose some sample by the given size of kRow and kCol, then select the information from the table.

Upvotes: 0

Related Questions