Multiplication of data in MATLAB - matlab

I have 3 datasets in one 40×7 double data set and I want to multiply these and plot the result over a time period. My question is how to do that.
My attempt has been to divide the datasets into 3 individual cells of data and call them A, B and C (each with 40×3) by using the operator a=[{A}] and so on.
Next, I multiplied them with each other by using .*a.*b.*c and with the time t=[0:40] (which is the x-axis).
I get the following error and I don't know what to do.
Index exceeds matrix dimensions
Anyone that can help me?
Code as provided by OP in a comment:
a = ans(:,1:3);
b = ans(:,4:6);
c = ans(:,7:9);
A[{xyz}];
B=[{a}];
C=[{c}];
t=[0:41];
D=(A.*B.*C);
plot(D,t);

One way to do this is to combine reshape and permute, and take the product along the third dimension.
Assume the following is your data. This will be 40x9 in your case.
rows = 4; cols = 6; N = 2;
x = ceil(10*rand(rows,cols))
x =
9 6 1 6 5 8
6 9 9 5 10 6
10 9 7 9 6 3
7 10 10 3 9 7
r = permute(reshape(x, rows, N, []), [3,1,2])
result = prod(r,3).'
result =
54 6 40
54 45 60
90 63 18
70 30 63

So looking at your code, it seems unnecessary to create a cell from it:
you can for example:
ans=rand(40,9);
a = ans(:,1:3); b = ans(:,4:6); c = ans(:,7:9);
D=a.*b.*c;
t=[1:40];
plot(D,t)
or
ans=rand(40,9);
a = ans(:,1:3); b = ans(:,4:6); c = ans(:,7:9);
D=a.*b.*c;
t=[0:39];
plot(D,t)
Your t vector has to have the same length as your inital matrix - your matrix has 40 rows but the vector you create by t=[0:40] is 41 entries long so you either do t=[1:40] or t=[0:39]
and if t is your x-axis you should plot it in the right order so plot(t,D) instead of plot(D,t)

Related

Summing specific columns for each row in a matrix of double

I would like to sum specific columns of each row in a matrix using a for loop. Below I have included a simplified version of my problem. As of right now, I am calculating the column sums individually, but this is not effective as my actual problem has multiple matrices (data sets).
a = [1 2 3 4 5 6; 4 5 6 7 8 9];
b = [2 2 3 4 4 6; 3 3 3 4 5 5];
% Repeat the 3 lines of code below for row 2 of matrix a
% Repeat the entire process for matrix b
c = sum(a(1,1:3)); % Sum columns 1:3 of row 1
d = sum(a(1,4:6)); % Sum columns 4:6 of row 1
e = sum(a(1,:)); % Sum all columns of row 1
I would like to know how to create a for loop that automatically loops through and sums the specific columns of each row for each matrix that I have.
Thank you.
Here is a solution that you don't need to use for loop.
Assuming that you have a matrix a of size 2x12, and you want to do the row sums every 4 columns, then you can use reshape() and squeeze() to get the final result:
k = 4;
a = [1:12
13:24];
% a =
% 1 2 3 4 5 6 7 8 9 10 11 12
% 13 14 15 16 17 18 19 20 21 22 23 24
s = squeeze(sum(reshape(a,size(a,1),k,[]),2));
and you will get
s =
10 26 42
58 74 90

How to split a matrix based on how close the values are?

Suppose I have a matrix A:
A = [1 2 3 6 7 8];
I would like to split this matrix into sub-matrices based on how relatively close the numbers are. For example, the above matrix must be split into:
B = [1 2 3];
C = [6 7 8];
I understand that I need to define some sort of criteria for this grouping so I thought I'd take the absolute difference of the number and its next one, and define a limit upto which a number is allowed to be in a group. But the problem is that I cannot fix a static limit on the difference since the matrices and sub-matrices will be changing.
Another example:
A = [5 11 6 4 4 3 12 30 33 32 12];
So, this must be split into:
B = [5 6 4 4 3];
C = [11 12 12];
D = [30 33 32];
Here, the matrix is split into three parts based on how close the values are. So the criteria for this matrix is different from the previous one though what I want out of each matrix is the same, to separate it based on the closeness of its numbers. Is there any way I can specify a general set of conditions to make the criteria dynamic rather than static?
I'm afraid, my answer comes too late for you, but maybe future readers with a similar problem can profit from it.
In general, your problem calls for cluster analysis. Nevertheless, maybe there's a simpler solution to your actual problem. Here's my approach:
First, sort the input A.
To find a criterion to distinguish between "intraclass" and "interclass" elements, I calculate the differences between adjacent elements of A, using diff.
Then, I calculate the median over all these differences.
Finally, I find the indices for all differences, which are greater or equal than three times the median, with a minimum difference of 1. (Depending on the actual data, this might be modified, e.g. using mean instead.) These are the indices, where you will have to "split" the (sorted) input.
At last, I set up two vectors with the starting and end indices for each "sub-matrix", to use this approach using arrayfun to get a cell array with all desired "sub-matrices".
Now, here comes the code:
% Sort input, and calculate differences between adjacent elements
AA = sort(A);
d = diff(AA);
% Calculate median over all differences
m = median(d);
% Find indices with "significantly higher difference",
% e.g. greater or equal than three times the median
% (minimum difference should be 1)
idx = find(d >= max(1, 3 * m));
% Set up proper start and end indices
start_idx = [1 idx+1];
end_idx = [idx numel(A)];
% Generate cell array with desired vectors
out = arrayfun(#(x, y) AA(x:y), start_idx, end_idx, 'UniformOutput', false)
Due to the unknown number of possible vectors, I can't think of way to "unpack" these to individual variables.
Some tests:
A =
1 2 3 6 7 8
out =
{
[1,1] =
1 2 3
[1,2] =
6 7 8
}
A =
5 11 6 4 4 3 12 30 33 32 12
out =
{
[1,1] =
3 4 4 5 6
[1,2] =
11 12 12
[1,3] =
30 32 33
}
A =
1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3
out =
{
[1,1] =
1 1 1 1 1 1 1
[1,2] =
2 2 2 2 2 2
[1,3] =
3 3 3 3 3 3 3
}
Hope that helps!

What wrong with the following code?

I have a 20*120 matrix. For each column in the matrix I need to find the maximum value between all the values, and then sum the remaining values. Then I need to divide the maximum value by the summation of the remaining values. I tried the following code but the result was not correct. What is the problem?
s = 1:z %z=120
for i = 1:x %x=20
maximss = max(Pres_W); %maximum value
InterFss = (sum(Pres_W))-maximss; %remaining values
SIRk(:,s) = (maximss(:,s))./(InterFss(:,s));
end
Instead of answering "what's wrong", I'll first provide a solution explaining how this should be done:
Say we have an example matrix m as follows:
m =
8 5 9 14 10 7 5
10 8 12 11 9 9 12
10 3 7 7 8 4 6
13 11 6 15 13 11 9
Find the maximum value of each column:
col_max = max(m, [], 1)
col_max =
13 11 12 15 13 11 12
Sum all elements in each column, and substract the maximum values:
col_sum = sum(m, 1) - col_max
col_sum =
28 16 22 32 27 20 20
Divide the maximum value by the sum of the other elements:
col_max ./ col_sum
ans =
0.46429 0.68750 0.54545 0.46875 0.48148 0.55000 0.60000
Or, as a one-liner:
max(m,[],1)./(sum(m,1)-max(m,[],1))
ans =
0.46429 0.68750 0.54545 0.46875 0.48148 0.55000 0.60000
By the way: Your code does exactly what you're explaining, it returns the maximum value divided by all values except the maximum value.
Notes regarding best practice:
Vectorize things like this, no need for loops.
max(m, [], 1) is the same as max(m) for 2D-arrays. However, if your matrix for some reason only have one row, it will return the maximum value of the row, thus a single number.
sum(m,1) is the same as sum(m) for 2D-arrays. However, if your matrix for some reason only have one row, it will return the sum of the row, thus a single number.

Creating a column of certain values from an array? Matlab [duplicate]

Suppose I had a 1-by-12 matrix and I wanted to resize it to a 4-by-3 matrix. How could I do this?
My current solution is kind of ugly:
for n = 1:(length(mat)/3)
out(n,1:3) = mat( ((n-1)*3 + 1):((n-1)*3 + 3) );
end
Is there a better way to do this?
reshape is of course the proper solution, as stated by #gnovice.
A nice feature of reshape is that it allows this:
A = 1:12;
B = reshape(A,4,[]);
B =
1 5 9
2 6 10
3 7 11
4 8 12
So if you don't know how many columns there will be, reshape will compute it for you. Likewise, reshape will fill in the number of rows, if you leave that out.
C = reshape(A,[],4)
C =
1 4 7 10
2 5 8 11
3 6 9 12
Try the RESHAPE function:
A = (1-by-12 matrix);
B = reshape(A,4,3);
Note that the matrix B will be filled with elements from A in a columnwise fashion (i.e. columns will be filled from top to bottom, moving left to right).
Example:
>> A = 1:12;
>> B = reshape(A,4,3)
B =
1 5 9
2 6 10
3 7 11
4 8 12
to extend gnovice's solution:
If you need a different order of matrix construction, use transpose (the ' operator) or permute() to change the dimension ordering after you have called reshape().

Filtering an adjacency matrix in matlab

I have got a nx3 adjacency matrix that contains nodes in the first two dimension and the correspondant weight in the third dimension. I want to filter the matrix for specific thresholds (for nodes indexing). For example, I want to keep the adjacency matrix for nodes smaller than 10.000, 20.000, etc. Which is the most efficient way to do so in matlab? I tried to do the following, find the index which correspond to nodes:
counter = 1;
for i=1: size(graph4, 1)
if (graph4(i,1) >30000) | (graph4(i,2) >30000)
bucket(counter) = i;
counter=counter+1;
end
end
Suppose the adjacency matrix is A as given below:
A =
8 1 6
3 5 7
4 9 2
11 4 9
6 8 10
7 12 5
17 10 15
12 14 16
13 18 11
If you want both column 1 and column 2 to be less than a value, you can do:
value = 10;
T = A(A(:,1) < value & A(:,2) < value, :)
T =
8 1 6
3 5 7
4 9 2
6 8 10
The following line seems to give the same results as your sample code (but it doesn't seem like it fits your description.
value = 10000;
bucket = find((A(:,1)>value) | A(:,2)>value)
I guess you made a mistake and want to increment the counter above the bucket-line and initialize it as counter = 0 before the loop? As it is now, it will be one more than the number of elements in the bucket-list.