vectorizing histogram on matrix rows in matlab - matlab

Hello I need to calculate a histogram for every row in a big matrix.
For the first row for example I get this:
AA = hist(symbolic_data(1,:), 1:8);
With symbolic_data(1,:)=[7 6 7 8 7], I get AA=[0 0 0 0 0 1 3 1].
Of course this is easy using a simple for loop, but my symbolic_data matrix is really big.
Is there a way to vectorize this.
I've been fiddling with bsxfun, but I can't make it work.
Any help would be much appreciated.
Thanks for your time.

From Matlab help:
N = hist(Y) bins the elements of Y into 10 equally spaced containers
and returns the number of elements in each container. If Y is a
matrix, hist works down the columns.
so:
AA = hist(symbolic_data', 1:8);
will do what you want

The answer by #Mercury is the way to go. But if you want to do it with bsxfun:
If you only have integer values, use
bin_centers = 1:8;
AA = squeeze(sum(bsxfun(#eq, permute(symbolic_data,[2 3 1]), bin_centers(:).')));
If the values are not necessarily integer:
bin_centers = 1:8;
AA = squeeze(sum( bsxfun(#le, permute(symbolic_data,[2 3 1]), bin_centers(:).'+.5) &...
bsxfun(#gt, permute(symbolic_data,[2 3 1]), bin_centers(:).'-.5) ));

Related

Every possible difference among multiple vectors

I have 3 vectors, v1, v2, v3. What I want to get is the difference between every possible pair of them, that is, v1-v2, v1-v3, v2-v3. How can I do this without looping in matlab?
Thank you.
Just use nchoosek to generate the combinations first and then use them to index into your array of row-vectors:
Test case:
numVectors = 3;
dim = 5;
Vs = rand(numVectors, dim);
Actual computation:
combs = nchoosek(1:size(Vs,1), 2);
differences = Vs(combs(:,1),:) - Vs(combs(:,2),:);
The above creates 3 random row vectors of dimension 5. So in your case, you may want to replace the creation of the random matrix with Vs = [v1; v2; v3]; if your vectors are row vectors; or transpose the vectors using Vs = [v1, v2, v3].'; if your data are column vectors.
Using bsxfun:
clear
clc
%// Sample vectors.
v1 = [1 2];
v2 = [10 20];
v3 = [0 0];
Out = bsxfun(#minus,[v1 v2 v3], [v1 v2 v3].')
Out =
0 1 9 19 -1 -1
-1 0 8 18 -2 -2
-9 -8 0 10 -10 -10
-19 -18 -10 0 -20 -20
1 2 10 20 0 0
1 2 10 20 0 0
Reasoning: Each difference is computed starting from the 1st element of the 1st vector until the 2nd element of the last vector.
The 1st column contains all the differences for the 1st element of the 1st vector, i.e. (1 -1), (1-2), (1-10), (1 - 20), (1 - 0), (1 - 0).
Then 2nd column, same thing but this time with the 2: (2 - 1), (2 - 2), (2 - 10), and so on.
Sorry if my explanations are unclear haha I don't know the right terms in english. Please ask for more details.
Code
%// Concatenate all vectors to form a 2D array
V = cat(2,v1(:),v2(:),v3(:),v4(:),v5(:))
N = size(V,2) %// number of vectors
%// Find all IDs of all combinations as x,y
[y,x] = find(bsxfun(#gt,[1:N]',[1:N])) %//'
%// OR [y,x] = find(tril(true(size(V,2)),-1))
%// Use matrix indxeing to collect vector data for all combinations with those
%// x-y IDs from V. Then, perform subtractions across them for final output
diff_array = V(:,x) - V(:,y)
Few points about the code
bsxfun with find gets us the IDs for forming pairwise combinations.
We use those IDs to index into the 2D concatenated array and perform subtractions between them to get the final output.
Bonus Stuff
If you look closely into the part where it finds the IDs of all combinations, that is basically nchoosek(1:..,2).
So, basically one can have alternatives to nchoosek(1:N,2) as:
[Y,X] = find(bsxfun(#gt,[1:N]',[1:N]))
[y,x] = find(tril(true(N),-1))
with [X Y] forming those pairwise combinations and might be interesting to benchmark them!

matlab: sum of f(k_i,x) where k_i are scalars and x is a matrix

Any idea how to formulate this sum other than using a loop?
sum(i) f(k(i),x) where k_i are some entries of a vector and x is a matrix.
Currently what I'm doing is this, but I'd rather have a general solution:
for ii=1:length(k)
psi=psi+f(k(ii),x)
end
If it's any concern:
f(k,x)=g(k)*exp(k*x)
Assuming g can take a vector input and returns a vector result of the same size, and that x is just a scalar
f=#(k,x) g(k).*exp(k*x);
psi=sum(f(k,x))
or if g can't be or isn't able to take vector input, you can do
g=#(k) arrayfun(g,k);
and then define f as before.
Do you mean that you want to sum only specific rows?
If so, this will do it:
a= [1 2 3 4;
5 2 7 2;
0 0 2 3];
k= [1 3]; %rows selection for sum
result= sum(a(k,:))

Recurring Function with Matrix Input

I believe most functions in MATLAB should be able to receive matrix input and return the output in the form of matrix.
For example sqrt([1 4 9]) would return [1 2 3].
However, when I tried this recurring factorial function:
function k = fact(z)
if z ~= 0
k = z * fact(z-1);
else
k = 1;
end
end
It works perfectly when a number is input into fact. However, when a matrix is input into fact, it returns the matrix itself, without performing the factorial function.
E.g.
fact(3) returns 6
fact([1 2 3]) returns [1 2 3] instead of [1 2 6].
Any help is appreciated. Thank you very much!
Since MATLAB is not known to be good with recursive functions, how about a vectorized approach? Try this for a vector input -
mat1 = repmat([1:max(z)],[numel(z) 1])
mat1(bsxfun(#gt,1:max(z),z'))=1
output1 = prod(mat1,2)
Sample run -
z =
1 2 7
output1 =
1
2
5040
For the sake of answering your original question, here's the annoying loopy code for a vector or 2D matrix as input -
function k1 = fact1(z1)
k1 = zeros(size(z1));
for ii = 1:size(z1,1)
for jj = 1:size(z1,2)
z = z1(ii,jj);
if z ~= 0
k1(ii,jj) = z .* fact1(z-1);
else
k1(ii,jj) = 1;
end
end
end
return
Sample run -
>> fact1([1 2 7;3 2 1])
ans =
1 2 5040
6 2 1
You can use the gamma function to compute the factorial without recursion:
function k = fact(z)
k = gamma(z+1);
Example:
>> fact([1 2 3 4])
ans =
1 2 6 24
Not sure if all of you know, but there is an actual factorial function defined in MATLAB that can take in arrays / matrices of any size, and computes the factorial element-wise. For example:
k = factorial([1 2 3 4; 5 6 7 8])
k =
1 2 6 24
120 720 5040 40320
Even though this post is looking for a recursive implementation, and Divakar has provided a solution, I'd still like to put my two cents in and suggest an alternative. Also, let's say that we don't have access to factorial, and we want to compute this from first principles. What I would personally do is create a cell array that's the same size as the input matrix, but each element in this cell array would be a linear index array from 1 up to the number defined for each location in the original matrix. You would then apply prod to each cell element to compute the factorial. A precondition is that no number is less than 1, and that all elements are integers. As such:
z1 = ... ; %// Define input matrix here
z1_matr = arrayfun(#(x) 1:x, z1, 'uni', 0);
out = cellfun(#prod, z1_matr);
If z1 = [1 2 3 4; 5 6 7 8];, from my previous example, we get the same output with the above code:
out =
1 2 6 24
120 720 5040 40320
This will obviously be slower as there is an arrayfun then cellfun call immediately after, but I figured I'd add another method for the sake of just adding in another method :) Not sure how constructive this is, but I figured I'd add my own method and join Divakar and Luis Mendo :)

How can I create systematic matrices in MATLAB?

I'm setting up a script and I want it to systematically go through ALL POSSIBLE 2x2, 3x3, and 4x4 matrices modulo 2, 3, 4, 5, 6, and 7. For example, for modulus 2 in a 2x2, there would be 16 possibilities (4^2 because there are 4 positions with 2 possibilities each). I'm having trouble getting MATLAB to not only form all these possibilities but to put them through my script one at a time. Any thoughts?
Thanks!
This solution uses allcomb from matlab file exchange.
%size
n=2
%maximum value
m=2
%generate input for allcomb
e=cell(1,n^2)
e(1:end)={[0:m-1]}
%generate all combinations.
F=reshape(allcomb(e{:}),[],n,n)
F is a 3D-Matrix, to get the first possibility use:
squeeze(F(1,:,:))
A slight generalization of this Q&A does the job in one line:
r = 2; %// number of rows
c = 2; %// number of columns
n = 2; %// considered values: 0, 1, ..., n-1
M = reshape(dec2base(0:n^(r*c)-1, n).' - '0', r,c,[]);
Result for r, c, n as above:
M(:,:,1) =
0 0
0 0
M(:,:,2) =
0 0
0 1
...
M(:,:,16) =
1 1
1 1

how to Conditionally add values to a matrix without using a for loop?

I have written a for loop code and I want to write in more succinct way without using a for loop, but instead use matrix conditional.
I am teaching myself matlab and I would appreciate any feedback.
I want to create a new matrix, the first column is y, and the second column is filled with zero except for the y's whose indices are contained in the indices matrix. And in the latter case, add 1 instead of 0.
Thanks.
y=[1;2;3;4;5;6;7];
indices=[1;3;5];
[m,n]=size(y);
tem=zeros(m,1);
data=[y,tem];
[r,c]=size(indices);
for i=1:r
a=indices(i);
data(a,2 )=1;
end
Output:
data =
1 1
2 0
3 1
4 0
5 1
6 0
7 0
A shorter alternative:
data = [y(:), full(sparse(indices, 1, 1, numel(y), 1))];
The resulting matrix data is composed of two column vectors: y(:) and a sparse array, with "1"s at the positions corresponding to indices.
Using proper initialization and sparse matrices can be really useful in MATLAB.
How about
data = zeros( m, 2 );
data(:,1) = y;
data( indices, 2 ) = 1;