How to separate rows of cells in a matrix using logical indexing? - matlab

l2 = [{'walk', 'water', 'warm', 'cheer', 'word', 'happy', 'whim', 'womb', 'wear', 'well'};
{'hello', 'here', 'hat', 'that', 'happy', 'hide', 'awesome', 'there', 'howl', 'harry'};
{'look', 'listen', 'lyer', 'hateful', 'lost', 'hatred', 'plot', 'player', 'plow', 'lay'};
{'goat', 'meat', 'hope', 'house', 'love', 'wall', 'down', 'up', 'sky', 'mount'};
{'go', 'golf', 'loser', 'gyrus', 'terrible', 'gallore', 'tug', 'thor', 'gear', 'leg'}];
So I have this data above, and I want to be able to separate each row in terms of it being either positive or negative.
As you can see above: My first row has 2 positive targets amongst neutral words and the third row has 2 negative targets amongst neutral words.
Now if I was running this where the participant saw each word in a sequence per row, how can I get an accuracy for their response to a row with positive targets vs negative target?
Any ideas?
Please help, I just cant figure it out
So far I was thinking of using logical indexing to separate positive targets and negative target, but how do I do that with cell rows?
I have this:
positive_t = [1 1; 1 1; 0 0; 1 1; 0 0]
This above denotes all the positive targets as 1 and negative targets as 0 but how would I be able to separate them properly row by row? Also. Then if I want to find how many time the participants got the answer for positive row vs negative row. How can I save the accuracy of that?

I assume 1) you want to test a person's ability to pick out positive or negative words and 2) you already have a standard answer ( as your test standard ) that you're going to compare testee's answer against.
I don't know what your definition of positive is, so I'm also being tested by you in a sense, but let's assume that you have this standard answer :
std_answer = logical([ 0 0 0 0 0 1 0 0 0 1;... % 'happy' and 'well'
0 0 0 0 1 0 1 0 0 0;... % 'happy' and 'awesome'
0 0 0 1 0 1 0 0 0 0;... % 'hateful' and 'hatred'
0 0 1 0 1 0 0 0 0 0;... % 'hope' and 'love'
0 0 1 0 1 0 0 0 0 0 ]); % 'loser' and 'terrible'
The std_answer here is an logical array that has the same number of elements as your l2. It has value of 1 wherever your answer is ( which of course, as a tester you already know. Here I'm just taking some guess and assume the standard answer to make an example) and 0 otherwise.
You can apply this mask to your l2 and the result will be your answers
answers = l2(std_answer);
If you really wish to do it row by row, of course you can do this:
for ii = 1:size(l2, 1)
sublist = l2(ii, :);
submask = std_answer(ii, :);
answer = sublist(submask);
end
At the end of the test, you'll have a testee response ( let's say you named it test_response) that's also a 5*10 logical array. You can compare the testee response to standard answer by using logical operation:
score = test_response & std_answer ;
score will also be a logical array whose 1 indicate a match between testee response and standard answer.

Related

How to deal with indexing involving three vectors?

I have the following three vectors:
trans_now=[1 2 4]; data2send=[1 0 0 1]; datasent=[0 0 0 0];
I want to set datasent to 1 for those nodes that are members of tran_now and whose data2send status is 1. e.g 4 is a member of trans_now and data2send(4) is 1 therefore datasent(4) should be set to 1.
I can do it using for loop and if statement as shown in the code below.
for i=1:length(trans_now)
if data2send(trans_now(i))==1
datasent(trans_now(i))=1;
end
end
However I want one liner code for this. The one liner code that I tried is
req_sent(req2send(trans_now)==1)=1;
But it doesn't work.
The output should set datasent vector to [1 0 0 1].
you could solve this in 2 ways:
1.
data_sent(trans_now) = data2send(trans_now)
the output is:
data_sent =
1 0 0 1
In this solution I assumed that all the initial values of data_sent are starting as 0 and that you need to assign it once.
2.
datasent(intersect(find(data2send == 1), trans_now)) = 1
output is:
data_sent =
1 0 0 1
In this solution no assumption is used and you assign only indices where data2send == 1 and also appear in trans_now

Comparing values across unequal matrices in Matlab

I would like to compare rows across two unequal matrices in Matlab and extract these rows to be stored in a different matrix (say D). For example,
tmp = [2245; 2345; 2290; 4576]
and
id=[1 2245 564 8890 123;
2 2445 5673 7846 342;
3 2290 3428 3321 908].
Id is a much larger matrix. I want to locate each value of tmp which is in ‘id’. Although using the intersect command in the line below I have been able to locate the rows of id which contain the values from tmp, I would like to do this for each value of tmp one by one as each value of tmp is repeated multiple times in id. I tried using foreach. However, I get an error message stating that foreach cannot be used for char type array. Could anyone please suggest an alternative how to go about this?
for j=1:length(tmp);
[D,itmp,id2] = intersect(tmp(j,1),id(:,2), 'rows');
Despite using the loop, the code doesn’t seem to take one value of j at a time. This was the reason behind trying ‘foreach j’. Also after finding the rows common to the two matrices and storing them in D, I would like to append matrix id to include the value of j next to the relevant row within id. For example, if the first value within tmp was repeated in id in rows 1,3,5,10; I would like a column in id which would take the value 1 next to rows 1,3,5,10. Any help on this would be much appreciated! Thanks.
Not sure exactly, what you trying to do, but to search a value in a matrix you can use find:
for i = 1:numel(tmp)
[row, col] = find(id == tmp(i));
end
You can easily achieve this using a combination of bsxfun and permute. What you would do is transform the tmp vector so that it is a single 3D vector, then use the eq (equals) function and see which values in your matrix are equal to each value of tmp. Therefore, do something like:
%// Your data
id=[1 2245 564 8890 123;
2 2445 5673 7846 342;
3 2290 3428 3321 908]
tmp = [2245; 2345; 2290; 4576];
tmp2 = permute(tmp, [3 2 1]); %// Make a 3D vector
tmp3 = bsxfun(#eq, id, tmp2); %// Find which locations of id are equal to each value of tmp
This is what I get for my final output, stored in tmp3:
tmp3(:,:,1) =
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0
tmp3(:,:,2) =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
tmp3(:,:,3) =
0 0 0 0 0
0 0 0 0 0
0 1 0 0 0
tmp3(:,:,4) =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
As you can see here, each 3D slice tells you which elements in id match the corresponding value in tmp. Therefore, the first slice tells you whether any element in id is equal to tmp(1), which is 2245. In this case, this would be the first row and second column. For the second slice, no values matched tmp(2) = 2345. For the third slice, one value in id matched tmp(3) = 2290, which is row 3, column 3.
Now, what you're really after is determining the rows and columns of where each value of tmp matched each location in id. You want this to be delineated per id number. That can easily be done using ind2sub and find on this matrix:
[rows, cols, ID] = ind2sub(size(tmp3), find(tmp3))
rows =
1
3
cols =
2
2
ID =
1
3
Therefore, ID tells you which id we have matched to, and rows, cols tells you which rows and columns in id we were able to match with. Therefore, for id = 1, we found a match with tmp(1)= 2245, and this is located at row=1,col=2. Similarly, for id = 3, we found a match with tmp(3)=2290 and this is at row=3,col=2.
To make this into all one big 2D matrix that contains all the information you want, you can simply concatenate all of these columns into one matrix. Therefore:
final = [ID rows cols]
final =
1 1 2
3 3 2
You can read this like so:
id=1 with tmp(1) = 2245, we found this value in row=1,col=2.
id=3, with tmp(3) = 2290, we found this value in row=3,col=2
Hope this helps!

How to make a general case of inserting ones in any type of matrix, in the non-principal diagonal

The title might be confusing, here's a particular example to explain myself. Also, I'm not sure how do you call the diagonal that starts in (1,2) and goes onward: (2,3) ; (3,4) and so on. Non-principal, non-main diagonal, not sure at all.
3x3 case
-1 1 0
-1 0 1
0 -1 1
4x4 case
-1 1 0 0
-1 0 1 0
-1 0 0 1
0 -1 1 0
0 -1 0 1
0 0 -1 1
So if the original matrix was a 4x4 (or any other size), I am able to make a matrix the size of the second example. I now have to insert the -1 and 1's in this fashion. This means n-1 number of -1's inserted if j=1, and then, a n-1 number of ones in the non-principal diagonal. When this is done, it's the same but for j=2 and the next non-principal diagonal, and so on.
Thing is, I'm thinking all the time about loops, and too many cases arise, because what I want is to be able to do this for any possible dimension, not for a particular case.
But then I saw this post Obtaining opposite diagonal of a matrix in Matlab
With this answer: A(s:s-1:end-1)
And it seems like a much cleaner way of doing it, since my own way (not finished since I'm not able to figure all the cases) has too many conditions. With a sentence like that, I could choose the diagonal, insert ones, and do it as many times as required, depending of the n dimension.
This leaves the problem of inserting the -1's, but I guess I could manage something.
It seems to mee that you want to obtain the following matrix B of size n × (n-1)*n/2
n = 4;
idx = fliplr(fullfact([n n]));
idx(diff(idx')<=0,:) = [];
m = size(idx,1);
B = zeros(m,n);
B(sub2ind(size(B),1:m,idx(:,1)')) = -1;
B(sub2ind(size(B),1:m,idx(:,2)')) = 1;
Approach #1
Here's a vectorized approach that has more memory requirements than a non-vectorized or for-loop based one. So, it could be tried out for small to medium sized datasizes.
The basic idea is this. For n=4 as an example, we take
-1 1 0 0
-1 0 1 0
-1 0 0 1
as the basic building block, replicate it n-1 i.e. 3 times and then remove the rows that aren't supposed to be part of the final output as per the requirements of the problem. Because of this very nature, this solution has more memory requirements, as we need to remove rows 6,8,9 for n = 4 case. But this gives us the opportunity to work with everything in one go.
N = n-1; %// minus 1 of the datasize, n
blksz = N*(N+1); %// number of elements in a (n-1)*n blocksize that is replicated
b1 = [-1*ones(N,1) eye(N)] %// Create that special starting (n-1)*n block
idx1 = find(b1~=0) %// find non zero elements for the starting block
idx2 = bsxfun(#plus,idx1,[0:N-1]*(blksz+N)) %// non zero elements for all blocks
b1nzr = repmat(b1(b1~=0),[1 N]) %// elements for all blocks
vald_ind = bsxfun(#le,idx2,[1:N]*blksz) %// positions of valid elements all blocks
mat1 = zeros(N,blksz) %// create an array for all blocks
mat1(idx2(vald_ind)) = b1nzr(vald_ind) %// put right elements into right places
%// reshape into a 3D array, join/concatenate along dim3
out = reshape(permute(reshape(mat1,N,N+1,[]),[1 3 2]),N*N,[])
%// remove rows that are not entertained according to the requirements of problem
out = out(any(out==1,2),:)
Approach #2
Here's a loop based code that could be easier to get a hold on if you have to explain it to yourself or just people and most importantly scales up pretty well on performance criteria across varying datasizes.
start_block = [-1*ones(n-1,1) eye(n-1)] %// Create that special starting (n-1)*n block
%// Find starting and ending row indices for each shifted block to be repeated
ends = cumsum([n-1:-1:1])
starts = [1 ends(1:end-1)+1]
out = zeros(sum(1:n-1),n) %// setup all zeros array to store output
for k1 = 1:n-1
%// Put elements from shifted portion of start_block for creating the output
out(starts(k1):ends(k1),k1:end) = start_block(1:n-k1,1:n-k1+1)
end
With n=4, the output -
out =
-1 1 0 0
-1 0 1 0
-1 0 0 1
0 -1 1 0
0 -1 0 1
0 0 -1 1
I don't know if I understood properly, but is this what you are looking for:
M=rand(5);
k=1; % this is to select the k-th diagonal
D=diag(ones(1,size(M,2)-abs(k)), k);
M(D==1)=-1;
M =
0.9834 -1.0000 0.8402 0.6310 0.0128
0.8963 0.1271 -1.0000 0.3164 0.6054
0.8657 0.6546 0.3788 -1.0000 0.5765
0.8010 0.8640 0.2682 0.4987 -1.0000
0.5550 0.2746 0.1529 0.7386 0.6550

MATLAB:how to summarize the ones in an vector?

For example:
a=[1 1 0 0 1 1 0 1 1 1 0 0];
Now i want to sum only the ones which are divides by the zeros:
ones=[2 2 3] - That means two ones,then we have 2 zeros which we do not count,then again two ones etc.
How can i do this?
Well, I would suggest finding all places where it switches from 0 to 1 and then finding all places where it switches from 1 to 0, and using those indices to find those lengths. The problem arises at the edges where if the first entry is 1, it doesn't switch to one from zero, and if the last entry is 1, we never find it because nothing switches to 0 at the end. In order to avoid this problem easily, we can add a 0 in the beginning and one at the end. This way we're guaranteed to find each one of those bursts of ones. In essence:
b = [0 a 0];
d = diff(b);
posEdge = find(d==1);
negEdge = find(d==-1);
countOnes = negEdge - posEdge

I Need help Numeric Comparison in matlab

I have one matrix called targets (1X4000); column 1 to 2000 contains double value 0 and column 2001 to 4000 contains double value 1
a)
i want to create a matrix called targets_1 where i want to check if the value is 0 then make the entry 1 so at the end of the day i must have a matrix with :column 1 to 2000 with value 1 and column 2001:4000 with value zero
b)
Same situation as above but this time i want to check if the value is 1 then make the entry 1 and if it is zero then make the entry zero; at the end; my new matrix targets_2 contains values: column 1 to 2000 with value zero and column 2001:4000 with value 1
i know how to use the strcmp function to make such checking with strings, but problem is that my original matrix is double and i dont know if there is such function like
setosaCmp = strcmp('setosa',species);
which could work with double (numbers); any help would be appreciated
Your question isn't very clear. It sounds like the following would satisfy your description:
targets_1 = 1 - targets;
targets_2 = targets;
targets1 = double(targets == 0);
targets2 = targets;
I'm basing this answer purely on the fact that you've mentioned setosaCmp = strcmp('setosa', species);. From this I'm guessing that
You have Statistics Toolbox, as setosa is a species of iris from the Fisher Iris dataset widely used in Statistics Toolbox demos, and
You have a variable containing class labels, and you'd like to construct some class indicator variables (i.e. a new variable for each class label, each of which is 1 when the item is in that class, and 0 when it's not).
Is that right? If not, please ignore me.
If I'm right, then I think the command you're looking for is dummyvar from Statistics Toolbox. Try this:
>> classLabels = [1, 2, 1, 2, 3, 1, 3];
>> dummyvar(classLabels)
ans =
1 0 0
0 1 0
1 0 0
0 1 0
0 0 1
1 0 0
0 0 1