This question already has answers here:
Fast Algorithms for Finding Pairwise Euclidean Distance (Distance Matrix)
(3 answers)
Closed 5 years ago.
I am trying to calculate the Square Euclidean Distance between each column from two matrices and store in matrix D.
im_patches is 81*60840 double
codebook is 81*456 double
SquareEuclidean = #(x, y) x'*x+y'*y-2*x'*y;
% Get N*K distance matrix D between the N patches extracted
% from the image (im patches) and the K prototypes in the codebook
D=zeros(size(im_patches,2),size(codebook, 2));
for i=1:size(im_patches,2)
for j=1:size(codebook, 2)
D(i,j)=SquareEuclidean(im_patches(:,i),codebook(:,j));
end
end
However, this is very inefficient that cost more than 10 minutes in my laptop.
I am wondering is there a better way of using bsxfun. So I tried:
D2 = bsxfun(#(x,y) x'.*x+y'.*y-2.*x'.*y,im_patches,codebook);
which gives an error:
Error using bsxfun: Non-singleton dimensions of the two input arrays must match each other.
I think bsxfun or arrayfun would be a nice way of dealing such problem. But don't know the correct way of doing this.
Thank you in advance.
Your loop can be reduced to:
bsxfun(#plus,sum(im_patches.'.^2,2),sum(codebook.^2)-2*im_patches.'*codebook)
In MATLAB r2016b there is no need to bsxfun:
sum(im_patches.'.^2,2)+sum(codebook.^2)-2*im_patches.'*codebook
Related
This question already has answers here:
Multiply a 3D matrix with a 2D matrix
(10 answers)
Closed 5 years ago.
I try to use svd in my work which will return the vector as below.
A=rand(10,5);
b=rand(10,5,100);
[U, S , V]=svd(A);
What I'm trying to do is to multiply each slice of b with U. With one specific slice, this operation is valid:
c=U'*b(:,:,1);
However when I try to use a vectorized method as below, it return array dimensions mismatch error.
Utran=U.';
c = cellfun(#(x) x.*b,num2cell(Utran,[1 2]),'UniformOutput',false);
I could probably use loop for the first method, but it's not efficient if I have a large matrix. Any idea what's my mistake here?
The following is a vectorized solution.
Not sure if it's faster than using loops; and even if it is, note that it uses more memorry for intermediate computations:
result = permute(sum(permute(conj(U), [1 3 4 2]).*b), [4 2 3 1]);
This question already has an answer here:
MATLAB: Comparing 2 arrays with different lengths
(1 answer)
Closed 6 years ago.
I have the following problem:
I have two data vectors v1 (Length N1=13812) and v2 (Length N2=60002021). I have to bring both vectors in the same length N3 using interpolation bzw. downsampling, with the requirement: 2xN1.
Can somebody help me? My idea was to use: interp, interp1 and downsample to solve to problem. Is that the right approach?
Depending on your signal and sampling rate, using interp1 might not be the right thing to do.
There is a resample function that you could use like this:
v1_resampled = resample(v1, 2, 1);
v2_resampled = resample(v2, p, q);
where the parameters p, q depending on the sampling rate of your vector v2.
Always check the beginning / end of the resampled vectors. Check NaNs and be careful if you have non equidistant sampling.
Another possible alternative would be to use a moving average / moving median filter on the higher resolution signal. The best resampling approach really depends on the signal type.
This question already has answers here:
Weighted sampling without replacement in Matlab
(5 answers)
Weighted random numbers in MATLAB
(4 answers)
Closed 7 years ago.
I'm trying to calculate 5 numbers at random. The numbers 1-35 have set probability weights that are assigned to each number. I'm wondering how, in Matlab, to compute 5 random numbers with weights WITHOUT repeats. Also seeking how to compute 5 sets of those.
Although I would suspect MATLAB has a built in function for this, the documentation for randsample suggests otherwise:
Y = randsample(N,K,true,W) or randsample(POPULATION,K,true,W) returns a
weighted sample, using positive weights W, taken with replacement. W is
often a vector of probabilities. This function does not support weighted
sampling without replacement.
So, instead, since you only are looking for a few numbers, looping isn't a terrible idea:
POP = 1:35;
W = rand(1,35); W=W/sum(W);
k = 5;
mynumbers = zeros(1,k);
for i=1:k
mynumbers(i) = randsample(POP,1,true,W);
idx2remove = find(POP==mynumbers(i));
POP(idx2remove) = [];
W(idx2remove) = [];
end
The entries in W are your weights. The vector POP is your number 1 through 35. The number k is how many you'd like to choose.
The loop randomly samples one number (with weights) at a time using MATLAB's randsample, then the selected number and corresponding weight are removed from POP and W.
For larger k I hope there's a better solution...
This question already has answers here:
element by element matrix multiplication in Matlab
(2 answers)
Closed 7 years ago.
I am trying to multiply 2 matrices in Matlab, but they don't have the same dimension. In fact, my multiplication isn't quite the standard matrix multiplication.
I have a 31-by-1 matrix (or vector), and a 31-by-512-by-512 matrix.
I would like to take the 1st element of my vector and multiply the 1st 512-by-512 slice with it and so on, resulting in a new 31-by-512-by-512 array.
But I don't want to use for loops for performance issues.
This is the straightforward use-case of bsxfun:
bsxfun(#times, v, M)
Or you might have to permute you vector, v, so that its singelton dimension is orthogonal the direction you want to expand over (in your case it's actually along dimension one and two), i.e. turn v into a 31-by-1-by-1 (although I'm not certain if this is necessary, try it if you get errors) as in your case you will be expanding along the third dimension:
bsxfun(#times, permute(v,[1,3,2]), M)
Note that another common way to do this is using repmat and .* but bsxfun is more efficient.
This question already has answers here:
Vector norm of an array of vectors in MATLAB
(4 answers)
Closed 5 years ago.
I have a 3 columns, n rows matrix:
[ a,b,c;
d,e,f;
g,h,i; ]
I want to apply the norm function to each of the rows, and get a 1xn matrix containing the norms:
[ norm([a,b,c]);
norm([d,e,f]);
norm([g,h,i]); ]
I could do this with a for-loop, but is there a better way?
What about
norms = sqrt(sum(A.^2,1))
or
norms = sqrt(sum(A.^2,2))?
depending on whether your coordinates are in rows or in columns.
If readability is a bigger consideration than performance you might also consider:
norms = cellfun(#norm,num2cell(A,2));
This pattern is also adaptable to other operations along one dimension you might want to perform where MATLAB doesn't support it natively.
if the first dimension is not too large:
norms = sqrt(diag(A * A'));