I have a matrix like the following:
A =
5 2 10 14 11
I am looking to create an additional row using this data. The element in the fifth column, second row, is constant and known: 100
By subtracting from the above row I am looking to insert these values
B =
63 65 75 89 100
E.g. 100-11 = 89. 89-14=75
To ultimately give the following:
[A;B]
ans =
5 2 10 14 11
63 65 75 89 100
Any suggestions?
You can use the cumulative summation of the elements of A, via the MATLAB function cumsum, in order to perform this calculation:
knownvalue = 100;
firstrow = [5 2 10 14 11]
secondrow = fliplr(knownvalue - cumsum([0 firstrow(end:-1:2)]))
I believe what you are after is this:
A = [5, 2, 10, 14, 11];
Soln = [A; 100 * ones(1, length(A))];
Soln(2, 1:end - 1) = 100 - fliplr(cumsum(fliplr(A(2:end))));
EDIT: Probably go with cjh's solution (+1 for it). It requires one less call to fliplr so is probably faster.
Related
I want to repeat a row vector to create a matrix, in which every row is a slightly modified version of the original vector.
For example, if I have a vector v = [10 20 30 40 50], I want every row of my matrix to be that vector, but with a random number added to every element of the vector to add some fluctuations.
My matrix should look like this:
M = [10+a 20+a 30+a 40+a 50+a;
10+b 20+b 30+b 40+b 50+b;
... ]
Where a, b, ... are random numbers between 0 and 2, for an arbitrary number of matrix rows.
Any ideas?
In Matlab, you can add a column vector to a matrix. This will add the vector elements to each of the row values accordingly.
Example:
>> M = [1 2 3; 4 5 6; 7 8 9];
>> v = [1; 2; 3];
>> v + M
ans =
2 3 4
6 7 8
10 11 12
Note that in your case v is a row vector, so you should transpose it first (using v.').
As Sardar Usama and Wolfie note, this method of adding is only possible since MATLAB version R2016b, for earlier versions you will need to use bsxfun:
>> % instead of `v + M`
>> bsxfun(#plus, v, M)
ans =
2 4 6
5 7 9
8 10 12
If you have a MATLAB version earlier than 2016b (when implicit expansion was introduced, as demonstrated in Daan's answer) then you should use bsxfun.
v = [10 20 30 40 50]; % initial row vector
offsets = rand(3,1); % random values, add one per row (this should be a column vector)
output = bsxfun(#plus,offsets,v);
Result:
>> output =
10.643 20.643 30.643 40.643 50.643
10.704 20.704 30.704 40.704 50.704
10.393 20.393 30.393 40.393 50.393
This can be more easily understood with less random inputs!
v = [10 20 30 40 50];
offsets = [1; 2; 3];
output = bsxfun(#plus,offsets,v);
>> output =
11 21 31 41 51
12 22 32 42 52
13 23 33 43 53
Side note: to get an nx1 vector of random numbers between 0 and 2, use
offsets = rand(n,1)*2
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)
I am trying to extract a sequence of rows from a column of data in MATLAB. For example, my data looks like this in one column:
10
20
30
40
50
60
70
80
90
100
110
120
130
I want to select a sequence of rows and store these rows in a column vector A that looks like this after extracting the first 3 rows skipping 2 rows then selecting the next 3 rows and skipping 2 rows and selecting the next 3 to the end of the column.
Finally, the data should look like this with 9 rows and 1 column:
10
20
30
60
70
80
110
120
130
Thank you!
Let
x = [10 20 30 40 50 60 70 80 90 100 110 120 130].'; %'// data
m = 3; %// keep
n = 2; %// skip
Then
y = x(mod(0:end-1,m+n)<=m-1);
or equivalently
y = x(mod(0:numel(x)-1,m+n)<=m-1);
How this works: generate the sequence 0,1,2,... numel(x)-1. Each number corresponds to a position in x. To keep m and skip n cyclically, you apply mod(...,m+n) to that sequence. For example, for m=3, n=2 the result is sequence 0,1,2,3,4,0,1,2,.... You then select those numbers (that is, the corresponding entries of x) that are <=m-1. This results in the periodic pattern "keep, keep, keep, skip, skip".
To first skip and then keep (reverse from above): just reverse the inequality:
y = x(mod(0:end-1,m+n)>=m-1);
or
y = x(mod(0:numel(x)-1,m+n)>=m-1);
Try this, assuming a is your input column vector -
r_accept = 3; %// number of rows to accept
r_reject = 2; %// number of rows to reject
ind1 = bsxfun(#plus,1:r_accept+r_reject:numel(a),[0:r_accept-1]') %//'
out = a(ind1(ind1(:)<=numel(a))) %// desired output
I just figured out another way to compliment the nice solutions using find function.
If my data is:
x = [10; 20; 30; 40; 50; 60; 70; 80; 90; 100; 110; 120; 130]
and I want to extract a repeating sequence of rows then:
Develop an index of the repeating pattern or row sequence of keeps (3) and skips (2) rows. My index would be then:
index = [1:5 1:5 1:5]
or
index = 123451234512345
Then use the find function to logically index the "keep" sequence.
a = find(index<4)
which gives:
a = 1 2 3 6 7 8 11 12 13
then:
b = x(a)
produces
b = 10 20 30 60 70 80 110 120 130
I have the following matrix:
MatrixA =
1 10 50
23 45 76
71 81 91
1 2 3
4 5 6
78 89 91
2 3 4
I would like to run the var function for multiple ranges in each column. More specifically, I would like to calculate var for rows 1 through 3, 2 through 4, 3 through 5, etc. for each column. The output I would like would be:
1281.33 1260.33 430.33
1281.33 1564.33 2216.33
1566.33 2004.33 2496.33
... ... ...
I was thinking the syntax would be something along the lines of:
var(MatrixA([1 2 3]:[3 4 5],:))
but this (obviously) does not work.
I can do this using loops, but I was wondering if there is a solution to this that does not involve loops?
You can get rid of one loop using hankel function to create the ranges:
V = [];
for C = MatrixA,
V = [V, var(hankel(C(1:3),C(3:end))).'];
end
For instance if C contains the first column of MatrixA then
>> hankel(C(1:3),C(3:end))
ans =
1 23 71 1 4
23 71 1 4 78
71 1 4 78 2
and
>> var(hankel(C(1:3),C(3:end)))
ans =
1281.3 1281.3 1566.3 1902.3 1876
You could be a little creative with bsxfun and reshape to compute an index array and then compute the variances:
n = 3;
idx = bsxfun(#plus, 1:size(MatrixA, 1) - n + 1, (0:n - 1)');
B = reshape(var(reshape(MatrixA(idx, :), 3, [])), [], size(MatrixA, 2));
Quick MATLAB question.
What would be the best/most efficient way to select a certain number of elements, 'n' in windows of 'm'. In other words, I want to select the first 50 elements of a sequence, then elements 10-60, then elements 20-70 ect.
Right now, my sequence is in vector format(but this can easily be changed).
EDIT:
The sequences that I am dealing with are too long to be stored in my RAM. I need to be able to create the windows, and then call upon the window that I want to analyze/preform another command on.
Do you have enough RAM to store a 50-by-nWindow array in memory? In that case, you can generate your windows in one go, and then apply your processing on each column
%# idxMatrix has 1:50 in first col, 11:60 in second col etc
idxMatrix = bsxfun(#plus,(1:50)',0:10:length(yourVector)-50); %'#
%# reshapedData is a 50-by-numberOfWindows array
reshapedData = yourVector(idxMatrix);
%# now you can do processing on each column, e.g.
maximumOfEachWindow = max(reshapedData,[],1);
To complement Kerrek's answer: if you want to do it in a loop, you can use something like
n = 50
m = 10;
for i=1:m:length(v)
w = v(i:i+n);
% Do something with w
end
There's a slight issue with the description of your problem. You say that you want "to select the first 50 elements of a sequence, then elements 10-60..."; however, this would translate to selecting elements:
1-50
10-60
20-70
etc.
That first sequence should be 0-10 to fit the pattern which of course in MATLAB would not make sense since arrays use one-indexing. To address this, the algorithm below uses a variable called startIndex to indicate which element to start the sequence sampling from.
You could accomplish this in a vectorized way by constructing an index array. Create a vector consisting of the starting indices of each sequence. For reuse sake, I put the length of the sequence, the step size between sequence starts, and the start of the last sequence as variables. In the example you describe, the length of the sequence should be 50, the step size should be 10 and the start of the last sequence depends on the size of the input data and your needs.
>> startIndex = 10;
>> sequenceSize = 5;
>> finalSequenceStart = 20;
Create some sample data:
>> sampleData = randi(100, 1, 28)
sampleData =
Columns 1 through 18
8 53 10 82 82 73 15 66 52 98 65 81 46 44 83 9 14 18
Columns 19 through 28
40 84 81 7 40 53 42 66 63 30
Create a vector of the start indices of the sequences:
>> sequenceStart = startIndex:sequenceSize:finalSequenceStart
sequenceStart =
10 15 20
Create an array of indices to index into the data array:
>> index = cumsum(ones(sequenceSize, length(sequenceStart)))
index =
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
>> index = index + repmat(sequenceStart, sequenceSize, 1) - 1
index =
10 15 20
11 16 21
12 17 22
13 18 23
14 19 24
Finally, use this index array to reference the data array:
>> sampleData(index)
ans =
98 83 84
65 9 81
81 14 7
46 18 40
44 40 53
Use (start : step : end) indexing: v(1:1:50), v(10:1:60), etc. If the step is 1, you can omit it: v(1:50).
Consider the following vectorized code:
x = 1:100; %# an example sequence of numbers
nwind = 50; %# window size
noverlap = 40; %# number of overlapping elements
nx = length(x); %# length of sequence
ncol = fix((nx-noverlap)/(nwind-noverlap)); %# number of sliding windows
colindex = 1 + (0:(ncol-1))*(nwind-noverlap); %# starting index of each
%# indices to put sequence into columns with the proper offset
idx = bsxfun(#plus, (1:nwind)', colindex)-1; %'
%# apply the indices on the sequence
slidingWindows = x(idx)
The result (truncated for brevity):
slidingWindows =
1 11 21 31 41 51
2 12 22 32 42 52
3 13 23 33 43 53
...
48 58 68 78 88 98
49 59 69 79 89 99
50 60 70 80 90 100
In fact, the code was adapted from the now deprecated SPECGRAM function from the Signal Processing Toolbox (just do edit specgram.m to see the code).
I omitted parts that zero-pad the sequence in case the sliding windows do not evenly divide the entire sequence (for example x=1:105), but you can easily add them again if you need that functionality...