I'm still fairly new to working with Matlab and programming. I have a dataset with n trials, of these (in this case) m are relevant. So I have an m-by-1 vector with the indices of the relevant trials (rel). I have another vector (Correct which is n-by-1) that consists of 0 and 1. n is always bigger than m. I need to know which trials (of the m-by-1 relevant trials) have a 1 in the n-by-1 vector. I have tried for-loops but I always get an error 'Index exceeds matrix dimensions.'
Here is my code:
for i=1:length(rel);
CC=rel(find(Correct==1));
end;
I think it should be fairly simple but I don't know yet how to explain to Matlab what I want...
Thank you all for your answers. I realized that my question was not as clear as I thought (also a learning process I guess..) so your suggestions weren't exactly what I need. I'm sorry for being unclear.
Correct is not a logical, it does contain 0 and 1 but these refer to correct or incorrect answer (I'm actually not sure if this matters but I thought I let you know)
rel is a subset of the original data with all trials (all trials=n trials), Correct is the same length as the original vector with all trials (n trials). So rel contains the indices of the (for me) relevant trials of the original data and is that way connected to Correct.
I hope this makes my question a bit more clear, if not, let me know!
Thank you!
It's not quite clear from your question what you are trying to do but I think I have an idea.
You have a vector n similar to
>> n = round(rand(1, 10))
n =
0 1 1 0 0 0 1 0 0 1
and m is indices of this vector similar to
>> m = [1 3 7 9];
Now we use m to index n as n(m) which will return the values of n corresponding to the elements in m. Next we need to check these for equality with 1 as n(m) == 1 and finally we need to figure out what values of m have n equal to 1 again by indexing. So putting this altogether we get
>> m(n(m) == 1)
ans =
3 7
To find the indices of m that are being returned you can use
>> find(n(m) == 1)
ans =
2 4
I'm assuming that Correct is of type logical (i.e. it contains trues and falses instead of 0s and 1s).
You actually don't need a loop here (this is clear in your case, since you are looping over i and never actually use i in your loop):
m = numel(rel)
CC = rel(Correct(1:m))
The reason you are getting that error is because Correct has more elements than rel so you are attempting to address elements beyond the end of rel. I solve this above by only considering the first m elements of Correct.
Related
I have checked other questions. I didn't find my answer. I have a matrix of n * 2 size. I want to compare the 1st and 2nd column and based on which is greater I want to assign 0/1 to the respective index. Suppose I want an output as
a = 1 2
4 3
7 8
I want the output like this
out = 0 1
1 0
0 1
I did this :
o1 = a(:,1) > a (:,2)
o2 = not(o1)
out = [o1, o2]
This does the job but I am sure there's a better way to do this. Need suggestions on that/.
Forgot to mention, the datatype is float in the matrix.
A more generic solution that can handle matrices with more than two columns:
out = bsxfun(#eq, a, max(a,[],2));
What you did is good. The number of lines doesn't really matter, what matters is the complexity of the operation in each line. Following the comments, I think you could gain some time as well by avoiding copy and multiple allocations:
out = false(size(a)); out(:,1) = (a(:,1) > a(:,2)); out(:,2) = ~out(:,1);
It is good practice to preallocate in Matlab, and in general to avoid copies in any programming language.
Optimizing further the runtime of this by using different operations is pointless IMO. If you really need speed you could Mex it to spare one iteration through the rows (second assignment), it's literally a dozen C lines, although you'd have to be careful about how you write the loop (the naive way would cause cache-miss at each iteration).
Introduction to problem:
I'm modelling a system where i have a matrix X=([0,0,0];[0,1,0],...) where each row represent a point in 3D-space. I then choose a random row, r, and take all following rows and rotate around the point represented by r, and make a new matrix from these rows, X_rot. I now want to check whether any of the rows from X_rot is equal two any of the rows of X (i.e. two vertices on top of each other), and if that is the case refuse the rotation and try again.
Actual question:
Until now i have used the following code:
X_sim=[X;X_rot];
if numel(unique(X_sim,'rows'))==numel(X_sim);
X(r+1:N+1,:,:)=X_rot;
end
Which works, but it takes up over 50% of my running time and i were considering if anybody in here knew a more efficient way to do it, since i don't need all the information that i get from unique.
P.S. if it matters then i typically have between 100 and 1000 rows in X.
Best regards,
Morten
Additional:
My x-matrix contains N+1 rows and i have 12 different rotational operations that i can apply to the sub-matrix x_rot:
step=ceil(rand()*N);
r=ceil(rand()*12);
x_rot=x(step+1:N+1,:);
x_rot=bsxfun(#minus,x_rot,x(step,:));
x_rot=x_rot*Rot(:,:,:,r);
x_rot=bsxfun(#plus,x_rot,x(step,:));
Two possible approaches (I don't know if they are faster than using unique):
Use pdist2:
d = pdist2(X, X_rot, 'hamming'); %// 0 if rows are equal, 1 if different.
%// Any distance function will do, so try those available and choose fastest
result = any(d(:)==0);
Use bsxfun:
d = squeeze(any(bsxfun(#ne, X, permute(X_rot, [3 2 1])), 2));
result = any(d(:)==0);
result is 1 if there is a row of X equal to some row of X_rot, and 0 otherwise.
How about ismember(X_rot, X, 'rows')?
I had a matrix D which is m*n and i am calculating the pseudo inverse using the formula inv(D'*D)*D' but it is not generating the same result as pinv(D).I need the term inv(D'*D) which i require for incremental operation. My all accuracy depends upon inv(D'*D) which is not correct. Is there any alternate way to get inv(D'*D) accurately? can any one help me please?
% D is 3x4 matrix that i had copied from one blog just for demonstration purpose. Actually original one of mine also had same problem bu its size is too large that i can't post it here.
D = -[1/sqrt(2) 1 1/sqrt(2) 0;0 1/sqrt(2) 1 1/sqrt(2);-1/sqrt(2) 0 1/sqrt(2) 1];
B1 = pinv(D)
B2 = D'*inv(D*D')
B1 =
-0.353553390593274 0.000000000000000 0.353553390593274
-0.375000000000000 -0.176776695296637 0.125000000000000
-0.176776695296637 -0.250000000000000 -0.176776695296637
0.125000000000000 -0.176776695296637 -0.375000000000000
Warning: Matrix is close to singular or badly scaled. Results may be inaccurate. RCOND =
1.904842e-017.
B2 =
-0.250000000000000 0 0.500000000000000
-0.500000000000000 0 0
0.250000000000000 -0.500000000000000 0
0 0 -0.750000000000000
I need inv(D'D) to do incremental operation. Actually in my problem at step 1, each time a new row will be added to the last position of D and in step 2 first row of the D will be removed. So i want to find final D inverse using the inverse which i calculated before these two steps. More precisely have a look here:
B = inv(D'*D); % if i can calculate it accurately then further work is as follows
D1 = [D;Lr]; %Lr is last row to be added
BLr = B-((B*Lr'*Lr*B)/(1+Lr*B*Lr')); % Row addition formula
Fr = D1(1,:); % First row to be removed
D2 = removerows(D1,1);
BFr = BLr+ ((BLr*Fr'*Fr*BLr)/(1-Fr*BLr*Fr')); % row deletion formula
B = BFr;
Y = BFr*D2;
The formulae (D^T D)^-1 D^T or D^T (D D^T)^-1 you are using for the Moore-Penrose pseudoinverse are only valid if D has full column or full row rank, respectively.
This is not true in your case, as the warning "Matrix is close to singular" shows.
The matlab pinv command works for arbitrary D, even if the matrix has neither full row or full column rank.
Try running cond(D) on your matrix and see what the condition number is. The higher the number, the more ill-conditioned your matrix is. Similarly, you can run cond(D'*D). A matrix can be full rank and still be ill-conditioned. On paper, an ill-conditioned matrix is still invertible. However, when you attempt to directly invert an ill-conditioned matrix on a computer, small precision errors caused by quantization and other effects can cause wildly undpredictable results in the solution.
For the above stated reason, there is usually a better way (more numerically stable) to achieve what you are after than to compute the inverse directly. Many of these involve matrix decomposotion techniques such as SVD. If you help us understand why you need inv(D'*D) it would be easier to point you in the direction of the appropriate alternative. For example, if you just need the pseudo-inverse, go ahead and use pinv(), even though it differs from your result using inv(). The pinv() function and the \ (mldivide) backslash operator are much more numerically stable tools than inv().
See the official documentation at http://www.mathworks.com/help/matlab/ref/pinv.html .
If A x ~ b, the solution x = pinv(A) * b produces the minimum-norm solution, but x = A\b doesn't. See the numerical example at the link above.
I was looking to find the most efficient way to find the non zero minimum of a matrix and found this on a forum :
Let the data be a matrix A.
A(~A) = nan;
minNonZero = min(A);
This is very short and efficient (at least in number of code lines) but I don't understand what happens when we do this. I can't find any documentation about this since it's not an operation on matrices like +,-,\,... would be.
Could anyone explain me or give me a link or something that could help me understand what is done ?
Thank you !
It uses logical indexing
~ in Matlab is the not operator. When used on a double array, it finds all elements equal to zero. e.g.:
~[0 3 4 0]
Results in the logical matrix
[1 0 0 1]
i.e. it's a quick way to find all the zero elements
So if A = [0 3 4 0] then ~A = [1 0 0 1] so now A(~A) = A([1 0 0 1]). A([1 0 0 1]) uses logical indexing to only affect the elements that are true so in this case element 1 and element 4.
Finally A(~A) = NaN will replace all the elements in A that were equal to 0 with NaN which min ignores and thus you find the smallest non-zero element.
The code you provided:
A(~A) = NaN;
minNonZero = min(A);
Does the following:
Create a logical index
Apply the logical index on A
Change A, by assigning NaN values
Get the minimum of all values, while not including NaN values
Note that this leaves you with a changed A, which may be indesirable. But more importantly this has some inefficiencies as you spend time changing A and possibly even because you get the minimum of a large matrix.
Therefore you could speed things up (and even reduce one line) by doing:
minNonZero = min(A(logical(A)))
Basically you have now skipped step 3 and possibly reduced step 4.
Furthermore, you seem to get an additional small speedup by doing:
minNonZero = min(A(A~=0))
I don't have any good reason for this, but it seems like step 1 is now done more efficiently.
In Matlab, suppose I would like to create a 0-vector of length L, except with a 1 at index i?
For example, something like:
>> mostlyzeros(6, 3)
ans =
0 0 1 0 0 0
The purpose is so I can use it as a 'selection' vector which I'll multiply element-wise with another vector.
The simplest way I can think of is this:
a = (1:N)==m;
where N>=m. Having said that, if you want to use the resulting vector as a "selection vector", I don't know why you'd multiply two vectors elementwise, as I would expect that to be relatively slow and inefficient. If you want to get a vector containing only the m-th value of vector v in the m-th position, this would be a more straightforward method:
b = ((1:N)==m)*v(m);
Although the most natural method would have to be this:
b(N)=0;
b(m)=v(m);
assuming that b isn't defined before this (if b is defined, you need to use zeros rather than just assigning the Nth value as zero - it has been my experience that creating a zero vector or matrix that didn't exist before that is most easily done by assigning the last element of it to be zero - it's also useful for extending a matrix or vector).
I'm having a hard time thinking of anything more sensible than:
Vec = zeros(1, L);
Vec(i) = 1;
But I'd be happy to be proven wrong!
UPDATE: The one-liner solution provided by #GlenO is very neat! However, be aware that if efficiency is the chief criteria, then a few speed tests on my machine indicate that the simple method proposed in this answer and the other two answers is 3 or 4 times faster...
NEXT UPDATE: Ah! So that's what you mean by "selection vectors". #GlenO has given a good explanation of why for this operation a vector of ones and zeros is not idiomatic Matlab - however you choose to build it.
ps Try to avoid using i as a subscript, since it is actually a matlab function.
Just for the fun of it, another one-liner:
function [out] = mostlyzeros(idx, L)
out([L, idx]) = [0 1];
I can think of:
function mostlyones(m,n)
mat=zeros(1,m);
mat(n)=1;
Also, one thing to note. In MATLAB, index starts from one and not from zero. So your function call should have been mostlyzeros(6,3)
I would simply create a zero-vector and change whatever value you like to one:
function zeroWithOne(int numOfZeros, int pos)
a = zeros(numOfZeros,1);
a(pos) = 1;
Another one line option, which should be fast is:
vec = sparse(1, ii, 1, 1, L);