I have a matrix which is 9x10000 size.
So rows are R1, R2, upto R9.
I want to generate all possible combination of the rows such as
[R1;R2] [R1;R3].. [R1;R9]
[R1;R2;R3]...[R1;R2;R4]... [R1;R2:R3;R4;..R8]
I am currently doing this using for loops.
Is there any better way of doing this.
Basically, counting up the binary from 1 to 2^9-i indicates which rows need to be selected:
M=... your matrix
S=dec2bin(1:2^size(M,1)-1)=='1';
allSubsets=cell(size(S,1),1);
for ix=1:size(S,1)
allSubsets{ix}=M(find(S(ix,:)),:);
end
As in the comment, I'm not sure if you always want the first row. This code doesn't do that, but you can modify it for that easily enough. It still uses for loops, but relies on the "nchoosek" function for the row index generation.
%generate data matrix
nMax=9; %number of rows
M=rand(nMax,1e4); %the data
%cell array of matrices with row combinations
select=cell(2^nMax-nMax-1,1); %ignore singletons, empty set
%for loop to generate the row selections
idx=0;
for i=2:nMax
%I is the matrix of row selections
I=nchoosek(1:nMax,i);
%step through the row selections and form the new matrices
for j=1:size(I,1)
idx=idx+1; %idx tracks number of entries
select{idx}=M(I(j,:),:); %select{idx} is the new matrix with selected rows
%per Floris' comment above you could do
%select{idx}=I(j,:); %save the selection for later
end
end
The function nchoosek, when given a vector, will return all possible ways to choose k values from that vector. You can trick it into giving you what you want with
allCombis = unique(nchoosek([zeros(1,9) 1:9], 9), 'rows');
This will include all possible ways to select 9 values from the set that includes nine zeros, plus the indices of each of the rows. Now you have every possible combination (including "no row at all"). With this matrix generated just once, you can find any combination easily - without having to store them all in memory. You can now pick you combination:
thisNumber = 49; % pick any combination
rows = allCombis(thisNumber, :);
rows(rows==0)=[]; % get rid of the zeros
thisCombination = myMatrix(rows, :); % pick just the rows corresponding to this combination
Related
I'm trying to generate a 3x2 matrix. Each row is generated using randperm(3,2). This means each row is generated as a vector with 2 unique integers with values between 1 and 3.
The problem is that I want each new row to be different than all the previous. For example, if one row is [1 3] then no other row can be:
[1 3], nor
[3 1].
I tried checking the sum AND the multiplied value of each newly created row. (Using our example 1+3=4 and 1*3=3)
My idea is that the multiplied value and the sum value of each new generated row is compared to the multiplied value and sum value of every other row that comes before it. If any of these values are the same (which means we will get a repetition), we keep generating a new row using randperm(3,2) until a completely new row is obtained.
My code checks each each row before one at a time, and "forgets" every other row that it previously checked. It does not take into consideration ALL the previous rows, instead it only iterates back one step at a time. I tried using something like parents(i:-1:1) instead of parents(i-k,1) etc but couldn't make it work.
Question: How can I do this comparison?
parents=randperm(3,2);
for i=2:3
parents=[parents; randperm(3,2)]
for k=1:i-1
while prod(parents(i,:))==prod(parents(i-k,:)) && sum(parents(i,:))==sum(parents(i-k,:))
parents(i,:)=randperm(3,2)
end
end
i=i+1;
end
Download this function, then use it as follows:
% generate all the possible permutations
p = permn(1:3,2);
% generate a random permutation of the indices and take the first three
r = randperm(size(p,1));
idx = r(1:3);
% take three random rows from the possible permutations using the indices
result = p(idx,:);
This way:
you will never obtain a row identical to another one in your result matrix
you won't be forced to use a "shuffle until condition is met" approach
you have a reusable and flexible approach
I have a 5-by-200 matrix where the i:50:200, i=1:50 are related to each other, so for example the matrix columns 1,51,101,151 are related to each other, and columns 49,99,149,199 are also related to each other.
I want to use a for-loop to create another matrix that re-sorts the previous matrix based on this relationship.
My code is
values=zeros(5,200);
for j=1:50
for m=1:4:200
a=factor_mat(:,j:50:200)
values(:,m)=a
end
end
However, the code does not work.
Here's what's happening. Let's say we're on the first iteration of the outer loop, so j == 1. This effectively gives you:
j = 1;
for m=1:4:200
a=factor_mat(:,j:50:200)
values(:,m)=a;
end
So you're creating the same submatrix for a (j doesn't change) 50 times and storing it at different places in the values matrix. This isn't really what you want to do.
To create each 4-column submatrix once and store them in 50 different places, you need to use j to tell you which of the 50 you're currently processing:
for j=1:50
a=factor_mat(:,j:50:200);
m=j*4; %// This gives us the **end** of the current range
values(:,m-3:m)=a;
end
I've used a little trick here, because the indices of Matlab arrays start at 1 rather than 0. I've calculated the index of the last column we want to insert. For the first group, this is column 4. Since j == 1, j * 4 == 4. Then I subtract 3 to find the first column index.
That will fix the problem you have with your loops. But loops aren't very Matlab-ish. They used to be very slow; now they're adequate. But they're still not the cool way to do things.
To do this without loops, you can use reshape and permute:
a=reshape(factor_mat,[],50,4);
b=permute(a,[1,3,2]);
values=reshape(b,[],200);
I'm struggling with one of my matlab assignments. I want to create 10 different models. Each of them is based on the same original array of dimensions 1x100 m_est. Then with for loop I am choosing 5 random values from the original model and want to add the same random value to each of them. The cycle repeats 10 times chosing different values each time and adding different random number. Here is a part of my code:
steps=10;
for s=1:steps
for i=1:1:5
rl(s,i)=m_est(randi(numel(m_est)));
rl_nr(s,i)=find(rl(s,i)==m_est);
a=-1;
b=1;
r(s)=(b-a)*rand(1,1)+a;
end
pert_layers(s,:)=rl(s,:)+r(s);
M=repmat(m_est',s,1);
end
for k=steps
for m=1:1:5
M_pert=M;
M_pert(1:k,rl_nr(k,1:m))=pert_layers(1:k,1:m);
end
end
In matrix M I am storing 10 initial models and want to replace the random numbers with indices from rl_nr matrix into those stored in pert_layers matrix. However, the last loop responsible for assigning values from pert_layers to rl_nr indices does not work properly.
Does anyone know how to solve this?
Best regards
Your code uses a lot of loops and in this particular circumstance, it's quite inefficient. It's better if you actually vectorize your code. As such, let me go through your problem description one point at a time and let's code up each part (if applicable):
I want to create 10 different models. Each of them is based on the same original array of dimensions 1x100 m_est.
I'm interpreting this as you having an array m_est of 100 elements, and with this array, you wish to create 10 different "models", where each model is 5 elements sampled from m_est. rl will store these values from m_est while rl_nr will store the indices / locations of where these values originated from. Also, for each model, you wish to add a random value to every element that is part of this model.
Then with for loop I am choosing 5 random values from the original model and want to add the same random value to each of them.
Instead of doing this with a for loop, generate all of your random indices in one go. Since you have 10 steps, and we wish to sample 5 points per step, you have 10*5 = 50 points in total. As such, why don't you use randperm instead? randperm is exactly what you're looking for, and we can use this to generate unique random indices so that we can ultimately use this to sample from m_est. randperm generates a vector from 1 to N but returns a random permutation of these elements. This way, you only get numbers enumerated from 1 to N exactly once and we will ensure no repeats. As such, simply use randperm to generate 50 elements, then reshape this array into a matrix of size 10 x 5, where the number of rows tells you the number of steps you want, while the number of columns is the total number of points per model. Therefore, do something like this:
num_steps = 10;
num_points_model = 5;
ind = randperm(numel(m_est));
ind = ind(1:num_steps*num_points_model);
rl_nr = reshape(ind, num_steps, num_points_model);
rl = m_est(rl_nr);
The first two lines are pretty straight forward. We are just declaring the total number of steps you want to take, as well as the total number of points per model. Next, what we will do is generate a random permutation of length 100, where elements are enumerated from 1 to 100, but they are in random order. You'll notice that this random vector uses only a value within the range of 1 to 100 exactly once. Because you only want to get 50 points in total, simply subset this vector so that we only get the first 50 random indices generated from randperm. These random indices get stored in ind.
Next, we simply reshape ind into a 10 x 5 matrix to get rl_nr. rl_nr will contain those indices that will be used to select those entries from m_est which is of size 10 x 5. Finally, rl will be a matrix of the same size as rl_nr, but it will contain the actual random values sampled from m_est. These random values correspond to those indices generated from rl_nr.
Now, the final step would be to add the same random number to each model. You can certainly use repmat to replicate a random column vector of 10 elements long, and duplicate them 5 times so that we have 5 columns then add this matrix together with rl.... so something like:
a = -1;
b = 1;
r = (b-a)*rand(num_steps, 1) + a;
r = repmat(r, 1, num_points_model);
M_pert = rl + r;
Now M_pert is the final result you want, where we take each model that is stored in rl and add the same random value to each corresponding model in the matrix. However, if I can suggest something more efficient, I would suggest you use bsxfun instead, which does this replication under the hood. Essentially, the above code would be replaced with:
a = -1;
b = 1;
r = (b-a)*rand(num_steps, 1) + a;
M_pert = bsxfun(#plus, rl, r);
Much easier to read, and less code. M_pert will contain your models in each row, with the same random value added to each particular model.
The cycle repeats 10 times chosing different values each time and adding different random number.
Already done in the above steps.
I hope you didn't find it an imposition to completely rewrite your code so that it's more vectorized, but I think this was a great opportunity to show you some of the more advanced functions that MATLAB has to offer, as well as more efficient ways to generate your random values, rather than looping and generating the values one at a time.
Hopefully this will get you started. Good luck!
I would like to generate all possible combinations for selecting rows in batches of lets say 'k' size. For example, matrix A has 3 rows and I want all combinations for batch size 2, i.e. rows (1,2)(1,3)(2,3). What would be the simplest way to do it? Then I would like use them for some operation like myfunction();
I think nchoosek function does the trick of selecting the combination but then how can I use each row of the output from nchoosek as index for my matrix?
If you want to use each combination one by one you can do something like this:
A = rand(3);
comb = nchoosek(length(A), 2);
for i = 1:size(comb, 1)
myfunction(A(comb(i, :), :));
end
A(comb(i, :)) is a k x n matrix (here 3 x 2) corresponding to the i-th combination of rows.
Starting wish a 7x4 binary matrix I need to change a random bit in each column to simulate error. Have been trying to no avail.
A very straightforward way to do this is to use a for loop. It might not be the most efficient approach in MATLAB, but it's probably good enough considering your data set is so small.
Iterate through each of the four columns. On each iteration, randomly chose a number from 1 to 7 to represent the row in that column that you have selected to change. Finally, flip the bit at that row/column. The following code does just this. Assume that "A" is a binary matrix with 7 rows and 4 columns
for col=1:4; %// Iterate through each column
row = ceil(7*rand()); %// Randomly chose a number from 1 to 7 to represent row
A(row,col) = ~A(row,col); %// Flip the bit at the specified row/col
end
Another possibility is to create 4 random numbers in one call, and assign in a vectorized fashion:
rowNumbers = randi(4,[1 4])
A(rowNumbers,:) = ~A(rowNumbers,:);