size of inner elements of cells - matlab

I'm reading some data with their attribute (say A in which first row is ids and second row is their attribute value) . I'd like to place such data in a cell where the first column are the unique ids and second row their attribute. whenever there's duplicate values for the attribute, I'll put on the vacancy available on front of its row. for example I'd like to construct C
A =
1 2 3 2
2 4 5 9
C{1}=
1 2 0
2 4 9
3 5 0
when I'm going to test the size of inner homes in cell, e.g.
size(C{1},2)
ans = 3
size(C{1},1)
ans = 3
size(C{1}(1,:),2)
ans = 3
All return 3 since it occupies empty homes with 0. So how should I understand where to put my new data (e.g. (1,5))? Should I traverse or find the place of 0 and insert there?
Thanks for any help.

Why not use a cell-Array for these kind of problem? How did you generate your C matrix?
Even though you have used cell-Arrays for C matrix, each element of C is a matrix in your case, so that the dimensions should be constant.
I have used a cell array inside a matrix. (i.e) each elements takes its own size based on the duplicate sizes. for eg, you could see that C{2,2} has two values while C{1,2} and C{3,2} has only one values. you could easily check the size of them without checking for zeros. Note that, even if any values were zero, this code will still work.
The first column of the matrix represents identifiers while the second column represents the values which takes its own size based on the number of duplicates.
Here is my Implementation using accumarray and unique to generate C as a cell-array.
Code:
C = [num2cell(unique(A(1,:).')), accumarray(A(1,:).',A(2,:).',[],#(x) {x.'})]
Your Sample Input:
A = [1 2 3 2;
2 4 5 9];
Output:
>> C
C =
[1] [ 2]
[2] [1x2 double]
[3] [ 5]
>> size(C{2,2},2)
ans =
2
>> size(C{1,2},2)
ans =
1
From the DOC
Note: If the subscripts in subs are not sorted with respect to their linear indices, then accumarray might not always preserve the order of the data in val when it passes them to fun. In the unusual case that fun requires that its input values be in the same order as they appear in val, sort the indices in subs with respect to the linear indices of the output.
Another Example:
Input:
A = [1 2 1 2 3 1;
2 4 5 9 4 8];
Output:
C =
[1] [1x3 double]
[2] [1x2 double]
[3] [ 4]
Hope this helps!!

Related

(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.

Merging elements of different cells

Suppose, we have a cell array consisting of ids and one attribute, e.g.
A{1,1}=[1 2;2 4]
A{1,2}=[2 3 5;8 5 6]
Now, I'd like to have a final output consisting of unique ids of two cells (first row values) and corresponding columns have attribute value of each cell separately.
i.e.
C =
[1] [ 2]
[2] [1x2 double] % 4 in first cell and 8 in second cell
[3] [ 5]
[5] [ 6]
it seems that it's not possible to use something like C=[unique(A{1,:}(1,:)')]. Any help is greatly appreciated.
Assuming that each cell has two rows and a variable amount of columns where the first row is the ID and the second row is an attribute, I'd consolidate all of the cells into a single 2D matrix and use accumarray. accumarray is very suitable here because you want to group values that belong to the same ID together and apply a function to it. In our case, our function will simply place the values in a cell array and we'll make sure that the values are sorted because the values that are grouped by accumarray per ID come into the function in random order.
Use cell2mat to convert the cells into a 2D matrix, transpose it so that it's compatible for accumarray, and use it. One thing I'll need to note is that should any IDs be missing, accumarray will make this slot empty. What I meant by missing is that in your example, the ID 4 is missing as there is a gap between 3 and 5 and also the ID 6 between 5 and 7 (I added the example in your comment to me). Because the largest ID in your data is 7, accumarray works by assigning outputs from ID 1 up to ID 7 in increments of 1. The last thing we would need to tackle is to eliminate any empty cells from the output of accumarray to complete the grouping.
BTW, I'm going to assume that your cell array consists of a single row of cells like your example.... so:
%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A).';
%// Group IDs together and ensure they're sorted
out = accumarray(B(:,1), B(:,2), [], #(x) {sort(x)});
%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out)).');
out = [IDs out];
%// Any cells from the grouping that are empty, eliminate
ind = cellfun(#isempty, out(:,2));
out(ind,:) = [];
We get:
out =
[1] [ 2]
[2] [2x1 double]
[3] [ 5]
[5] [ 6]
[7] [ 8]
>> celldisp(out(2,:))
ans{1} =
2
ans{2} =
4
8
If you'd like this done on a 2D cell array, where each row of this cell array represents a separate instance of the same problem, one suggestion I have is to perhaps loop over each row. Something like this, given your example in the comments:
%// Setup
A{1,1}=[1 2;2 4];
A{1,2}=[2 3 5;8 5 6];
A{1,3}=[7;8];
A{2,1}=[1 2;2 4];
A{2,2}=[1;7];
%// Make a cell array that will contain the output per row
out = cell(size(A,1),1);
for idx = 1 : size(A,1)
%// Convert row of cell arrays to a single 2D matrix, then transpose for accumarray
B = cell2mat(A(idx,:)).';
%// Group IDs together and ensure they're sorted
out{idx} = accumarray(B(:,1), B(:,2), [], #(x) {sort(x)});
%// Add a column of IDs and concatenate with the previous output
IDs = num2cell((1:numel(out{idx})).');
out{idx} = [IDs out{idx}];
%// Any cells from the grouping that are empty, eliminate
ind = cellfun(#isempty, out{idx}(:,2));
out{idx}(ind,:) = [];
end
We get:
>> out{1}
ans =
[1] [ 2]
[2] [2x1 double]
[3] [ 5]
[5] [ 6]
[7] [ 8]
>> out{2}
ans =
[1] [2x1 double]
[2] [ 4]
>> celldisp(out{1}(2,:))
ans{1} =
2
ans{2} =
4
8
>> celldisp(out{2}(1,:))
ans{1} =
1
ans{2} =
2
7

Searching a cell array of vectors and returning indices

I have a 3000x1 cell array of vectors of different lengths and am looking for a way to search them all for a number and return the cell indices for the first and last occurrence of that number.
So my data looks like this:
[1]
[1 2]
[1 2]
[3]
[6 7 8 9]
etc
And I want to my results to look like this when I search for the number 1:
ans = 1 3
All the indices (e.g. [1 2 3] for 1) would also work, though the above would be better. So far I'm unable to solve either problem.
I've tried
cellfun(#(x) x==1, positions, 'UniformOutput', 0)
This returns a logical array, effectively putting me back at square 1. I've tried using find(cellfun...) but this gives the error undefined function 'find' for input arguments of type 'cell'. Most of the help I can find is for searching for strings within a cell array. Do I need to convert all my vectors to strings for this to work?
C = {[1]
[1 2]
[1 2]
[3]
[6 7 8 9]}; %// example data
N = 1; %// sought number
ind = cellfun(#(v) any(v==N), C); %// gives 1 for cells which contain N
first = find(ind,1);
last = find(ind,1,'last');
result = [ first last ];

MATLAB search row index of matrix with values of another matrix

In MATLAB I have a very large matrix (matrix A). Now I would like to find the row-index of the row which contain certain values in the second column. These values - which I'm looking for in Matrix A - are stored in anonther Matrix (Matrix B) with consists out of a row (800 numbers).
Besides I would like to redo this calculation for the same matrix A, but for ten different matrices, with different sizes (which contain the values I'm looking for in different columns of matrix A).
Because of the sizes of the matrix I think i need a loop to extract the row in matrix A which contain te value of Matrix B. How can I do this?
regards,
V
Thanks for the quick response! Indeed the problem is maybe a bit complex to answer without an example, and indeed duplicate entries cause some problems. Therefore hereby an example
For example I have a -simplified- matrix A:
1 2 3 4
9 9 9 9
4 3 2 1
And a -simplified- matrix (row) B: [9 3]
And a -simplified- matrix (row) C: [9 2]
Then I would like to get matrix D and matrix E.These matrices should contain in the first column the numbers from the original matrix D(or E) and in the second column the corresponding row-location of this value in matrix A.
So, matrix D =
9 2
3 3
matrix E =
9 2
2 3
As represented in this example matrix B and matrix C can contain data which is present in several column of matrix A (like the nine). However, martix B should "search" in column 2 of matrix A. Likewise, should matrix C "search" in column 3 of Matrix A, resulting in matrix D and E as given in the example.
As mentionned by Shai in his comment, your question is quite vague and a lot of special case could arise (duplicate entries, relative size of A and B, etc.). But in all generality I tried a small piece of code that seems to do what you want. There are certainly quicker ways of doing it, and certainly more information on your problem could help optimize this.
colA=2;
% Example
nmax=10;
nA=5;
A=randi(nmax,[nA nA]);
nB=3;
B=randi(nmax,[1 nB]);
% Find rows
rows=cell(size(B));
for i=1:numel(B)
rows(i)={find(A(:,colA)==B(i))};
end
The input / output was:
A =
3 7 8 5 4
9 7 3 7 5
8 2 9 9 8
9 5 9 7 9
3 3 4 6 8
B =
1 7 5
rows =
[0x1 double] [1;2] [4]
Assuming you have two vectors, largeDataIndex (the second column of your matrix) and interestingIndex (your b) and you want the following:
For each value of interestingIndex , find the position in largeDataIndex
Then an easy method would be this:
result = zeros(size(interestingIndex))
for i = 1:length(result)
result(i) = find(interestingIndex(i) == largeDataIndex)
end
Note that this assumes there is always just one entry that matches, otherwise you should define result as a cell array rather than a vector.

splitting a Matrix into column vectors and storing it in an array

My question has two parts:
Split a given matrix into its columns
These columns should be stored into an array
eg,
A = [1 3 5
3 5 7
4 5 7
6 8 9]
Now, I know the solution to the first part:
the columns are obtained via
tempCol = A(:,iter), where iter = 1:end
Regarding the second part of the problem, I would like to have (something like this, maybe a different indexing into arraySplit array), but one full column of A should be stored at a single index in splitArray:
arraySplit(1) = A(:,1)
arraySplit(2) = A(:,2)
and so on...
for the example matrix A,
arraySplit(1) should give me [ 1 3 4 6 ]'
arraySplit(2) should give me [ 3 5 5 8 ]'
I am getting the following error, when i try to assign the column vector to my array.
In an assignment A(I) = B, the number of elements in B and I must be the same.
I am doing the allocation and access of arraySplit wrongly, please help me out ...
Really it sounds like A is alread what you want--I can't imagine a scenario where you gain anything by splitting them up. But if you do, then your best bet is likely a cell array, ie.
C = cell(1,3);
for i=1:3
C{i} = A(:,i);
end
Edit: See #EitanT's comment below for a more elegant way to do this. Also accessing the vector uses the same syntax as setting it, e.g. v = C{2}; will put the second column of A into v.
In a Matlab array, each element must have the same type. In most cases, that is a float type. An your example A(:, 1) is a 4 by 1 array. If you assign it to, say, B(:, 2) then B(:, 1) must also be a 4 by 1 array.
One common error that may be biting you is that a 4 by 1 array and a 1 by 4 array are not the same thing. One is a column vector and one is a row vector. Try transposing A(:, 1) to get a 1 by 4 row array.
You could try something like the following:
A = [1 3 5;
3 5 7;
4 5 7;
6 8 9]
arraySplit = zeros(4,1,3);
for i =1:3
arraySplit(:,:,i) = A(:,i);
end
and then call arraySplit(:,:,1) to get the first vector, but that seems to be an unnecessary step, since you can readily do that by accessing the exact same values as A(:,1).