component wise indexing in Matlab - arrays

How can I do component wise Indexing in Matlab ?
given
N =
1 2
2 3
3 1
L =
0 2.0000 2.8284
2.0000 0 2.0000
2.8284 2.0000 0
I want to extract element of L that are given by rows of N
that is
[L(1,2),L(2,3),L(3,1)] = [2.0, 2.0, 2.8284]
We can easily do that using a for loop
Lele=zeros(3,1);
for i = 1:3
Lele(i) = L(N(i,1),N(i,2));
end
How can we do this in a vectorized way using indexing technique ?.
in other words how can we use the row of matrix as index

Extract linear indices using sub2ind and then use them to extract the required elements i.e.
Lele = L(sub2ind(size(L), N(:,1), N(:,2)));

Related

Add cell value from a matrix row based on corresponding index to another matrix row

I have two arrays A and B.
Column 1 of array A contains the index number of the samples; other columns of matrix A contain other attributes of each sample, (in array B, the first two cell along each row contain an attribute and the index number of a sample).
Columns 2, 4 and 6 of array B contain the index number of samples contained in matrix A.
I am trying to insert corresponding sample attribute in column 4 of array A (based on corresponding index number in array A and B) into new 3rd, 6th and 9th column of matrix B; to have matrix C as shown below:
A = [1,3.43,2.34,5.43,3.22;2,8.32,6.34,7.34,2.34;3,3.67,8.34,8.23,1.34;4,2.67;6.89,4.99,8.65;5,1.33,5.42,2.53,6.13]
B = [0.12,2,0.15,1,0.65,3;0.33,5,0.62,4,0.55,1;0.91,1,0.77,2,0.66,5]
C = [0.12,2,7.34,0.15,1,5.43,0.65,3,1.34;0.33,5,2.53,0.62,4,4.99,0.55,1,5.43;0.91,1,5.43,0.77,2,7.34,0.66,5,2.53]
I have tried the following code but got an error:
for i = 1:3
f = ismember(A(:,1(i)), B(:,2), 'rows');
k = find(f);
f = A(f,4);
C = [C,f(i)]
end
First of all you have a typo in your A matrix - different size of rows. Maybe you meant:
A = [1,3.43,2.34,5.43,3.22;
2,8.32,6.34,7.34,2.34;
3,3.67,8.34,8.23,1.34;
4,2.67,6.89,4.99,8.65;
5,1.33,5.42,2.53,6.13];
B = [ 0.12,2,0.15,1,0.65,3;
0.33,5,0.62,4,0.55,1;
0.91,1,0.77,2,0.66,5];
So if you run your code, you will have good numbers, but in bad order. You should try:
Z = [0;0;0];
C = [[B(:,1:2) Z B(:,3:4) Z B(:,5:6)]]; %Generating satic part
for j = 1:3 %generating dynamic part in loop
for i = 1:3
n = A(find(ismember(A(:,(1)), B(i,j*2), 'rows')),4);
C(i,j*3) = n;
end
end
The output is:
C =
0.1200 2.0000 7.3400 0.1500 1.0000 5.4300 0.6500 3.0000 8.2300
0.3300 5.0000 2.5300 0.6200 4.0000 4.9900 0.5500 1.0000 5.4300
0.9100 1.0000 5.4300 0.7700 2.0000 7.3400 0.6600 5.0000 2.5300

L2 Normalize a 3 dimensional matrix in Matlab

Is there a quick way of normalizing each row of a 3 dimensional Matrix without resorting to slow for loops in Matlab?
Say my input data looks like this:
d(:,:,1) =
1 2 3
4 5 6
d(:,:,2) =
7 8 9
10 11 12
I know that I can get the norm of each row by using
norms = sqrt(sum(d.^2,2))
norms(:,:,1) =
3.7417
8.7750
norms(:,:,2) =
13.9284
19.1050
But how to divide now the second dimension with these norm values?
I know that in 2 dims I can use ./ however this seems not to work for 3 dimensional data.
bsxfun is your friend:
out = bsxfun(#rdivide, d, norms);
What this does is that it temporarily creates a 3D matrix that replicates each row of norms for as many columns as there are in d and it divides each element in an element-wise manner with d and norms.
We get:
>> d = cat(3, [1 2 3; 4 5 6], [7 8 9; 10 11 12]);
>> norms = sqrt(sum(d.^2,2));
>> out = bsxfun(#rdivide, d, norms)
out(:,:,1) =
0.2673 0.5345 0.8018
0.4558 0.5698 0.6838
out(:,:,2) =
0.5026 0.5744 0.6462
0.5234 0.5758 0.6281
We can also verify that each row is L2-normalized by determining the sum of squares along each row independently and ensuring that each result sums to 1:
>> sum(out.^2, 2)
ans(:,:,1) =
1.0000
1.0000
ans(:,:,2) =
1.0000
1.0000
If the approach with bsxfun doesn't quite make sense, an alternative you could use is to create a matrix that respects the same dimensions as d by using repmat... then you can perform the element-wise division you desire:
>> out = d ./ repmat(norms, [1 size(d,2) 1])
out(:,:,1) =
0.2673 0.5345 0.8018
0.4558 0.5698 0.6838
out(:,:,2) =
0.5026 0.5744 0.6462
0.5234 0.5758 0.6281
With repmat you specify how many times you want the matrix to be copied in each dimension. We only want the matrix to be replicated over the columns while the number of rows and slices are the same... hence the vector [1 size(d,2) 1] that specifies how many times you want the matrix copied in each dimension.
Actually, this is what bsxfun does under the hood without you having to deal with the headaches of creating this temporary matrix. This replication is done for you without having you think about it.

Combine odd and even indexes of two array columns in matlab / octave

I have an array (b) with two columns I would like to combine the data with even indexes of the second column with the data of the odd indexes of the first.
PS: the numbers won't be this linear so I can't use linspace command it's just an example.
a1=[1;2;3;4;5]
a2=[1.5;2.5;3.5;4.5;5.5]
b=[a1,a2]
b array:
1.0000 1.5000
2.0000 2.5000
3.0000 3.5000
4.0000 4.5000
5.0000 5.5000
Final output below I'm trying to get:
1
2.5
3
4.5
5
How about:
[nb_rows,nb_cols] = size(b);
c = zeros(nb_rows,1);
c(1:2:end) = b(1:2:end,1);
c(2:2:end) = b(2:2:end,2);
This handles the cases that the number of elements in a1 (and a2) is odd or even:
c = b.'; %'//
n = numel(a1);
ind = bsxfun(#plus, [1;4], 0:4:2*n-1);
result = c(ind(1:n)).';
You can combine both vectors (odd and even), then sort them:
c = sort([a1(1:2:end); a2(2:2:end)])

Operations with arrays in Matlab

I have this 2-dimensional array
x=[62,29,64;
63,31,62;
65,29,60;
63,29,62;
63,31,62;];
1st element in each column is R, 2nd is G, 3rd is B from the formula below.
I would like a function to compute the following operation:
So far, my function definition looks like this:
function[distance]=RGB_dist(x,y)
distance=sqrt(sum(((x-y)*[3;4;2]).^2,2));
end
Tested with the matrix above, disp(RGB_dist(x,x)) outputs only zeroes. That must happen because he is calculating the distance between same vectors. How do I do to calculate the distance between any two vector(lines) from my matrix. Any help would be appreciated.
You can use bsxfun twice (once for the subtraction and once for applying the weights):
weights = [3 4 2];
d = squeeze(sqrt(sum(bsxfun(#times, ...
bsxfun(#minus, x.', permute(x, [2 3 1])).^2, weights(:)))));
One approach based on bsxfun and pdist2 -
%// Input RGB matrix
x=[62,29,64;
63,31,62;
65,29,60;
63,29,62;
63,31,62;];
Wgts = [3 4 2]; %// Weights
weuc = #(XI,XJ,W)(sqrt(bsxfun(#minus,XI,XJ).^2 * W'));
out = pdist2(x,x, #(Xi,Xj) weuc(Xi,Xj,Wgts)) %// output
Output -
out =
0 5.1962 7.6811 3.3166 5.1962
5.1962 0 6.0000 4.0000 0
7.6811 6.0000 0 4.4721 6.0000
3.3166 4.0000 4.4721 0 4.0000
5.1962 0 6.0000 4.0000 0
According to the smart comment posted by #Luis, it seems like in the final step you can use - out = squareform(pdist(x,#(Xi,Xj) weuc(Xi,Xj,Wgts))), which might be a bit faster, but no promises as no proper runtime benchmarks were done. The concepts squareform and pdist are introduced in Dan's solution, so credit to him for that. But the values seem different, so I am only guessing that the second input to pdist aren't the same between these two solutions.
For two arbitrary lines (e.g. line 1 and line 2) do:
RGB_dist(x(1,:), x(2,:))
if you want all the combinations then check out pdist2. If you don't have the stats toolbox (i.e. no pdist2) then use nchoosek to create all possible pairs of rows:
I = nchoosek(1:size(x,1),2);
D = RGB_dist(x(I(:,1),:), x(I(:,2),:))
by the way, if you want to use pdist or pdist2 then you will have to alter your function to be able to find the distance between one observation and a list of observations in one shot. The easiest way is to replace your - with bsxfun like this:
sqrt(sum(((bsxfun(#minus,x,y))*[3;4;2]).^2,2));
then you can go
D = pdist(x, #RGB_dist)
both methods give you
D =
7
1
1
7
6
8
0
2
6
8
or
squareform(D)
ans =
0 7 1 1 7
7 0 6 8 0
1 6 0 2 6
1 8 2 0 8
7 0 6 8 0
But this is probably wrong as this squares after multiplying by the weights. You probably don't want that so I think your final function should look like that in Divakar's answer

Insert the mean of each neighbouring value, into the original vector

I have a vector, I want to 'pad' it out in MATLAB so that the resultant vector is twice the length, with the extra data being mean values of the original neighboring values.
eg.
a = [1:10]
b = function of a, where b is now size 20
b = 0.5 1 1.5 2 2.5 3 3.5....... 9.5 10
You could do this in a single line using interpolation (notice that the first digit is NaN because it really isn't defined):
interp1(2:2:length(a)*2, a, 1:length(a)*2)
The idea is to have evenly spaced x values (i.e. 2,4,6...) so that you can have single spaced xi values (i.e. 1,2,3,4...) which are thus exactly half way between each x value. Then the linear interpolation of the y points will be their means. If you don't like that NaN in the front which I left in mostly to illustrate the point that it's undefined, you can use the 'extrap' flag in interp1, or (better imo) start your xi from 2:
interp1(2:2:length(a)*2, a, 1:length(a)*2, 'linear', 'extrap')
or
interp1(2:2:length(a)*2, a, 2:length(a)*2)
Otherwise here is a simple vectorized approach:
a = 1:10;
t = [a(1:end-1);a(2:end];
t(2,:) = mean(t);
b = [t(:); a(end)]
The simplest approach is to use linspace to specify the locations at which you would like to interpolate (and extrapolate) with interp1:
>> a = 1:10;
>> b = interp1(a,linspace(0.5,numel(a),2*numel(a)),'linear','extrap')
b =
Columns 1 through 8
0.5000 1.0000 1.5000 2.0000 2.5000 3.0000 3.5000 4.0000
Columns 9 through 16
4.5000 5.0000 5.5000 6.0000 6.5000 7.0000 7.5000 8.0000
Columns 17 through 20
8.5000 9.0000 9.5000 10.0000
Using 'linear' as the method gives the average of the neighboring values, and 'extrap' says to perform extrapolation (so b(1) does not come out as NaN, but rather 0.5).
It looks like you are assuming the "zeroth" entry is zero so that you get the same number of means as the length of the original vector. You can use
a2 = filter([0.5,0.5],1,a);
to get the vector of means, where the first entry will be the mean of 0 and the first entry in a. Then, you can do whatever you like to interleave the two vectors, e.g,
b = zeros(2*max(size(a)),1);
b(1:2:end) = a2;
b(2:2:end) = a;
filter is a nifty command, especially for computing discrete convolutions on your original data vector (your neighboring means are a very simple example of a convolution). It also works on matrices either row-by-row or column-by-column.

Resources