construct a matrix by removing different elements from an array without loops in matlab - arrays

Given a vector X of discrete positive integers with size 160*1, and a table Tb1 in size 40*200, that contains a list of indices to be deleted from X Each column from the 200 columns in Tb1 points to 40 elements to be deleted from original X.
I create a new matrix of the remaining 120*200 elements by using a for loop with 200 iterations, that at round i deletes 40 elements from a copy of the original X according to the indices listed in Tb1(:,i), but it takes too much time and memory.
How can I get the result without using loops and with a minimum number of operations?

Here are different methods:
Method1:
idx = ~hist(tbl, 1:160);
[f,~]=find(idx);
result1 = reshape(M(f),120,200);
Method2:
idx = ~hist(tbl, 1:160);
M2=repmat(M,200,1);
result2 = reshape(M2(idx),120,200);
Method 3 & 4:
% idx can be generated using accumarray
idx = ~accumarray([tbl(:) reshape(repmat(1:200,40,1),[],1)],true,[160,200],#any);
%... use method 1 and 2
Method5:
M5=repmat(M,200,1);
M5(bsxfun(#plus,tbl,0:160:160*199))=[];
result5 = reshape(M5,120,200);
Assuming that M is an array of integers and tbl is the table of indices.
It can be tested with the following data:
M = rand(160,1);
[~,tbl] = sort(rand(160,200));
tbl = tbl(1:40,:);
However it is more efficient if you generate indices of elements to be remained instead of indices of elements to be removed.

Related

Adding multiple rows in Array

I have an array A size of 16X16 and I want to add first 3 rows out of 16 in A. What is the most efficient solution in MATLAB?
I tried this code but this is not efficient because I want to extend it for large arrays:
filename = 'n1.txt';
B = importdata(filename);
i = 1;
D = B(i,:)+ B(i+1,:)+ B(i+2,:);
For example, if I want to extend this for an array of size 256x256 and I want to extract 100 rows and add them, how I will do this?
A(1:3,:);%// first three rows.
This uses the standard indices of matrix notation. Check Luis's answer I linked for the full explanation on indices in all forms. For summing things:
B = A(1:100,:);%// first 100 rows
C = sum(B,1);%// sum per column
D = sum(B,2);%// sum per row
E = sum(B(:));%// sum all elements, rows and columns, to a single scalar

How do I create random Boolean array with at least one 1 in each row in matlab?

I am trying to create roandom boolean arrays in Matlab with atleast one 1 in each row.
you can use randi to generate random integers?
A = randi([0 1], 50, 10);
Generate a 50-by-10 array of integer values drawn uniformly from 0 or 1 and
you can convert matrix to dataset array by
ds = mat2dataset(A);
to convert a binary row to a number - as in the previous answers:
bin2dec(num2str(A(n,:)));
Suppose you want a random logical (boolean) matrix of size m-by-n with roughly p=0.25 entries set to true at each row but not less than one, then you can simply:
P = rand(m,n); %// generate random numbers in [0,1]
th = min( max(P,[],2), 1-p ); %// set threshold
B = bsxfun( #ge, P, th ); %// threshold the probability matrix to get random boolean entries
Note that the threshold is determined by the amount of true values you want per row, but it is also truncated to the max value of each row, ensuring that at least one element (at random) will be set to true.
Here's one way. Let
M = 5; %// number of columns
N = 4; %// number of rows
p = .5; %// initial probability of 1
You can generate the matrix with the given probability of ones, and then fill in a one at a random position in each row (possibly overwriting a zero) to make sure there's at least a one in each row:
result = rand(M,N)<p; %// generate matrix
result(bsxfun(#plus, floor(N*rand(1,M))*M, 1:M)) = 1; %// at least a one per row

Is there a better/faster way of randomly shuffling a matrix in MATLAB?

In MATLAB, I am using the shake.m function (http://www.mathworks.com/matlabcentral/fileexchange/10067-shake) to randomly shuffle each column. For example:
a = [1 2 3; 4 5 6; 7 8 9]
a =
1 2 3
4 5 6
7 8 9
b = shake(a)
b =
7 8 6
1 5 9
4 2 3
This function does exactly what I want, however my columns are very long (>10,000,000) and so this takes a long time to run. Does anyone know of a faster way of achieving this? I have tried shaking each column vector separately but this isn't faster. Thanks!
You can use randperm like this, but I don't know if it will be any faster than shake:
[m,n]=size(a)
for c = 1:n
a(randperm(m),c) = a(:,c);
end
Or you can try switch the randperm around to see which is faster (should produce the same result):
[m,n]=size(a)
for c = 1:n
a(:,c) = a(randperm(m),c);
end
Otherwise how many rows do you have? If you have far fewer rows than columns, it's possible that we can assume each permutation will be repeated, so what about something like this:
[m,n]=size(a)
cols = randperm(n);
k = 5; %//This is a parameter you'll need to tweak...
set_size = floor(n/k);
for set = 1:set_size:n
set_cols = cols(set:(set+set_size-1))
a(:,set_cols) = a(randperm(m), set_cols);
end
which would massively reduce the number of calls to randperm. Breaking it up into k equal sized sets might not be optimal though, you might want to add some randomness to that as well. The basic idea here though is that there will only be factorial(m) different orderings, and if m is much smaller than n (e.g. m=5, n=100000 like your data), then these orderings will be repeated naturally. So instead of letting that occur by itself, rather manage the process and reduce the calls to randperm which would be producing the same result anyway.
Here's a simple vectorized approach. Note that it creates an auxiliary matrix (ind) the same size as a, so depending on your memory it may be usable or not.
[~, ind] = sort(rand(size(a))); %// create a random sorting for each column
b = a(bsxfun(#plus, ind, 0:size(a,1):numel(a)-1)); %// convert to linear index
Obtain shuffled indices using randperm
idx = randperm(size(a,1));
Use the indices to shuffle the vector:
m = size(a,1);
for i=1:m
b(:,i) = a(randperm(m,:);
end
Look at this answer: Matlab: How to random shuffle columns of matrix
Here's a no-loop approach as it processes all indices at once and I believe this is as random as one could get given the requirements of shuffling among each column only.
Code
%// Get sizes
[m,n] = size(a);
%// Create an array of randomly placed sequential indices from 1 to numel(a)
rand_idx = randperm(m*n);
%// segregate those indices into rows and cols for the size of input data, a
col = ceil(rand_idx/m);
row = rem(rand_idx,m);
row(row==0)=m;
%// Sort both these row and col indices based on col, such that we have col
%// as 1,1,1,1 ...2,2,2,....3,3,3,3 and so on, which would represent per col
%// indices for the input data. Use these indices to linearly index into a
[scol,ind1] = sort(col);
a(1:m*n) = a((scol-1)*m + row(ind1))
Final output is obtained in a itself.

How to obtain a vector with the indexes of the elements given in a combination?

I have a vector that stores unique area values. I am using a for loop to generate an array with the sum of every possible combination of these areas, as shown below:
A_values=[155 143 193.5 233.25 419.7 351.9 256.8 1054.9 997.5 997.5 726.2 73.5 66.8 62 82.5]
comb_sums=[];
indexes=[];
for x=1:length(A_values)
comb_sums=[comb_sums;
sum(combntns(A_values,x),2)];
end
Now I would like to obtain the indexes of the elements given in every combination. For example, if some of the possible given combinations had been [143], [726.2 66.8] and [155 419.7 256.8], the code would give me an array like this:
indexes=[ 2 0 0 0;
11 13 0 0;
1 5 7 0];
The array that I get from the for loop is obviously much bigger than the example given in the indexes variable above, so indexes would give me a much bigger array too.
You can create an array of indices and use combntns on it, just you like did on A_values -
nA = numel(A_values)
for k1 = 1:nA
comb_out = combntns([1:nA],k1);
indexes = [comb_out zeros(size(comb_out,1),nA - size(comb_out,2))]
end
If you would like to store up indexes from each iteration into a huge array named indexes_all instead, you can pre-calculate the sizes of indexes for each iteration and use them to pre-allocate for indexes_all. The code would be -
%// Number of A_values to be used at various places in the code
nA = numel(A_values);
%// Get number of rows to be produced at each iteration
nrows = arrayfun(#(x) factorial(nA)/(factorial(x)*factorial(nA-x)),1:nA);
%// Preallocate with zeros as also needed in the desired output
indexes_all = zeros(sum(nrows),nA);
off1 = 1; %// row-offset
for k1 = 1:nA
comb_out = combntns(1:nA,k1); %// combntns on array of indices
indexes_all(off1:off1+nrows(k1)-1,1:size(comb_out,2)) = comb_out; %// Store
off1 = off1+nrows(k1); %// Update row-offset for next set of combinations
end

Turning an array in to a matrix in MATLAB

I need to turn a large array into a matrix in the following way: to take the first m entries of the array and make that the 1st row of the matrix.
For example: if I had an array that was 100 entries long, the corresponding matrix would be 10 rows and each row would be 10 entries of the array with the order preserved.
I've tried the following code:
rows = 10
row_length = 10
a = randi(1,100);
x = zeros(rows,row_length)
for i=1:rows
x(i) = a(i:i+row_length)
end
but with no luck. I'm stuck on how to slide the window along by row_length so that i will start from row_length+1 in the second (and subsequent) iterations of the loop.
The best way to do it is to use Matlab's reshape function:
reshape(a,row_length,[]).'
It will reshape by first assigning down the columns which is why I transpose at the end (i.e. .')
However just for the sake of your learning, this is how you could have done it your way:
rows = 10
row_length = 10
a = rand(1,100)
x = zeros(rows,row_length)
for i=1:row_length:rows*row_length %// use two colons here, the number between them is the step size
x(i:i+row_length-1) = a(i:i+row_length-1) %// You need to assign to 10 elements on the left hand side as well!
end

Resources