Coordinates of dimension-wise maximum of Matlab array - arrays

I have 5-dimensional array of numbers. The goal is to find maximum values along 5-th dimension and their coordinates. I use
[x,y] = max(A,[],5);
Ideally I expect that x == A(y), however this does not appear to happen. I need an idea of how to translate y to an array of coordinates z such that x == A(z). Using find + loops is costly in my case, since matrices are huge.

Suppose your matrix A has dimension of (m,n,o). Now you have the indices of maximum entries along the 3rd dimension in y and the corresponding maximum values in x. You can access the maximum values by the following code-
z = (1:m*n)' + (y(:)-1)*(m*n); % linear index of these locations in full array
final_matrix = reshape(A(z),m,n);
It can be easily extended to 5 dimensional matrices.
Try this code for 5-dimensional-
[x,y] = max(A,[], 5);
z = (1:m*n*o*p)' + (y(:)-1)*(m*n*o*p);
final_matrix = reshape(A(z),m,n,o,p);

s = size(A);
[v,ii] = max(reshape(A,[],s(3)));
[i1 j1 ] = ind2sub(s(1:2),ii);
out = [v;i1;j1;1:s(3)]';

Related

How can I merge my data set based on the time in MATLAB?

I want to merge the two data into one. But as they are in two different times that's why I cannot just combine them.
I need to add them by keeping the time as it is.
How can I do this?
data_1_y_axes=[0,1,3,5,4,6,8,9,7]
time_1_x_axes=[.02,0.03,.05,.06,.07,0.08,0.09,.1,.2]
data_2_y_axes=[0,2,4,5,2,7,5,7,5]
time_2_x_axes=[.002,0.004,.006,.009,.02,0.04,0.06,.07,.09]
plot(time_1_x_axes,data_1_y_axes)
hold on
plot(time_2_x_axes,data_2_y_axes)
My expected data will be as follows:
New_data=[ 0, 2,4,5,2+0,1,7,3,5+5,7+4,6,5+8,9,7]
New_time=[.002,.004,.006,.009,.02,.03,.04,.05,.06,.07,.08,.09,.1,.2]
How can I do this?
Here is another way to do it without using a for loop. This will run much faster:
data_1_y_axes=[0,1,3,5,4,6,8,9,7]
time_1_x_axes=[.02,0.03,.05,.06,.07,0.08,0.09,.1,.2]
data_2_y_axes=[0,2,4,5,2,7,5,7,5]
time_2_x_axes=[.002,0.004,.006,.009,.02,0.04,0.06,.07,.09]
[time_merged,i1,i2] = intersect(time_1_x_axes, time_2_x_axes)
data_merged = data_1_y_axes(i1) + data_2_y_axes(i2)
[time1_remaining, ir1] = setdiff(time_1_x_axes, time_merged)
[time2_remaining, ir2] = setdiff(time_2_x_axes, time_merged)
[time_merged, idx] = sort([time_merged time_1_x_axes(ir1) time_2_x_axes(ir2)])
data_merged = [data_merged data_1_y_axes(ir1) data_2_y_axes(ir2)]
data_merged = data_merged(idx)
plot(time_merged,data_merged)
You could combine the x and y axis arrays, then aggregate by x-axis values using
unique to get unique x values and their indices within the y values) and
accumarray to add up all of the y values with a common x axis index
Using your example data, this would look like:
y1 =[0,1,3,5,4,6,8,9,7];
x1 =[.02,0.03,.05,.06,.07,0.08,0.09,.1,.2];
y2 =[0,2,4,5,2,7,5,7,5];
x2 =[.002,0.004,.006,.009,.02,0.04,0.06,.07,.09];
x = [x1, x2]; % Combine x axis data
y = [y1, y2]; % Combine y axis data
[x, ~, idx] = unique( x(:) ); % Get unique x, and their indices
y = accumarray( idx, y ); % Add up y values according to x value index
Aggregating Sample Values With Different Sampling Times
The following approach combines the data into a single vectors, Time_Vector and Data_Vector. Then the unique() function is used to find the unique sample times that exist within Time_Vector. A for-loop is used to evaluate the indices where the same sample time exists by using the find() function. After finding these indices the corresponding values are obtained by using matrix indexing (finds all the values that occur at a given sample time). The aggregate is then taken of this array by using the sum() function.
data_1_y_axes = [0,1,3,5,4,6,8,9,7];
time_1_x_axes = [0.02,0.03,0.05,0.06,0.07,0.08,0.09,0.1,0.2];
data_2_y_axes = [0,2,4,5,2,7,5,7,5];
time_2_x_axes = [0.002,0.004,0.006,0.009,0.02,0.04,0.06,0.07,0.09];
Data_Vector = [data_1_y_axes data_2_y_axes];
Time_Vector = [time_1_x_axes time_2_x_axes];
Unique_Times = unique(Time_Vector);
for Sample_Index = 1: length(Unique_Times)
Time_Value = Unique_Times(Sample_Index);
Indices_With_Matching_Time = find(Time_Vector == Time_Value);
Output_Data(Sample_Index) = sum(Data_Vector(Indices_With_Matching_Time));
end
plot(Unique_Times,Output_Data);
Ran using MATLAB R2019b

Calculation mean across dimensions

Beginners MATLAB question
I have 4 variables(beam1,beam2,beam3,beam4) in separate arrays with the same dimensions (23746 x 35). I want to calculate the average of the 4 arrays to have an answer in one array with the same size (23746 x 35). In other words I want to average the values in the first dimension.
x = beam1,beam2,beam3,beam4
xx = mean(x,1)
Gives a 1x35 array and
x = beam1,beam2,beam3,beam4
xx = mean(x,2)
Gives a 23746x1 array
How do I keep the same dimensions (23746 x 35) in the new array and compute the average value of the 4 individual arrays?
Many thanks
Doesn't simply doing
xx = (beam1 + beam2 + beam3 + beam4)/4
give what you want?
Note that it's typically bad practice to have variable names that only differ by an appended integer such as you have. You've be better creating the data as a 3-dimenional array where
beam_data = beam1;
beam_data(:,:,2) = beam2;
beam_data(:,:,3) = beam3;
beam_data(:,:,4) = beam4;
In this way if you have more (or less) beams then you don't have a proliferation of variables.
It also means irrespective of how many beams you have the mean would be calculates along the 3rd dimension
beam_mean = mean(beam_data,3);

MATLAB pairwise differences in Nth dimension

Say i have a N-Dimensional matrix A that can be of any size. For example:
A = rand([2,5,3]);
I want to calculate all possible pairwise differences between elements of the matrix, along a given dimension. For example, if i wanted to calculate the differences along dimension 3, a shortcut would be to create a matrix like so:
B = cat(3, A(:,:,2) - A(:,:,1), A(:,:,3) - A(:,:,1), A(:,:,3) - A(:,:,2));
However, i want this to be able to operate along any dimension, with a matrix of any size. So, ideally, i'd like to either create a function that takes in a matrix A and calculates all pairwise differences along dimension DIM, or find a builtin MATLAB function that does the same thing.
The diff function seems like it could be useful, but it only calculates differences between adjacent elements, not all possible differences.
Doing my research on this issue, i have found a couple of posts about getting all possible differences, but most of these are for items in a vector (and ignore the dimensionality issue). Does anyone know of a quick fix?
Specific Dimension Cases
If you don't care about a general solution, for a dim=3 case, it would be as simple as couple lines of code -
dim = 3
idx = fliplr(nchoosek(1:size(A,dim),2))
B = A(:,:,idx(:,1)) - A(:,:,idx(:,2))
You can move around those idx(..) to specific dimension positions, if you happen to know the dimension before-hand. So, let's say dim = 4, then just do -
B = A(:,:,:,idx(:,1)) - A(:,:,:,idx(:,2))
Or let's say dim = 3, but A is a 4D array, then do -
B = A(:,:,idx(:,1),:) - A(:,:,idx(:,2),:)
Generic Case
For a Nth dim case, it seems you need to welcome a party of reshapes and permutes -
function out = pairwise_diff(A,dim)
%// New permuting dimensions
new_permute = [dim setdiff(1:ndims(A),dim)];
%// Permuted A and its 2D reshaped version
A_perm = permute(A,new_permute);
A_perm_2d = reshape(A_perm,size(A,dim),[]);
%// Get pairiwse indices for that dimension
N = size(A,dim);
[Y,X] = find(bsxfun(#gt,[1:N]',[1:N])); %//' OR fliplr(nchoosek(1:size(A,dim),2))
%// Get size of new permuted array that would have the length of
%// first dimension equal to number of such pairwise combinations
sz_A_perm = size(A_perm);
sz_A_perm(1) = numel(Y);
%// Get the paiwise differences; reshape to a multidimensiona array of same
%// number of dimensions as the input array
diff_mat = reshape(A_perm_2d(Y,:) - A_perm_2d(X,:),sz_A_perm);
%// Permute back to original dimension sequence as the final output
[~,return_permute] = sort(new_permute);
out = permute(diff_mat,return_permute);
return
So much for a generalization , huh!

Trimming vals in a matrix of arbitrary dimensions in a specified dimension

I'm writing a function that requires some values in a matrix of arbitrary dimansions to be dropped in a specified dimension.
For example, say I have a 3x3 matrix:
a=[1,2,3;4,5,6;7,8,9];
I might want to drop the third element in each row, in which case I could do
a = a(:,1:2)
But what if the dimensions of a are arbitrary, and the dimension to trim is defined as an argument in the function?
Using linear indexing, and some carefully considered maths is an option but I was wondering if there is a neater soltion?
For those interested, this is my current code:
...
% Find length in each dimension
sz = size(dat);
% Get the proportion to trim in each dimension
k = sz(d)*abs(p);
% Get the decimal part and integer parts of k
int_part = fix(k);
dec_part = abs(k - int_part);
% Sort the array
dat = sort(dat,d);
% Trim the array in dimension d
if (int_part ~=0)
switch d
case 1
dat = dat(int_part + 1 : sz(1) - int_part,:);
case 2
dat = dat(:,int_part + 1 : sz(2) - int_part);
end
end
...
It doesn't get any neater than this:
function A = trim(A, n, d)
%// Remove n-th slice of A in dimension d
%// n can be vector of indices. d needs to be scalar
sub = repmat({':'}, 1, ndims(A));
sub{d} = n;
A(sub{:}) = [];
This makes use of the not very well known fact that the string ':' can be used as an index. With due credit to this answer by #AndrewJanke, and to #chappjc for bringing it to my attention.
a = a(:, 1:end-1)
end, used as a matrix index, always refers to the index of the last element of that matrix
if you want to trim different dimensions, the simplest way is using and if/else block - as MatLab only supports 7 dimensions at most, you wont need an infinite number of these to cover all bases
The permute function allows to permute the dimension of an array of any dimension.
You can place the dimension you want to trim in a prescribed position (the first, I guess), trim, and finally restore the original ordering. In this way you can avoid running loops and do what you want compactly.

Optimize parameters of a pairwise distance function in Matlab

This question is related to matlab: find the index of common values at the same entry from two arrays.
Suppose that I have an 1000 by 10000 matrix that contains value 0,1,and 2. Each row are treated as a sample. I want to calculate the pairwise distance between those samples according to the formula d = 1-1/(2p)sum(a/c+b/d) where a,b,c,d can treated as as the row vector of length 10000 according to some definition and p=10000. c and d are probabilities such that c+d=1.
An example of how to find the values of a,b,c,d: suppose we want to find d between sample i and bj, then I look at row i and j.
If kth entry of row i and j has value 2 and 2, then a=2,b=0,c=1,d=0 (I guess I will assign 0/0=0 in this case).
If kth entry of row i and j has value 2 and 1 or vice versa, then a=1,b=0,c=3/4,d=1/4.
The similar assignment will give to the case for 2,0(a=0,b=0,c=1/2,d=1/2),1,1(a=1,b=1,c=1/2,d=1/2),1,0(a=0,b=1,c=1/4,d=3/4),0,0(a=0,b=2,c=0,d=1).
The matlab code I have so far is using for loops for i and j, then find the cases above by using find, then create two arrays for a/c and b/d. This is extremely slow, is there a way that I can improve the efficiency?
Edit: the distance d is the formula given in this paper on page 13.
Provided those coefficients are fixed, then I think I've successfully vectorised the distance function. Figuring out the formulae was fun. I flipped things around a bit to minimise division, and since I wasn't aware of pdist until #horchler's comment, you get it wrapped in loops with the constants factored out:
% m is the data
[n p] = size(m, 1);
distance = zeros(n);
for ii=1:n
for jj=ii+1:n
a = min(m(ii,:), m(jj,:));
b = 2 - max(m(ii,:), m(jj,:));
c = 4 ./ (m(ii,:) + m(jj,:));
c(c == Inf) = 0;
d = 1 - c;
distance(ii,jj) = sum(a.*c + b.*d);
% distance(jj,ii) = distance(ii,jj); % optional for the full matrix
end
end
distance = 1 - (1 / (2 * p)) * distance;

Resources