Related
I have an array A as follows:
A = [7 7 10 10 10 15 1 1 15 15 7 16 17 1 18]. ';
How can I obtain all numbers which occur more than one times in my array? In this example the answer should be 1 7 10 15.
Here's another approach, just for variety:
[~, ind] = unique(A);
result = A;
result(ind) = [];
result = unique(result);
Solved it by using the following code
[ii,jj,kk]=unique(A);
repeated=ii(histc(kk,1:numel(ii))>1);
I have a 3D-cell array designated as A{s,i,h}, serving as a store for large amounts of numerical data during a nested-loop portion of my script. Some of the cell entries will be blank [ ], whilst the rest consist of numbers - either singular or in arrays (1 x 10 double etc.):
I want to convert this cell array to a set of 2D matrices.
Specifically, one separate matrix for each value of h (h is always equal 1:3) and one column in each matrix for every value of s. Each column will contain all the numerical data combined - it does not need to be separated by i.
How can I go about this? I ordinarily deal with 3D-cell arrays in this form to produce separate matrices (one for each value of h) using something like this:
lens = sum(cellfun('length',reshape(A,[],size(A,3))),1);
max_length = max(lens);
mat = zeros(max_length,numel(lens));
mask = bsxfun(#le,[1:max_length]',lens);
mat(mask) = [A{:}];
mat(mat==0) = NaN;
mat = sort(mat*100);
Matrix1 = mat(~isnan(mat(:,1)),1);
Matrix2 = mat(~isnan(mat(:,2)),2);
Matrix3 = mat(~isnan(mat(:,3)),3);
However in this instance, each matrix had only a single column. I'm have trouble adding multiple columns to each output matrix.
1. Result in the form of a cell array of matrices (as requested)
Here's one possible approach. I had to use one for loop. However, the loop can be easily avoided if you accept a 3D-array result instead of a cell array of 2D-arrays. See second part of the answer.
If you follow the comments in the code and inspect the result of each step, it's straightforward to see how it works.
%// Example data
A(:,:,1) = { 1:2, 3:5, 6:9; 10 11:12 13:15 };
A(:,:,2) = { 16:18, 19:22, 23; 24:28, [], 29:30 };
%// Let's go
[S, I, H] = size(A);
B = permute(A, [2 1 3]); %// permute rows and columns
B = squeeze(mat2cell(B, I, ones(1, S), ones(1, H))); %// group each col of B into a cell...
B = cellfun(#(x) [x{:}], B, 'uniformoutput', false); %// ...containing a single vector
t = cellfun(#numel, B); %// lengths of all columns of result
result = cell(1,H); %// preallocate
for h = 1:H
mask = bsxfun(#le, (1:max(t(:,h))), t(:,h)).'; %'// values of result{h} to be used
result{h} = NaN(size(mask)); %// unused values will be NaN
result{h}(mask) = [B{:,h}]; %// fill values for matrix result{h}
end
Result in this example:
A{1,1,1} =
1 2
A{2,1,1} =
10
A{1,2,1} =
3 4 5
A{2,2,1} =
11 12
A{1,3,1} =
6 7 8 9
A{2,3,1} =
13 14 15
A{1,1,2} =
16 17 18
A{2,1,2} =
24 25 26 27 28
A{1,2,2} =
19 20 21 22
A{2,2,2} =
[]
A{1,3,2} =
23
A{2,3,2} =
29 30
result{1} =
1 10
2 11
3 12
4 13
5 14
6 15
7 NaN
8 NaN
9 NaN
result{2} =
16 24
17 25
18 26
19 27
20 28
21 29
22 30
23 NaN
2. Result in the form of 3D array
As indicated above, using a 3D array to store the result permits avoiding loops. In the code below, the last three lines replace the loop used in the first part of the answer. The rest of the code is the same.
%// Example data
A(:,:,1) = { 1:2, 3:5, 6:9; 10 11:12 13:15 };
A(:,:,2) = { 16:18, 19:22, 23; 24:28, [], 29:30 };
%// Let's go
[S, I, H] = size(A);
B = permute(A, [2 1 3]); %// permute rows and columns
B = squeeze(mat2cell(B, I, ones(1, S), ones(1, H))); %// group each col of B into a cell...
B = cellfun(#(x) [x{:}], B, 'uniformoutput', false); %// ...containing a single vector
t = cellfun(#numel, B); %// lengths of all columns of result
mask = bsxfun(#le, (1:max(t(:))).', permute(t, [3 1 2])); %'// values of result to be used
result = NaN(size(mask)); %// unused values will be NaN
result(mask) = [B{:}]; %// fill values
This gives (compare with result of the first part):
>> result
result(:,:,1) =
1 10
2 11
3 12
4 13
5 14
6 15
7 NaN
8 NaN
9 NaN
result(:,:,2) =
16 24
17 25
18 26
19 27
20 28
21 29
22 30
23 NaN
NaN NaN
Brute force approach:
[num_s, num_i, num_h] = size(A);
cellofmat = cell(num_h,1);
for matrix = 1:num_h
sizemat = max(cellfun(#numel, A(:,1,matrix)));
cellofmat{matrix} = nan(sizemat, num_s);
for column = 1:num_s
lengthcol = length(A{column, 1, matrix});
cellofmat{matrix}(1:lengthcol, column) = A{column, 1,matrix};
end
end
Matrix1 = cellofmat{1};
Matrix2 = cellofmat{2};
Matrix3 = cellofmat{3};
I don't know what your actual structure looks like but this works for A that is setup using the following steps.
A = cell(20,1,3);
for x = 1:3
for y = 1:20
len = ceil(rand(1,1) * 10);
A{y,1,x} = rand(len, 1);
end
end
I have a 12-D array and am using each dimension as an index value in an optimization problem.
A(:,:,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10)
each index value i is a value from 1 to 5.
I want to sort A from greatest to least and keep track of the indices so I know which indices correspond to to what value of A.
So my ideal output would be a 2 column cell/array with one column being the value and the other other column being the index values.
For a simple 3D example: say I have a 3D array: A(:,:,i1).
Where:
A(:,:,1) = 2
A(:,:,2) = 6
A(:,:,3) = 13
A(:,:,4) = 11
A(:,:,5) = 5
I would like my output to be:
13 3
11 4
6 2
5 5
2 1
EDIT:
assume I have 1x1x3x3 sized input such that
A(1,1,1,1) = 3
A(1,1,2,1) = 1
A(1,1,3,1) = 23
A(1,1,1,2) = 12
A(1,1,2,2) = 9
A(1,1,3,2) = 8
A(1,1,1,3) = 33
A(1,1,2,3) = 14
A(1,1,3,3) = 6
the expected output would be:
33 [1,1,1,3]
23 [1,1,3,1]
14 [1,1,2,3]
12 [1,1,1,2]
9 [1,1,2,2]
8 [1,1,3,2]
6 [1,1,3,3]
3 [1,1,1,1]
1 [1,1,2,1]
This should be a generic code for any multi-dimensional input array -
%// Sort A and get the indices
[sorted_vals,sorted_idx] = sort(A(:),'descend');
%// Set storage for indices as a cell array and then store sorted indices into it
c = cell([1 numel(size(A))]);
[c{:}] = ind2sub(size(A),sorted_idx);
%// Convert c to the requested format and concatenate with cell arary version of
%// sorted values for the desired output
out = [num2cell(sorted_vals) mat2cell([c{:}],ones(1,numel(A)),numel(size(A)))];
The generic code owes its gratitude to this fine solution.
I guess this is what you want:
b=A(:);
[sorted_b,ind]=sort(b,'descend');
[dim1,dim2,dim3,dim4]=ind2sub(size(A),ind);
%arranging in the form you want
yourCell=cell(size(b,1),2);
yourCell(:,1)=mat2cell(sorted_b,ones(size(b,1),1),1);
%arranging indices -> maybe vectorized way is there for putting values in "yourCell"
for i=1:size(b,1)
yourCell{i,2}=[dim1(i) dim2(i) dim3(i) dim4(i)];
end
For the array A, given by you, my output looks like:
33 [1,1,1,3]
23 [1,1,3,1]
14 [1,1,2,3]
12 [1,1,1,2]
9 [1,1,2,2]
8 [1,1,3,2]
6 [1,1,3,3]
3 [1,1,1,1]
1 [1,1,2,1]
which matches with your output.
I am considering an easy algorithm to rank my 2D array and mark their rank in the same size of the 2D array.
For example, I have a matrix in below:
[0 2 15 34;
0 15 21 24;
0 3 5 8;
1 14 23 29]
The output should be as follow:
[1 5 10 16;
1 10 12 14;
1 6 7 8;
4 9 13 15]
I am kind of new to matlab, I not sure if the matlab have the functionality to directly do it. Or it would be even better if you could provide some ideas for implementing the algorithm. Thank you very much!
If I understand correctly, you want to replace each element by its rank. I offer three ways to do it; the third seems to be what you want.
Let your example data be defined as
data = [0 2 15 34;
0 15 21 24;
0 3 5 8;
1 14 23 29];
This assigns equal ranks to equal data values (as in your example), but doesn't skip ranks in that case (your example seems to do so):
[~, ~, vv] = unique(data(:));
result = reshape(vv, size(data));
With your example data, this gives
result =
1 3 8 13
1 8 9 11
1 4 5 6
2 7 10 12
This assigns different ranks to equal data values (so skipping ranks is out of the question):
[~, vv] = sort(data(:));
[~, vv] = sort(vv);
result = reshape(vv, size(data));
With your example data,
result =
1 5 11 16
2 10 12 14
3 6 7 8
4 9 13 15
This assigns equal ranks to equal data values, and in that case it skips ranks:
[~, vv] = sort(data(:));
[~, vv] = sort(vv);
[~, jj, kk] = unique(data(:), 'first');
result = reshape(vv(jj(kk)), size(data));
With your example data,
result =
1 5 10 16
1 10 12 14
1 6 7 8
4 9 13 15
Another approach, single-line: for each entry, find how many other entries are smaller, and add 1:
result = reshape(sum(bsxfun(#lt,data(:),data(:).'))+1, size(data));
I need help with my code. The code is used to find the minumin of a square-distance problem. I am providing my code through an example, I believe this will be the easiest way to explain what I need.
clear all
clc
x=10.8; % is a fixed value
y=34; % is a fixed value
z=12; % is a fixed value
A = [11 14 1; 5 8 18; 10 8 19; 13 20 16]; % a (4x3) matrix
B = [2 3 10; 6 15 16; 7 3 15; 14 14 19]; % a (4x3) matrix
I create a new matrix C which is composed in this following way:
C1 = bsxfun(#minus, A(:,1)',B(:,1));
C1=C1(:); % this is the first column of the new matrix C
C2 = bsxfun(#minus, A(:,2)',B(:,2));
C2=C2(:); % this is the second column of the new matrix C
C3 = bsxfun(#minus, A(:,3)',B(:,3));
C3=C3(:); % this is the third column of the new matrix C
C = [C1 C2 C3]; % the new matrix C of size (16x3)
C has to be formed in this way! And this is what I meant when I wrote in my title a composed-matrix
Then:
[d,p] = min((C(:,1)-x).^2 + (C(:,2)-y).^2 + (C(:,3)-z).^2);
d = sqrt(d);
outputs:
d = 18.0289;
p = 13;
Gives me the distance (d) and position (p) which satisfies this min problem.
MY PROBLEM:
I need to find which combinations of A and B has given my this p value, in other words I need the index from ´A,B´ which gives me this optimal C1,C2,C3:
C1 = bsxfun(#minus, A(?,1)',B(?,1));
C2 = bsxfun(#minus, A(?,2)',B(?,2));
C3 = bsxfun(#minus, A(?,3)',B(?,3));
The ? is the index position I need, in this case the index position of the matrix A and the index position of B.
Calculated by hand I have the following illustration:
I know that:
C = [9 11 -9
5 -1 -15
4 11 -14
-3 0 -18
3 5 8
-1 -7 2
-2 5 3
-9 -6 -1
8 5 9
4 -7 3
3 5 4
-4 -6 0
11 17 6
7 5 0
6 17 1
-1 6 -3]
And I know that my optimal index is given in the position 13th. This index positions goes back to:
[13-2 20-3 16-10]
Which is A(4,:) - B(1,:)
I need a code which can help me to find this indexes from A and B
Thanks in advance!
PS. I am using the code in parameter estimation problems of ODEs.
First case: vector-matrix case
subvals = bsxfun(#minus,A,[x y z])
[distance,index] = min(sqrt(sum(subvals.^2,2)))
Second case: Two matrices case
subvals = bsxfun(#minus,A,permute(B,[3 2 1]));
[distances,indices] = min(sqrt(sum(subvals.^2,2)),[],3)
Testing for second case:
%%// Get some random data into A and B
A = randi(20,8,3)
B = randi(20,4,3)
%%// Just to test out out code for correctness,
%%// let us make any one one row of B, say 3rd row equal to
%%// any one row of A, say the 6th row -
B(3,:) = A(6,:)
%%// Use the earlier code
subvals = bsxfun(#minus,A,permute(B,[3 2 1]));
[distances,indices] = min(sqrt(sum(subvals.^2,2)),[],3)
%%// Get the minimum row index for A and B
[~,min_rowA] = min(distances)
min_rowB = indices(min_rowA)
Verification
min_rowA =
6
min_rowB =
3
Edit 1 [Response to simple example posted in question]:
The title says you are interested in finding the difference of two matrices and then find the shortest distance between it to a vector [x y z]. So I am hoping this is what you need -
x=10.8;
y=34;
z=12;
A = [11 14 1; 5 8 18; 10 8 19; 13 20 16];
B = [2 3 10; 6 15 16; 7 3 15; 14 14 19];
C = A -B; %%// Distance of two vectors as posted in title
subvals = bsxfun(#minus,C,[x y z])
[distance,index] = min(sqrt(sum(subvals.^2,2)))
Output
distance =
31.0780
index =
3
Edit 2: After you have done this -
[d,p] = min((C(:,1)-x).^2 + (C(:,2)-y).^2 + (C(:,3)-z).^2);
If you are looking to find the corresponding indices of A and B , you may do this -
[minindex_alongB,minindex_alongA] = ind2sub(size(A),p)