How to obtain a random vector in MatLab? - matlab

I need obtain a vector with n numbers disposed in random order in MatLab. How can I do it?
If I use, for example, randi(10,1,10), I will obtain random values, but I have no garantee that all the numbers will be in the sequence.
For example:
I need a vector with all the numbers 1,2,3,4,5,6,7,8,9,10, disposed in a random order, like in 2,5,3,6,8,10,4,7,9,1.

It appears that you are looking for the randperm function. From the docs:
p = randperm(n) returns a row vector containing a random permutation of the integers from 1 to n inclusive.
Your example would be randperm(10).
There is an optional second argument that you could pass in to determine how many elements will be chosen. For example, randperm(10, 5) would choose five random numbers from 1 to 10.
You can also use the results of randperm to shuffle or select from an arbitrary vector. Say you wanted the numbers 101 to 110 in random order instead of 1 to 10:
nums = 101:110;
nums = nums(randperm(numel(nums)));

Related

MATLAB: Use Logical indexing to replace the values in the matrix by its value divided by 2?

So I have a matrix A. And I can find the values of greater than 7 with logical indexing of A>7.
How can I then, replace all the values of A>7 by the numbers divided by 2?
I tried:
A(A>7) = [num1/2, num2/2, etc]
But I'd want the math done without me inputting the nums/2 values to be replaced accordingly.
You can do it easily by using the same indices likes the following:
indices = A > 7;
A(indices) = A(indices)/2;

What does the third input to rand mean?

In the MATLAB if:
x = rand(a,b,c);
What does the third input to rand, c, mean?
a: numbers of rows
b: numbers of columns
c: ??
In MATLAB, matrices are not limited to 2 dimensions (i.e. only rows and columns), but can have many higher dimensions.
The third input to the rand function is just telling rand the size of the third dimension that you want. By default it is 1, but in your case it will instead be c.
In general, the nth input to rand will be the size of the nth dimension of the matrix of random numbers it produces.
See the docs:
X = rand(sz1,...,szN) returns an sz1-by-...-by-szN array of random
numbers where sz1,...,szN indicate the size of each dimension. For
example, rand(3,4) returns a 3-by-4 matrix.

Matlab: Array of random integers with no direct repetition

For my experiment I have 20 categories which contain 9 pictures each. I want to show these pictures in a pseudo-random sequence where the only constraint to randomness is that one image may not be followed directly by one of the same category.
So I need something similar to
r = randi([1 20],1,180);
just with an added constraint of two numbers not directly following each other. E.g.
14 8 15 15 7 16 6 4 1 8 is not legitimate, whereas
14 8 15 7 15 16 6 4 1 8 would be.
An alternative way I was thinking of was naming the categories A,B,C,...T, have them repeat 9 times and then shuffle the bunch. But there you run into the same problem I think?
I am an absolute Matlab beginner, so any guidance will be welcome.
The following uses modulo operations to make sure each value is different from the previous one:
m = 20; %// number of categories
n = 180; %// desired number of samples
x = [randi(m)-1 randi(m-1, [1 n-1])];
x = mod(cumsum(x), m) + 1;
How the code works
In the third line, the first entry of x is a random value between 0 and m-1. Each subsequent entry represents the change that, modulo m, will give the next value (this is done in the fourth line).
The key is to choose that change between 1 and m-1 (not between 0 and m-1), to assure consecutive values will be different. In other words, given a value, there are m-1 (not m) choices for the next value.
After the modulo operation, 1 is added to to transform the range of resulting values from 0,...,m-1 to 1,...,m.
Test
Take all (n-1) pairs of consecutive entries in the generated x vector and count occurrences of all (m^2) possible combinations of values:
count = accumarray([x(1:end-1); x(2:end)].', 1, [m m]);
imagesc(count)
axis square
colorbar
The following image has been obtained for m=20; n=1e6;. It is seen that all combinations are (more or less) equally likely, except for pairs with repeated values, which never occur.
You could look for the repetitions in an iterative manner and put new set of integers from the same group [1 20] only into those places where repetitions have occurred. We continue to do so until there are no repetitions left -
interval = [1 20]; %// interval from where the random integers are to be chosen
r = randi(interval,1,180); %// create the first batch of numbers
idx = diff(r)==0; %// logical array, where 1s denote repetitions for first batch
while nnz(idx)~=0
idx = diff(r)==0; %// logical array, where 1s denote repetitions for
%// subsequent batches
rN = randi(interval,1,nnz(idx)); %// new set of random integers to be placed
%// at the positions where repetitions have occured
r(find(idx)+1) = rN; %// place ramdom integers at their respective positions
end

N-Dimensional Histogram Counts

I am currently trying to code up a function to assign probabilities to a collection of vectors using a histogram count. This is essentially a counting exercise, but requires some finesse to be able to achieve efficiently. I will illustrate with an example:
Say that I have a matrix X = [x1, x2....xM] with N rows and M columns. Here, X represents a collection of M, N-dimensional vectors. IN other words, each of the columns of X is an N-dimensional vector.
As an example, we can generate such an X for M = 10000 vectors and N = 5 dimensions using:
X = randint(5,10000)
This will produce a 5 x 10000 matrix of 0s and 1s, where each column is represents a 5 dimensional vector of 1s and 0s.
I would like to assign a probability to each of these vectors through a basic histogram count. The steps are simple: first find the unique columns of X; second, count the number of times each unique column occurs. The probability of a particular occurrence is then the #of times this column was in X / total number of columns in X.
Returning to the example above, I can do the first step using the unique function in MATLAB as follows:
UniqueXs = unique(X','rows')'
The code above will return UniqueXs, a matrix with N rows that only contains the unique columns of X. Note that the transposes are due to weird MATLAB input requirements.
However, I am unable to find a good way to count the number of times each of the columns in UniqueX is in X. So I'm wondering if anyone has any suggestions?
Broadly speaking, I can think of two ways of achieving the counting step. The first way would be to use the find function, though I think this may be slow since find is an elementwise operation. The second way would be to call unique recursively as it can also provide the index of one of the unique columns in X. This should allow us to remove that column from X and redo unique on the resulting X and keep counting.
Ideally, I think that unique might already be doing some counting so the most efficient way would probably be to work without the built-in functions.
Here are two solutions, one assumes all values are either 0's or 1's (just like the example in your description), the other does not. Both codes should be very fast (more so the one with binary values), even on large data.
1) only zeros and ones
%# random vectors of 0's and 1's
x = randi([0 1], [5 10000]); %# RANDINT is deprecated, use RANDI instead
%# convert each column to a binary string
str = num2str(x', repmat('%d',[1 size(x,1)])); %'
%# convert binary representation to decimal number
num = (str-'0') * (2.^(size(s,2)-1:-1:0))'; %'# num = bin2dec(str);
%# count frequency of how many each number occurs
count = accumarray(num+1,1); %# num+1 since it starts at zero
%# assign probability based on count
prob = count(num+1)./sum(count);
2) any positive integer
%# random vectors with values 0:MAX_NUM
x = randi([0 999], [5 10000]);
%# format vectors as strings (zero-filled to a constant length)
nDigits = ceil(log10( max(x(:)) ));
frmt = repmat(['%0' num2str(nDigits) 'd'], [1 size(x,1)]);
str = cellstr(num2str(x',frmt)); %'
%# find unique strings, and convert them to group indices
[G,GN] = grp2idx(str);
%# count frequency of occurrence
count = accumarray(G,1);
%# assign probability based on count
prob = count(G)./sum(count);
Now we can see for example how many times each "unique vector" occurred:
>> table = sortrows([GN num2cell(count)])
table =
'000064850843749' [1] # original vector is: [0 64 850 843 749]
'000130170550598' [1] # and so on..
'000181606710020' [1]
'000220492735249' [1]
'000275871573376' [1]
'000525617682120' [1]
'000572482660558' [1]
'000601910301952' [1]
...
Note that in my example with random data, the vector space becomes very sparse (as you increase the maximum possible value), thus I wouldn't be surprised if all counts were equal to 1...

Variable has "incorrect" value when submitted to Matlab Grader

I am struggling with my Matlab homework:
Write a script to do the following:
Generate a matrix called grades of size 8 x 25 that contains random numbers of type double in the range of 1 to 6.
Calculate the mean of matrix rows (mrow), the mean of matrix columns (mcol), and the overall mean (mall) of the matrix grades.
Copy the matrix grades to a new variable, in which you replace the elements in the 5th row and 20th to 23rd column with NaN. Compute the overall mean (mall_2) of this matrix again, i.e., the mean of the remaining values.
I am done with task 2-5, however, task 1 is not correct. I am not sure what I am doing wrong. I assume that it has something to do with the type of number (double), but I was unable to convert it.
We have to submit our homework to the online tool "Matlab Grader". The system says:
Matrix of random numbers : Variable grades has an incorrect value.
Here is my code:
% Generate matrix 'grades' with random numbers in the range 1 to 6
a = 1;
b = 6;
grades = (b-a).*rand(8,25) + a;
% calculate mean values 'mrow', 'mcol', 'mall'
mrow = mean(grades,2)
mcol = mean(grades,1)
mall = mean(grades(:))
% Replace elements with NaN
grades(5,20:23) = NaN
%Calculate mean of elements omitting NaN
mall_2 = mean(grades(:),'omitnan')
I assume your homework validation system is checking that everything in the variable grades is a (random) number in the range 1 to 6, as required by question 1.
However, by the end of your computation there are also 3 NaN values in the grades variable, because you missed this step of question 3:
Copy the matrix grades to a new variable
Instead, you overrode the elements in grades.
If you did this:
grades_mod = grades;
grades_mod(5,20:23) = NaN;
mall_2 = mean(grades_mod(:),'omitnan');
Then grades would retain its original values (no NaNs) and you can calculate mall_2.