Select all elements except one in a vector - matlab

My question is very similar to this one but I can't manage exactly how to apply that answer to my problem.
I am looping through a vector with a variable k and want to select the whole vector except the single value at index k.
Any idea?
for k = 1:length(vector)
newVector = vector( exluding index k); <---- what mask should I use?
% other operations to do with the newVector
end

Another alternative without setdiff() is
vector(1:end ~= k)

vector([1:k-1 k+1:end]) will do. Depending on the other operations, there may be a better way to handle this, though.
For completeness, if you want to remove one element, you do not need to go the vector = vector([1:k-1 k+1:end]) route, you can use vector(k)=[];

Just for fun, here's an interesting way with setdiff:
vector(setdiff(1:end,k))
What's interesting about this, besides the use of setdiff, you ask? Look at the placement of end. MATLAB's end keyword translates to the last index of vector in this context, even as an argument to a function call rather than directly used with paren (vector's () operator). No need to use numel(vector). Put another way,
>> vector=1:10;
>> k=6;
>> vector(setdiff(1:end,k))
ans =
1 2 3 4 5 7 8 9 10
>> setdiff(1:end,k)
Error using setdiff (line 81)
Not enough input arguments.
That is not completely obvious IMO, but it can come in handy in many situations, so I thought I would point this out.

Very easy:
newVector = vector([1:k-1 k+1:end]);
This works even if k is the first or last element.

%create a logic vector of same size:
l=ones(size(vector))==1;
l(k)=false;
vector(l);

Another way you can do this which allows you to exclude multiple indices at once (or a single index... basically it's robust to allow either) is:
newVector = oldVector(~ismember(1:end,k))
Works just like setdiff really, but builds a logical mask instead of a list of explicit indices.

Related

Opposite indices when using find-function

i searched a lot in google but didnt find an answer that did help me without reducing my performance.
I have a Matrice A and B of the same size with different values. Then i want to filter:
indices=find(A<5 & B>3)
A(indices)=
B(indices)=
Now I want to apply a function on the indices -> indices_2=find(A>=5 | b<=3) without using the find function on the whole matrices A and B again. Logic operations are not possible in this case because I need the indices and not 0 and 1.
Something like:
A(~indices)=
B(~indices)=
instead of:
indices_2=find(A>=5 | B<=3)
A(indices_2)=
B(indices_2)=
And after that I want to split these sets once again.... Just Filtering.
I used indices_2=setdiff(indices, size(A)) but it did screw my computation performance. Is there any other method to split the matrices into subsets without using find twice?
Hope you understand my problem and it fits the regulations.
I don't understand why you can't just use find again, nor why you can't use logical indexing in this case but I suppose if you are going to restrict yourself like this then you could accomplish this using setdiff:
indices_2 = setdiff(1:numel(A), indices)
however, if you are worried about performance, you should be sticking to logical indexing:
indices = A<5 & B>3
A(indices)=...
B(indices)=...
A(~indices)=...
B(~indices)=...
I think you may be looking for something like this:
%Split your data in two and keep track of which numbers you have
ranks = 1:numel(A);
indices= find(A<5 & B>3);
% Update the numbers list to contain the set of numbers you are interested in
ranks_2 = ranks(~indices)
% Operate on the set you are interested in and find the relevant ranks
indices_2= A(~indices)>=5 | B(~indices)<=3
ranks_2 = ranks_2(indices_2)

bsxfun() Invalid output dimensions

I have a function that takes upto seven arguments and returns a row vector. The first three arguments are vectors (column, column, row) and the remaining four are optional scalars.
I want to use bsxfun() to apply the function to a vector of its last argument. Below is my attempt to do that.
o = #(m,pulse,N0,samples_per_pulse,sample_select,filter,channel_cutoff) ELE452Functions.EvaluateBER(m,pulse,N0,samples_per_pulse,sample_select,filter,channel_cutoff);
oo = #(m,pulse,N0,samples_per_pulse,sample_select,filter,channel_cutoff) bsxfun(#(N0,channel_cutoff) o(m,pulse,N0,samples_per_pulse,sample_select,filter,channel_cutoff), N0' , channel_cutoff);
when I try to call the function with a vector, oo(m,pulse,N0,1,1,1,[0.5 0.2]); for example, I get this error:
Error using bsxfun
Invalid output dimensions.
I am not experienced in using bsxfun and I tried to follow the documentation.
Update:
May be this is a clearer way to ask my question:
I want to use bsxfun to rewrite (improve) the code below with out a loop.
for i=1:length(channel_normalized_cuttoffs)
BER_LPchannel(i,:) = ELE452Functions.EvaluateBER(m,pulse,N0,1,1,1,channel_normalized_cuttoffs(i));
end
The idea behind bsxfun is to evaluate a certain function for all possible combinations of two elements (b in bsxfun stands for binary), each coming from one of the arrays. (NB: This is valid if you use it with a row and a column vector. But bsxfun can also do more.)
What you want to achieve is simply: For all entries of a single array, evaluate a function.
So bsxfun is just not the correct choice here.
You could use arrayfun instead, but this still may not perform a lot better than your original for loop, as it looks like the Matlab JIT Compiler would be able to optimize most of it, considering it's simplicity.
As I don't have the code of your function, I'm not able to test it, but your solution might look a lot like this:
evalBER = #(CNcutoffi) ELE452Functions.EvaluateBER(m,pulse,N0,1,1,1,CNcutoffi);
BER_LPchannel = arrayfun(evalBER, channel_normalized_cuttoffs, 'UniformOutput', false)

vectorizing a nested loop where one loop variable depends on the other

I've recently learned how to vectorize a "simple" nested loop in a previous question I've asked. However, now I'm trying also to vectorize the following loop
A=rand(80,80,10,6,8,8);
I=rand(size(A1,3),1);
C=rand(size(A1,4),1);
B=rand(size(A1,5),1);
for i=1:numel(I)
for v=1:numel(C)
for j=1:numel(B)
for k=1:j
A(:,:,i,v,j,k)= A(:,:,i,v,j,k)*I(i)*C(v)*B(j)*((k-1>0)+1);
end
end
end
end
So now k depends in j... What have I tried so far:
The combination of j and k terms (i.e. B(j)*((k-1>0)+1) gives a triangular matrix that I manage to vectorize independently:
B2=tril([ones(8,1)*B']');
B2(2:end,2:end)=2*B2(2:end,2:end);
But that gives me the (j,k) matrix properly and not a way to use it to vectorize the remaining loop. Maybe I'm in the wrong path too... So how can I vectorize that type of loop?
In one of your comments to the accepted solution of the previous question, you mentioned that successive bsxfun(#times,..,permute..) based codes were faster. If that's the case, you can use a similar approach here as well. Here's the code that uses such a pattern alongwith tril -
B1 = tril(bsxfun(#times,B,[1 ones(1,numel(B)-1).*2]));
v1 = bsxfun(#times,B1, permute(C,[3 2 1]));
v2 = bsxfun(#times,v1, permute(I,[4 3 2 1]));
A = bsxfun(#times,A, permute(v2,[5 6 4 3 1 2]));
You were close. The vectorization you proposed indeed follows the (j,k) logic, but doing tril adds zeros in places where the loop doesn't go into. Using the solution for your previous question (#david's) is not complete as it multiplies all elements including these zero value elements that the loop doesn't go into. My solution to that, is to find these zero elements and replace them with 1 (so simple):
Starting with your code:
B2=tril([ones(8,1)*B']');
B2(2:end,2:end)=2*B2(2:end,2:end);
and following the vectorization shown in the previous question:
s=size(A);
[b,c,d]=ndgrid(I,C,B2);
F=b.*c.*d;
F(F==0)=1; % this is the step that is important for your case.
A=reshape(A,s(1),s(2),[]);
A=bsxfun(#times,A,permute(F(:),[3 2 1]));
A=reshape(A,s);
For the size of A used in the question this cuts about 50% of the run time, not bad...

Replace certain elements of matrix with NaN (MATLAB)

I have a vector, A.
A=[3,4,5,2,2,4;2,3,4,5,3,4;2,4,3,2,3,1;1,2,3,2,3,4]
Some of the records in A must be replaced by NaN values, as they are inaccurate.
I have created vector rowid, which records the last value that must be kept after which the existing values must be swapped to NaN.
rowid=[4,5,4,3]
So the vector I wish to create, B, would look as follows:
B=[3,4,5,2,NaN,NaN;2,3,4,5,3,NaN;2,4,3,2,NaN,NaN;1,2,3,NaN,NaN,NaN]
I am at a loss as to how to do this. I have tried to use
A(:,rowid:end)
to start selecting out the data from vector A. I am expecting to be able to use sub2ind or some sort of idx to do this, possibly an if loop, but I don't know where to start and cannot find an appropriate similar question to base my thoughts on!
I would very much appreciate any tips/pointers, many thanks
If you are not yet an expert of matlab, I would stick to simple for-loops for now:
B = A;
for i=1:length(rowid)
B(i, rowid(i)+1:end) = NaN;
end
It is always a sport to write this as a one-liner (see Mohsen's answer), but in many cases an explicit for-loop is much clearer.
A compact one is:
B = A;
B(bsxfun(#lt, rowid.', 1:size(A,2)))=NaN;

MATLAB 'cat()' function returning different matrix size

If I perform s.device_macs then I get back a <1x3503 cell> so I would expect this as the output of my concatenate but I have 2 things I'm unsure on when I use: a = cat(2,s.device_macs)
To concatenate previously I used cat(1,x) but this doesn't work however the number 2 lets it run and the second thing is that it returns a <1x603326 cell>, obviously much larger than when I don't try and use cat().
Thanks alot, from a MATLAB newbie!
s.device_macs is a 1 row (first dimension) x 3503 column (second dimension) vector. That is why you have to specify 2 in cat(2,s.device_macs), so that it concatenates along the second dimension -- the columns. My guess is that the 1x603326 result is a string with 603326 characters (in columns), but not entirely sure... hopefully someone else can help here.
I have used a cheating method of solving this. As I mentioned the ans was coming out correct and so I decided to just use this:
s.device_macs; % This gives the answer of <1x3503 cell>
macId = ans; % I now make macId copy answer
clear ans; % Now I wipe ans leaving me with just macId
I know this isn't an efficient method of coding compared to just knowing the language but duct-tape-esque fixes are fun to find :P.