Mean of two values having the same timestamp in an array - arrays

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

Related

Fast column by column array division

Suppose that M and N are two Arrays. In simplest case, M and N like this:
1 14 7 80
2 15 8 12
3 16 9 11
(3 Rows and 4 Columns)
I want to divide column 1 by All three Columns, then divide column 2 by All three Columns and then divide column 3 by All three Columns.
What is the fastest way to do it? ( Surely, using for-loop is not a good algorithm. )
EDIT:
here is my for-loop code:
idx = 1;
for i = 1 : size(N,2)
for j = 1 : size(M,2)
u(:,idx)=N(:,i) ./ M(:,j);
idx = idx + 1;
end
end
How about using bsxfun and permute
Assuming M and N are same and equal to A
out = bsxfun(#rdivide, permute(A,[1 3 2]), A)
Input:
A =
1 14 7 80
2 15 8 12
3 16 9 11
Results for your Sample Input:
out(:,:,1) =
1.0000 0.0714 0.1429 0.0125
1.0000 0.1333 0.2500 0.1667
1.0000 0.1875 0.3333 0.2727
out(:,:,2) =
14.0000 1.0000 2.0000 0.1750
7.5000 1.0000 1.8750 1.2500
5.3333 1.0000 1.7778 1.4545
out(:,:,3) =
7.0000 0.5000 1.0000 0.0875
4.0000 0.5333 1.0000 0.6667
3.0000 0.5625 1.0000 0.8182
out(:,:,4) =
80.0000 5.7143 11.4286 1.0000
6.0000 0.8000 1.5000 1.0000
3.6667 0.6875 1.2222 1.0000
If
A = [1 14 7 80
2 15 8 12
3 16 9 11]
Then
bsxfun(#ldivide, prod(A,2), A).*A
returning
ans =
0.0001 0.0250 0.0062 0.8163
0.0014 0.0781 0.0222 0.0500
0.0019 0.0539 0.0170 0.0255
So the idea is to just divide every element by ALL the other elements in that row (i.e. by the product of the row, prod(A,2)) and then just multiply back by the original number so cancel the fact that you've divided by it (i.e. the .*A at the end). So ans(2,3) above is 0.0222 which equals (8/(2*15*8*12))*8 where (2*15*8*12) is the product of row 3.
NOTE this answers the original question (i.e. the question you describe) and does NOT answer the question that your code implies

How to make value in excel sheet become element of matrix in matlab

i have xls file name databus.xls, like this
No. Bus Code Voltage Mag. Fasa Beban Generator Stat Mvar
MW Mvar MW Mvar Qmin Qmax +Qc/-Ql'
1 1 1.04 0 50 30.99 0 0 0 0 0
2 0 1 0 170 105.35 0 0 0 0 0
3 0 1 0 200 123.94 0 0 0 0 20
4 2 1.02 0 80 49.58 318 0 0 0 0
how to make the value become component of matrix a
like
a=[1 1 1.04 0 50 30.99 ...etc
2 0 1 0 170 105.35 ...etc
...etc ]
If this is a one time operation, copy-paste is the simplest approach. If not, I would suggest xlsread
Try:
filename = 'databus.xls';
sheet = 1;
xlRange = 'A3:J7';
a = xlsread(filename, sheet, xlRange)
If there's only one sheet, you can skip the second argument and just do:
filename = 'databus.xls';
a = xlsread(filename,'A3:J7')
If you do not know the range, simply follow the documentation given in the link above:
num = xlsread(filename) reads data from the first worksheet in the
Microsoft® Excel® spreadsheet file named filename and returns the
numeric data in array num.
So, to show an example:
num = xlsread('test.xlsx')
num =
1.0000 1.0000 1.0000 50.0000 30.0000
2.0000 1.0000 1.0000 112.0000 60.0000
3.0000 2.0000 4.0000 40.0000 20.0000
4.0000 2.0000 3.0000 30.0000 20.0000
5.0000 3.0000 2.0000 60.0000 42.5000
As this reads all numeric data, you might get some rows with mostly NANs, if only a few of the columns contain numbers. If that's the case, you can simply delete those lines.
You have to split your task in two:
Export your data from Excel.
Import your data into Matlab.
For task 2, there are several options (links to official documentation are provided):
csvread
dimread
fscanf
importdata
Etc.?
See also Ways to Import Text Files and How do you create a matrix from a text file in MATLAB?.
If you use method 1 for task 2, then you have to export as csv from Excel.
Copy your worksheet into a new one.
Remove data not going into your matrix (as per your question, the first two rows).
Save as CSV.
Voilà

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.

How to calculate mean of matrix based on column value

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

Resources