Lets say I have the matrix
dataSet = [400,300,200,100,200,300,400;
1, 2, 3, 4, 5, 6, 7]
This will give me a 2x7 array with the larger numbers on row 1 and the smaller on row 2.
Lets say I am given the number 200 and asked to find what all the numbers below 200 are. The answer is 3 and 5, because they both correspond to 200, but how can I code this into my script?
>> dataSet(2,dataSet(1,:) == 200)
ans =
3 5
Is this what you want?
[t, ~, u] = unique(dataSet(1,:));
result = accumarray(u, dataSet(2,:).', [], #(x) {x.'});
result = [num2cell(t).' result];
In your example, this gives:
>> result
result =
[100] [ 4]
[200] [1x2 double]
[300] [1x2 double]
[400] [1x2 double]
with
result{2,2} =
3 5
result{3,2} =
2 6
etc
Related
I have this a cell that holds 4 vectors, and I'd like to expand it so it could hold another vector. Thanks in advance.
a = cell(4, 1);
a{1} = [1, 2, 3];
a{2} = [1, 4, 9];
a{3} = [1, 4, 9];
a{4} = [1; 5];
And I would like to add a new vector [2, 7] so that I will get this
a{1} = [2, 7];
a{2} = [1, 2, 3];
a{3} = [1, 4, 9];
a{4} = [1, 4, 9];
a{5} = [1; 5];
How could I do that ?
a = cell(4, 1);
a{1} = [1, 2, 3];
a{2} = [1, 4, 9];
a{3} = [1, 4, 9];
a{4} = [1; 5];
a = [[2, 7];a]
Yielding:
a =
[1x2 double]
[1x3 double]
[1x3 double]
[1x3 double]
[2x1 double]
The name for what you are trying to do is concatenation. In MATLAB, square brackets are an implicit method of concatenation. While you typically think about these being used to concatenate numbers to form a vector or matrix:
x = [1, 2, 3, 4] % 1 x 4
You can also use them to concatenate other data types (including cell arrays)
y = [{1,2}, 5, {4, 5}]; % 1 x 3 Cell Array
It is also important to keep track of the dimension of concatenation. With square brackets you can either concatenate across the columns (2nd dimension) using a comma or across the rows (1st dimension using a semi-colon).
size([1,2,3])
1 x 3
size([1;2;3])
3 x 1
While square brackets are a quick and easy solution, I prefer to be a little more explicit. For this, MATLAB has the following functions: cat, horzcat, and vertcat. I personally prefer cat since you can specify concatenation in any arbitrary dimension.
x = cat(2, 100, 200, 300); % 1 x 3
100 200 300
x = cat(1, 100, 200, 300); % 3 x 1
100
200
300
x = cat(3, 100, 200, 300) % 1 x 1 x 3
x(:,:,1) =
100
x(:,:,2) =
200
x(:,:,3) =
300
So back to your original question, you want to concatenate in the 1st dimension (rows) so you could simply do the following:
a = cell(4, 1);
a{1} = [1, 2, 3];
a{2} = [1, 4, 9];
a{3} = [1, 4, 9];
a{4} = [1; 5];
a = cat(1, [2, 7], a);
Also remember that this form of using concat or the square brackets can be applied to most datatypes within MATLAB including structs among others.
Given a matrix of n dimensions, how can I convert it to a matrix of indices as seen below:
As mentioned by MATLAB documents, you can use ind2sub function:
IND = [3 4 5 6]
s = [3,3];
[I,J] = ind2sub(s,IND)
I =
3 1 2 3
J =
1 2 2 2
The function ind2sub should work. Another option is to calculate it by hand. This is easy. Note the stucture of the matrix. It is denoted by linear indexing distributed columnwise. This mean that the indices can be calculated as:
idxRow = mod(idx-1,nRows)+1;
idxCol = ceil(idx./nColumns);
This is more or less what is done in ind2sub except that function cleverly solves the problem for an N-dimensional matrix. And also have some error handling.
n = 3;
[X,Y] = meshgrid(1:n);
C = cell(n,n);
for ii = 1:n
for jj = 1:n
C{ii,jj} = [X(ii,jj) Y(ii,jj)];
end
end
Note that the X and Y matrices are probably what you are looking for, since they are matrices. To also include the cell of indices I had to use a nested loop, but there's probably a vectorised way to do that as well.
X =
1 2 3
1 2 3
1 2 3
Y =
1 1 1
2 2 2
3 3 3
C =
[1x2 double] [1x2 double] [1x2 double]
[1x2 double] [1x2 double] [1x2 double]
[1x2 double] [1x2 double] [1x2 double]
where each [1x2 double] is the requested combination of indices.
How to assign a value from a cell array to a numerical array efficiently? A and B are always square matrices of any size. For simplicity I just allocated small matrices. If for example A{1}=[2 3 8]; then I want allocate value 8 in second row and third column of the B matrix.
E.g.,
Input
A=[1x3 double] [1x3 double] [1x3 double] [1x3 double]
[1x3 double] [1x3 double] [1x3 double] [1x3 double]
[1x3 double] [1x3 double] [1x3 double] [1x3 double]
[1x3 double] [1x3 double] [1x3 double] [1x3 double]
B=zeros(4,4);
A{1}=[2 3 8];
A{2}=[3 4 7];
and so on...
Output
B(2,3)=8;
B(3,4)=7;
and so on...
Use spconvert:
B = full(spconvert(cat(1, A{:})));
You can do this without loops:
B=zeros(4,4);
A{1}=[2 3 8];
A{2}=[3 4 7];
C = cell2mat(A);
C = reshape(C,3,size(C,2)/3)';
indices = sub2ind(size(B), C(:,1), C(:,2));
B(indices) = C(:,3);
For your example this results in:
B =
0 0 0 0
0 0 8 0
0 0 0 7
0 0 0 0
Using sub2ind and indexing
%// creating a sample cell array. Replace this with your actual cell array
A = {[1 2 8] [1 1 4]; [2 1 5] [2 2 1]};
%// Reshaping the cell array to kx3 matrix
Amat = cat(1,A{:}); %// from luis' answer
%// taking first column as row sub, 2nd col as col sub
%// The subs are converted into linear indices to the size of A or B
ind = sub2ind(size(A),Amat(:,1),Amat(:,2));
%// You have done this (helps in fixing the dimensions of B)
B = zeros(size(A));
%// Taking last col of 'Amat' as values and assigning to corresponding indices
B(ind) = Amat(:,3);
Results:
>> B
B =
4 8
5 1
I would suggest looping once over the A cells to find the maximum index values, let's say max_i,max_j.
Then initialize B like:
B=zeros(max_i,max_j)
And loop again over the A cells and assign th values to the corresponding B elements.
Edit: Added example code:
max_i=0
max_j=0
for k=1:size(A,1)
for l=1:size(A,2)
max_i=max([A{k,l}(1),max_i])
max_j=max([A{k,l}(2),max_j])
end
B=zeros(max_i,max_j)
for k=1:size(A,1)
for l=1:size(A,2)
B(A{k,l}(1),A{k,l}(2))=A{k,l}(3)
end
I have sentences cross words [4 cross 5] matrix as follows:
out=
0 1 1 0 1
1 1 1 0 0
0 0 1 1 0
1 1 0 1 1
I want to create a 1D cell array based upon above matrix which should tell in which two sentences same words appear with value = 1 i.e. let's take line 1 and line 2 in which at 2 points column 2 and column 3 the logical matrix has both 1's in row 1 and row 2 this information should be stored in 1D cell array.
suppose above example it's output would be as:
output{1,1} = []
output{1,2} = [2 3]
output{1,3} = [3]
.....
output{n,n} = [....]
where {1,1} tells sentence 1 relation with sentence 1 on the basis of value=1 of words, {1,2} tells sentence 1 relation with sentence 2 on the basis of value=1 of words and so on...
Try this:
x = [ 0 1 1 0 1
1 1 1 0 0
0 0 1 1 0
1 1 0 1 1];
[ii, jj] = ndgrid(1:size(x,1));
y = arrayfun(#(m,n) find(x(m,:) & x(n,:)), ii, jj, 'uniformoutput', 0);
Result:
y{1,1} =
2 3 5
y{2,1} =
2 3
y{3,1} =
3
y{4,1} =
2 5
[...]
If you want the diagonal elements to be empty:
y = arrayfun(#(m,n) find(x(m,:) & x(n,:) & m~=n), ii, jj, 'uniformoutput', 0)
Result:
y{1,1} =
[]
y{2,1} =
2 3
y{3,1} =
3
y{4,1} =
2 5
[...]
If you want something written quick... and since we are dealing with cell arrays, the easiest thing would be to have a pair of for loops. Assuming that you have your matrix defined in out:
out_cell = cell(size(out,1),size(out,1));
for idx = 1 : size(out,1)
for idx2 = 1 : idx
vals = find(out(idx,:) & out(idx2,:));
out_cell{idx,idx2} = vals;
out_cell{idx2,idx} = vals;
end
end
For each pair of rows, idx and idx2, we look to see if any columns match in terms of having a 1, then place the indices into its respective cell location in the 2D cell array. Note that because will encounter pairs of rows that are duplicates (i.e. checking row 3 and row 5, compared to row 5 and row 3), there is no need for the second for loop to iterate all over the other rows. We only need to check up to the current row that is described by the outer loop and we simply write the same values with the row indices swapped... so this is a "symmetric" matrix.
If you would like the diagonal elements to be empty, simply change the inner for loop so that it goes for idx2 = 1 : idx-1, instead of for idx2 = 1 : idx.
With your example, we get:
>> out_cell
out_cell =
[1x3 double] [1x2 double] [ 3] [1x2 double]
[1x2 double] [1x3 double] [ 3] [1x2 double]
[ 3] [ 3] [1x2 double] [ 4]
[1x2 double] [1x2 double] [ 4] [1x4 double]
>> celldisp(out_cell)
out_cell{1,1} =
2 3 5
out_cell{2,1} =
2 3
out_cell{3,1} =
3
out_cell{4,1} =
2 5
out_cell{1,2} =
2 3
out_cell{2,2} =
1 2 3
out_cell{3,2} =
3
out_cell{4,2} =
1 2
out_cell{1,3} =
3
out_cell{2,3} =
3
out_cell{3,3} =
3 4
out_cell{4,3} =
4
out_cell{1,4} =
2 5
out_cell{2,4} =
1 2
out_cell{3,4} =
4
out_cell{4,4} =
1 2 4 5
Consider a cell array ,
H = [ {N1x1} {N2x1} {N3x1} ...{Nmx1} ]
How does get (efficiently) all pairwise intersections of these cells?
Not sure how efficient this will be.
N = numel(H);
[ii jj] = ndgrid(1:N);
result = arrayfun(#(n) intersect(H{ii(n)},H{jj(n)}), 1:N^2, 'uni', 0);
result = reshape(result,N,N);
Example:
H = {[1 2 3], [2 3], [4 5]};
gives
result =
[1x3 double] [1x2 double] [1x0 double]
[1x2 double] [1x2 double] [1x0 double]
[1x0 double] [1x0 double] [1x2 double]
>> result{1,1}
ans =
1 2 3
>> result{1,2}
ans =
2 3
>> result{1,3}
ans =
Empty matrix: 1-by-0
[..]
This also works if H is a multidimensional cell array.
You could also use two for loops. Then you could save half operations explotiing the symmetry of the result.