MatLab - histc with many edges vector - matlab

Consider this :
a = [1 ; 7 ; 13];
edges = [1, 3, 6, 9, 12, 15];
[~, bins] = histc(a, edges)
bins =
1
3
5
Now I would like to have the same output, but with a different "edges" vector for each a value, i.e. a matrix instead of a vector for edges. Exemple :
a = [1 ; 7 ; 13];
edges = [ 1, 3, 6 ; 1, 4, 15 ; 1, 20, 30];
edges =
1 3 6
1 4 15
1 20 30
indexes = theFunctionINeed(a, edges);
indexes =
1 % 1 inside [1, 3, 6]
2 % 7 indide [1, 4, 15]
1 %13 inside [1, 20, 30]
I could do this with histc inside a for loop, by I'm trying to avoid loops.

If you transform your arrays to cell arrays, you can try
a = {1 ; 7 ; 13};
edges = {[ 1, 3, 6 ];[ 1, 4, 15] ; [1, 20, 30]};
[~, indexes] = cellfun(#histc, a, edges,'uniformoutput', false)
This results in
indexes =
[1]
[2]
[1]
~edit~
To transform your matrices into cell arrays you can use num2cell:
a = num2cell(a);
edges = num2cell(edges, 2);

You could also do:
a = [1; 7; 13];
edges = [1 3 6; 1 4 15; 1 20 30];
bins = sum(bsxfun(#ge, a, edges), 2)
The result:
>> bins
bins =
1
2
1

Related

Minimum of two multidimensional matrices, with which matrix 'won' (contained the minimum)

I have two matrices (size 4x4) and I want to find the minimum between the two. For example:
A = [ 3, 2, 4, 5;
1, 2, 0, 6;
9, 8, 5, 4;
0, 1, 0, 3 ];
B = [ 1, 1, 6, 8;
0, 4, 6, 3;
5, 6, 7, 1;
0, 2, 3, 4 ];
Now, if I did a min(A,B) in Octave, it gives me
[ 1, 1, 4, 5;
0, 2, 0, 3;
5, 6, 5, 1;
0, 1, 0, 3 ]
Is there a way to get the matrix that 'won', by which I mean which matrix contained the minimum, in each element-wise comparison?
Like, for the first element of both matrices, matrix B won and so on.
I don't want to loop through the matrices.
You can compare A and B to find out in which matrix the minimum occurred.
With A > B, you will get a matrix containing False if the entry from A was chosen, and True if the entry from B was chosen. By adding 1 to it, you will get 1 if A was chosen and 2 if B was chosen.
>> 1 + (A > B)
ans =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1
Alternatively, you can concatenate A and B to form a 3-dimensional array with dimensions [4, 4, 2], where C(:, :, 1) = A and where C(:, :, 2) = B. Then you can call min on this matrix C along the third axis. When calling min on one matrix, you can get the index of the "winner" directly as a second return value:
>> C = cat(3, A, B);
>> [res, idx] = min(C, [], 3)
res =
1 1 4 5
0 2 0 3
5 6 5 1
0 1 0 3
idx =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1

replacing values of a matrix with an if operation using matlab

mn = 1
for kn = 1:199
for sn = 1:19773
if abs((x1c{kn+1,1}(sn)) - (x1c{kn,1}(sn))) >= 20
extract{mn} = x1c{kn+1,1}(sn);
mn = mn+1;
end
end
end
extend = cell2mat(extract) + 40;
How can I change the values of "x1c" with the values of "extend"?
You are performing the operation on a cell. Considering you're comparing numbers, this would be done far more efficiently when done with matrices.
I therefor suggest you convert the cell (or a subset of it) to a matrix and then use vectorized operations, like this:
>> a={[13, 2, 3], [14, 25, 8], [100, 9, 10], [101, 8, 32], [140, 20, 3]};
>>
>> x = transpose(reshape(cell2mat(a), 3, []));
>> z = abs(x(2:end, :) - x(1:end-1,:)) > 20;
>> z2 = [zeros(1,3); z]
z2 =
0 0 0
0 1 0
1 0 0
0 0 1
1 0 1
>> x(logical(z2)) = x(logical(z2)) - 200
x =
13 2 3
14 -175 8
-100 9 10
101 8 -168
-60 20 -197
There are two alternatives if you really must use cells (I don't recommend it for speed reasons).
store the indices (k, sn) of the cell items where your condition holds true. And then you'd have to loop over the elements again (very inefficient).
You'd store the previous and next cell "row" in temporary variables and compare using those. When the condition holds, edit in-place and take the temporary variable with you in the next iteration of the loop. The code below shows how this is done:
a={[13, 2, 3], [14, 25, 8], [100, 9, 10], [101, 8, 32], [140, 20, 3]};
curr_row = a{1};
for rowind=1:4
next_row = a{rowind+1};
for colind=1:3
if abs(next_row(1, colind) - curr_row(1, colind)) > 20
a{rowind+1}(1, colind) = a{rowind+1}(1, colind) + 40;
end
end
curr_row = next_row;
end

How to expand my cell without losing information

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.

matlab - cellfun sum all elements of each cell

Hi I have populated a cell array using:
D(i) = {dist};
D = reshape(D, w, h)
so that if i have:
pix1 = D{1,1};
pix2 = D{2,2};
I get
pix1 =
1 2 3
pix2 =
4 5 6
What I want to do is sum all the elements in each pix, and then take those results and form a matrix i.e.
sum(pix1) = 6
sum(pix2) = 15
matrix =
6 15
where in this case matrix is a 1X2 matrix (mine is a lot larger).
I am trying to do this using:
field = cellfun(#(dist) sum(dist(:)), D,'UniformOutput', false);
but this just gives me a matrix full of NaN's. Where am I going wrong?
A = {[1 2 4], [4 5 6]};
B = cellfun(#sum, A)
results in
B = [6 15]
B = [7 15]
In case you have NaNs in your cells and you wish to ignore them you may use nansum:
A = {[1, 2, NaN], [3, NaN, 4, 5]; [6, NaN], [10, -3, NaN, 4]};
B = cellfun( #nansum, A )
Results with
B =
3 12
6 11

MATLAB: Finding n-th smallest element in per row

I want to find the n-th smallest element for each row in a matrix.
Example:
n = 2
M = [1, 2, 3; 4, 5, 6; 7, 8 9]
Result = [2, 5, 8]
First sort the matrix by the second dimension (i.e. sort every row in ascending order):
n = 2
M = [1, 2, 3; 4, 5, 6; 7, 8 9]
M_SORTED = sort(M,2)
M_SORTED =
1 2 3
4 5 6
7 8 9
The n-th column of the matrix will contain the result:
RESULT = M_SORTED(:, n)
RESULT =
2
5
8