Table comparison cell content reference from non cell array object - matlab

I have two tables with same variables. One table contain one row while other table contain more than one rows.
a=[1 2; 2 3],b=[2 3; 1 2]
S1=table(a,b)
a=[1 1],b=[1 1]
S2=table(a,b)
if all(S2{:,:}<S1{:,:}) & any(S2{:,:}<=S1{:,:})
S1=[S1;S2]
end
Where is the mistake in specifying table or cell? Even the conversion table2cell, table2struct, table2array did not work (getvar error was shown).
Table values are fixed. There is no addition, no replacement, but the appending only when the condition is satisfied. Final output is table with values as shown.
S1 = 3×2 table
a b
______ ______
1 2 2 3
2 3 1 2
1 1 1 1

The error is due to the fact that you are trying to compare two set of data (S1 and S2) that have different size.
S2{:,:}
1 1 1 1
S1{:,:}
1 2 2 3
2 3 1 2
If you want to compare each row of S1 against S2 you can use the function bsxfun:
to check S2 < S1
bsxfun(#lt,S2{:,:},S1{:,:})
to check S2 <= S1
bsxfun(#le,S2{:,:},S1{:,:})
This will lead to:
if all(bsxfun(#lt,S2{:,:},S1{:,:})) & any(bsxfun(#le,S2{:,:},S1{:,:}))
S1=[S1;S2]
end

Related

What is the easiest/ computationally efficient way to find the indexes at particular locations?

I have a matrix
m =
2 2 1
3 2 1
0 4 1
0 4 1
5 4 1
0 5 2
1 2 2
1 3 2
1 4 2
1 1 3
0 2 3
0 3 4
0 3 4
that is potentially of N x 3, where N can be very large.
I want to find the index in the first column (1-13) where i have zeros but only if there are duplicate rows or the rows are unique. I don't want rows that the 2nd and 3rd column are the same but the first column is other than zero. In other words, if there is a zero at the first column but its corresponding number in the second and third column are the same with another one that has a different number other than zero in the first column, then ignore the index of that zero. So, in the example above, i want to return only the indices 6, 11,12, 13. Index 3,4 should not be return because they violate the rule that there is a row similar to that (2nd and 3rd column) but the first column is different, as we can see below:
0 4 1
0 4 1
5 4 1
One slow solution would be to find the indices of the rows that the first column is 0 indm=m(:,1)==0 and then iterate over the rows of the matrix checking whether any other row exists in matrix (m) that has identical 2nd and 3rd columns but different 1st column. If such case does not exist then add the index of the row to the list to be returned by the program.
However, this method, would require "for loops" going over large matrices.
One way to solve this (assuming that a row is bad if there is any other row with the same columns 2 and 3) is to find all the different rows, and then checking whether the first column is the same everywhere.
%# uIdx is the same for sets of rows where m(i,2:3) is equal
[~,~,uIdx] = unique(m(:,2:3),'rows');
%# allZeros is true if all entries in the first column of m
%# corresponding to a set are the zero
allZeros = accumarray(uIdx,m(:,1),[],#(x)all(x==0));
%# a good row belongs to a set of rows from m(:,2:3)
%# where all corresponding entries in the first column are zeros
%# use allZeros(uIdx) to expand allZeros to size(m,1)
goodRowIndices = find(allZeros(uIdx) == true)
goodRowIndices =
6
11
12
13
Here is my solution:
mm = m(:,1)==0;
imm = find(mm);
[mu,~, imu] = unique(m(mm,2:3),'rows','stable');
[~,ia] = setdiff(mu,m(~mm,2:3),'rows');
X = imm(ismember(imu,ia));
Line 3 extract the unique lines beginning with 0; line 4 keeps only the lines that does not appear in the lines not beginning by 0, and line 5 get back the indexes of the lines to keep.
Not sure its the most efficient way, because of it involves two sorts.

MATLAB: Creating a matrix with all possible group combinations

I'm running an experiment with lots of conditions, and particular numbers of groups in each condition.
A. 3 groups
B. 3 groups
C. 2 groups
D. 3 groups
E. 3 groups
I've worked out that there are 3×3×2×3×3 = 162 possible combinations of groups.
I want to create a MATLAB matrix with 162 rows and 5 columns. That is, one row for each combination and one column to indicate the value for each group.
So, for instance, the first row would be [1 1 1 1 1], indicating that this combination is group 1 for all conditions. The second row would be [1 1 1 1 2], indicating that it's group 1 for all conditions except for the last which is group 2. The 162nd and final row would be [3 3 2 3 3].
M = 1 1 1 1 1
1 1 1 1 2
.........
3 3 2 3 3
What's the most efficient way to achieve this? I realise I could use a loop, but feel sure there's a better way. I thought maybe the perms function would work but I can't see how.
You can use combvec (see last line, the rest is only generating test data):
% A. 3 groups
% B. 3 groups
% C. 2 groups
% D. 3 groups
% E. 3 groups
ngroups = zeros(5, 1);
ngroups(1) = 3;
ngroups(2) = 3;
ngroups(3) = 2;
ngroups(4) = 3;
ngroups(5) = 3;
v = {};
for i = 1:length(ngroups)
v{i} = 1:ngroups(i) % generate a vector of valid group indices
end
% get all possible combinations
x = combvec( v{:} )
As this will return a 5 x 162 double you need to transpose the resulting matrix x:
x.'

(MATLAB) How can I copy certain multiple elements from certain rows of a matrix based upon the values of other elements in those rows?

So, I have large matrix (let's say dimensions are 160x6 and the name of the matrix is datamatrix). Next, let's say I have another matrix called datamatrix2 which has dimensions 80x2. Here's what I want to do:
find every row of datamatrix where the value in column 2 is 2 and the value in column 5 is 1,
and then take the value for column 3 and the value from column 6 of each of those rows and place them in column 1 and column 2, respectively, of datamatrix2.
So, for example:
Let's say that row 3 of datamatrix is the first row in datamatrix with a 2 in column 2 and a 1 in column 5. Let's say there is a 3.096 in column 3 of that row and a 10 in column 6 of that row. So, 3.096 would be placed in position 1,1 of data matrix2 and 10 would be placed in position 1,2 of datamatrix2.
Next, let's say that row 25 of datamatrix is the next row in datamatrix with a 2 in column 2 and a 1 in column 5. Let's say there is a 16.432 in column 3 of that row and a 15 in column 6 of that row. So, 16.432 would be placed in position 2,1 of data matrix2 and 15 would be placed in position 2,2 of datamatrix2.
This process would continue until all of the rows of datamatrix with a 2 in column 2 and a 1 in column 5 have been found.
Please let me know if anyone has any suggestions.
Mucho thanks!
G
When I follow your explanation rightly, what you want is:
index = (datamatrix(:,2) == 2) & (datamatrix(:,5) == 1);
datamatrix2 = datamatrix(index,[4,6]);
This solution uses logical indexing.index stores 1's and 0's depending on wheter the condition is fullfilled or not.
To start of with logical indexing it is easiest to start with a vector. Lets take x = [2 5 3 4 6]; and you want the first, second and fifth entry. Then x([1 2 5]) = [2 5 6]; This can also be expressed logically with x(logical([1 1 0 0 1])) = [ 2 5 6]; Notice how we have a true at every position we want.
The same can be applied when we want to access a matrix.
Lets take A = [1 2 3; 4 5 6; 7 8 9] as a sample matrix. The obvious way to access part of this matrix is something like A([1,2],[1,3]) = [1 3; 4 6]. We can now replace the index with a logical notation:
A([1,2],[1,3]) = A(logical([1 1 0]),logical([1 0 1])) = [1 3; 4 6].
Logical and vector notation can also be combined. In my code index is a logical representation of the columns we want, [4 6] is the vector notation of the rows we want. Therefore the right columns and rows will be selected.
I don't really know what exactly you are trying, but lets take a shot
First: find any value (here 6) in any column (here 2) and then take another value of the found rows from any column (here 5) (here with an example magic-matrix)
datamatrix = [magic(5) magic(5)];
myvalue = 2;
values = datamatrix(find(datamatrix(:,2)==myvalue), 5);
If you have 2 conditions for a row, then use this here
values = datamatrix(find((datamatrix(:,column1)==value1).*(datamatrix(:,column2)==value2)),column3);
if you need to get more than one value, say from two different columns, then you just need to replace column3with something like this
column3 --> [col1 col2 col3]
Summarizing, try this code here
values = datamatrix(find((datamatrix(:,2)==2).*(datamatrix(:,5)==1)),[3 6]);
datamatrix2(:,[1 2]) = values
The second statement may fail because of dimension errors. If so, you should maybe provide the datamatrix entries.

How to restructure histcounts for using with a 2d-matrix

I have a 250000x2-matrix in matlab, where in the first row I have a degree (int, 0-360°), and in the second a float-value corresponding to this value. My target is to count each occurence of a degree-value-pair (e.g. a row), and write the result in a nx3-matrix. n corresponds here with the number unique rows.
Thus my first step was to get all unique values (using unique(M, 'rows')) which works. But now I want to count all unique values. This was done by the following approach:
uniqu_val = unique(values, 'rows');
instance = histcounts(values(:), uniqu_val);
Here I have to enter a vector as second element, and not a matrix (uniqu_val is a nx2-dim-matrix). But I want to get the number of occurence for each unique row, therefore I can not use only one column of the matrix uniqu_val. In short: I want to use histcounts not only for a 1D-matrix as edge-value, but for a 2D-matrix. How can I solve this problem?
You can use the third output from unique and then use histcounts like so -
%// Find the unique rows and keep the order with 'stable' option
[uniq_val,~,row_labels] = unique(values, 'rows','stable')
%// Find the counts/instances
instances = histcounts(row_labels, max(row_labels))
%// OR with HISTC: instances = histc(row_labels, 1:max(row_labels))
%// Output the unique rows alongwith the counts
out = [uniq_val instances(:)]
Sample run -
>> values
values =
2 1
3 1
2 3
3 3
1 2
3 3
1 3
3 1
3 2
1 2
>> out
out =
2 1 1
3 1 2
2 3 1
3 3 2
1 2 2
1 3 1
3 2 1

comparing multiple columns of matrix together

I have a 50x50 matrix named nghlist(i,j) containing 0 and 1 values. 1 means there is a relation between (i,j).
There is another 5x50 matrix named chlist.
I need to check the nghlist matrix and if there is any connection between i and j (nghlist(i,j)==1) then I need to go to the chlist matrix and compare the values on column i and column j. For example compare columns (1,3,8,21,52) and get how many similar values they share together. i.e. I find all those columns have 3 similar values.
I tried using following code. But the problem is I need to compare the unknown number of columns (depend on the node connection (nghlist) for example 4 or 5 columns) together.
for i=1:1:n
for j=1:1:n
if (i~=j & nghlist(i,j)==1)
sum(ismember(chlist(:,i),chlist(:,j)));
end
end
end
Any help is highly appreciated.
++++ simplified example ++++++
take a look at the example http://i.imgur.com/mQjDqzz.jpg
nghlist matrix:
1 1 1 0 0
1 1 1 0 0
1 1 1 1 1
0 0 1 1 1
0 0 1 1 1
chlist matrix:
3 1 4 5 4
4 3 5 6 5
5 4 6 7 6
In this example since node 1 is connected to nodes 2 and 3, I need to compare column 1,2 and 3 from chlist. The output would be 1 (because they only share value '4').
And this value for node 5 would be 2 (because columns 3,4 and 5 only share value '5' and '6'). I hope now it is clear.
If the result of your simplified example is [1,2,0,3,2] then the following code worked for me.
(Matrix a stands for nghlist and matrix b for chlist, result is stored in s )
for i = 1:size(a,1)
s(i)=0;
row = a(i,:);
idx = find(row==1);
idx = idx(idx~=i);
tempb = b(:,idx);
for j=1:size(tempb,1)
if sum(sum(tempb==tempb(j,1)))==size(tempb,2)
s(i)=s(i)+1;
end
end
end
For every node you find all the ones in its row, then discard the one referring to the node itself. Pick the appropriate columns of chlist (line 6) and create a new matrix. For every element of the 1st column of this matrix check if it exists in all other columns.If it does, update the s value
Let's say, the indices of the columns that are to be compared is called idxList:
idxList = [1,3,8,21,50];
You may compare all with the first one and use "AND" to find the minimum number of shared values:
shared = ones(size(chlist(:,i)))
for ii = 2:length(idxList)
shared = (shared == (chlist(:,idxList(1)) == chlist(:,idxList(ii))))
end
Finally, sum as before
sum(shared)
I haven't checked the exact code, but the concept should become clear.
I manage to solve it this way. I compare the first and second column of tempb and put the result in tem. then compare tem with third column of tempb and so on. Anyway thank you finmor and also pyStarter, your codes has inspired me. However I knew its not the best way, but at least it works.
for i=1:size(nghlist,1)
s(i)=0;
j=2;
row=nghlist(i,:);
idx=find(row==1);
tempb=chlist(:,idx);
if (size(tempb,2)>1)
tem=intersect(tempb(:,1),tempb(:,2));
if (size(tempb,2)<=2)
s(i)=size(tem,1);
end
while (size(tempb,2)>j & size(tem)~=0)
j=j+1;
tem= intersect(tem(:,1),tempb(:,j));
s(i)=size(tem,1);
end
end
end