How to calculate mean of matrix based on column value - arrays

I have B matrix of N*4 dim. I want calculate the mean of the matrix based on last column values. Last column has repeated values in the range of 1 to 3. I want to calculate the mean of all rows whose last column have same value.
I am using this command:
l(it:,)=mean(B(i,:))
where it ranges from 1 to 3 in the loop and i has all the indices of rows whose last column=1.When I run this code I get Sub scripted assignment dimension mismatch error. Can anyone point out what is wrong in the command?

Consider the following example data:
B = [ 0.4000 0.3000 0.2000 1.0000
0.3000 0.2000 0.1000 2.0000
0.7000 0.8000 0.6000 1.0000
0.3000 0.4000 0.8000 2.0000
0.7000 0.5000 0.5000 3.0000
0.1000 0.3000 0.9000 3.0000
0.6000 0.4000 0.5000 1.0000 ];
Two possible approaches:
Using logical indexing:
result = NaN(3,3);
for k = 1:3
result(k,:) = mean(B(B(:,4)==k,1:3));
end
Using accumarray:
result = NaN(3,3);
for k = 1:3
result(:,k) = accumarray(B(:,4), B(:,k), [], #mean, NaN);
end
With the example data, either of the above gives
result =
0.5667 0.5000 0.4333
0.3000 0.3000 0.4500
0.4000 0.4000 0.7000

Your question is not the clearest, but I think I know what you are trying to do.
You say that i contains the indices of the rows of interest for each value 1,2,3 so I am assuming that you require
mean_k = mean(mean((B(i,:)))
for each k = 1,2,3. Obviously you must be recalculating i each time you iterate over 1,2,3 when identifying the relevant rows of interest.
The mean function when called on a matrix does not return a scalar, it returns a row vector whose elements are the mean of each column of the matrix. Therefore to get the mean, you need to call mean again on the result.
Bear in mind that this also includes the final column value (that you are using for classification) in your overall mean calculations

Related

component wise indexing in Matlab

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)));

Mean of two values having the same timestamp in an array

Following my question Merge 2 vectors according their time values: If two values in an array have the same timestamp I need to combine them and use the average value. How can I realize this in an elegant way?
Here is an example:
%1st column = time; 2nd column = value
%there are two values with timestamp '6'
C = [1,34;2,34;5,68;6,2;6,3;7,45]
C =
1 34
2 34
5 68
6 2
6 3
7 45
%after processing
C_proc =
1.0000 34.0000
2.0000 34.0000
5.0000 68.0000
6.0000 2.5000
7.0000 45.0000
That's what accumarray is for:
out = accumarray(C(:,1),C(:,2),[],#mean) %// use with care, see below
If you don't want the zeros for the skipped indices, combine it with unique, which also avoids the necessary assumption of integer timestamps of the first approach:
[a,~,u] = unique(C(:,1))
out = [a accumarray(u,C(:,2),[],#mean)]
out =
1.0000 34.0000
2.0000 34.0000
5.0000 68.0000
6.0000 2.5000
7.0000 45.0000

Replace some values of one MATLAB matrix with values from another

I'm a new programmer, working in MATLAB, and I am hoping to substitute some values in one of my matrices with information from another matrix.
So, for example, supposing I have one matrix [A]:
A = [0 0 0 0 0
.5 0 .2 .8 0
1 .3 1 .1 .1
1 1 .4 1 1
1 1 1 1 1]
And another matrix B:
B = [.4 .3 .2 .1 .2]
I would like to replace the first nonzero value in A with the one in the same column in matrix B such that:
A_new = [0 0 0 0 0
.4 0 .2 .1 0
1 .3 1 .1 .2
1 1 .4 1 1
1 1 1 1 1]
There are some values between 0 and 1 that I want to keep untouched which precludes just changing everything between 0 and 1 (exclusive). I'm sure the solution will involve an if statement and possibly a for loop, but I'm not sure how to set it up. Any advice is appreciated!
Try this:
[~, row] = max(A~=0);
A(row + (0:size(A,1):numel(A)-1)) = B
How it works:
The first line produces a vector row containing the index of the first nonzero row in each column. This use of max is a "column-wise find" of sorts. Namely, max works down each column and tells you the row index of the maximum value in that column. Since each column only contains 0 or 1, there may be several maximizing (1) values; max gives the (index of) the first one.
In the second line that vector is transformed into a linear index to replace those elements of A.
Another way, though probably inefficient, is to use find and search for row and column locations that are non-zero. Once you find this, because MATLAB searches for non-zero entries column-wise, you can apply diff to the column indices and find transitions. The elements on the right-hand of the transition denote the first non-zero value for each column. Once you find these locations, get the corresponding row locations for these entries, create a new matrix A_new that is a copy of A, then change the corresponding entries to B. You'll need to use sub2ind for the assignment.
Something like this:
%// Define matrix
A = [0 0 0 0 0
.5 0 .2 .8 0
1 .3 1 .1 .1
1 1 .4 1 1
1 1 1 1 1];
%// Find non-zero entries
[row,col] = find(A);
%// Figure out the column locations that are the first non-zero for each column
ind = diff([Inf; col]) ~= 0;
%// Create a new matrix that is a copy of the old one
A_new = A;
%// Create the B vector
B = [.4 .3 .2 .1 .2];
%// Do the assignment
A_new(sub2ind(size(A), row(ind), (1:size(A,2)).')) = B;
Doing sub2ind is perhaps inefficient because there is a lot error checking done and that can slow things down. You can compute the linear indices manually by:
columns = size(A,2);
A_new((0:columns-1).'*columns + row(ind)) = B;
Running the above code, we get:
>> A
A =
0 0 0 0 0
0.5000 0 0.2000 0.8000 0
1.0000 0.3000 1.0000 0.1000 0.1000
1.0000 1.0000 0.4000 1.0000 1.0000
1.0000 1.0000 1.0000 1.0000 1.0000
>> A_new
A_new =
0 0 0 0 0
0.4000 0 0.2000 0.1000 0
1.0000 0.3000 1.0000 0.1000 0.2000
1.0000 1.0000 0.4000 1.0000 1.0000
1.0000 1.0000 1.0000 1.0000 1.0000

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)])

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