Finding the difference between columns in matrix without loops - matlab

I have the results from an iterative process, where the results from each iteration is placed beside eachother, like this:
res =
43.7826 38.8460 38.6889 38.6912 38.6915
107.0735 98.5577 98.1212 98.1170 98.1175
-134.6218 -131.6938 -131.5378 -131.5352 -131.5352
-105.9498 -103.1403 -102.9195 -102.9139 -102.9139
What I want to do is create one matrix that shows the difference between each column, and one matrix that shows the percentage change from one column to the next.
This is obviously simple to do using loops, but is there a clever way to do this without loops (maybe using some built-in Matlab functions)?
Thanks.

The command diff(...) performes the difference:
diff_res = diff(res,1,2)
in this case the difference of the first order in the second dimension (columns).
After you can compute the percentage:
per_res = diff_res(:,1:4)./res(:,1:4).*100

Related

Matlab Parse Error with a simple parenthesis?

I'm trying to finish a program and for some reason, the matrix I loaded into Matlab is messing with the ability to select the rows inside it. I'm trying to select all the rows in the matrix and see which values match the criteria for a Live setting. However I can select specific values/sections of the matrix in the command window without issue. Why is this happening? Any ideas?
It appears to only happen when in a for loop, I can do it just fine when it's on its own.
The syntax is: for x = start:stop. I think you are trying to do a for to the whole "A" matrix. You can split "A", according to its format (e.g. if is a table split in two variables).
bye
Richardd is right on; you're trying to iterate on a matrix, no good.
If I read you right, you're trying to run through your A matrix one column at a time, and see all the rows in that column? Assuming that is correct...
Your A matrix is 14x3, so you should go through your for loop 3 times, which is the size of your column dimension. Luckily, there is a function that MATLAB gives you to do just that. Try:
for iColumn = 1:size(A,2)
...
end
The size function returns the size of your array in a vector of [rows, columns, depth...] - it will go as many dimensions as your array. Calling size(A,2) returns only the size of your array in the column dimension. Now the for loop is iterating on columns.

Create a loop using part of variable name in MATLAB

I am a beginner in Matlab and have not been able to find an answer to my question so far. Your help will definitely be very much appreciated.
I have 70 matrices (100x100), named SUBJ_1, SUBJ_2 etc. I would like to create a loop so that I would calculate some metrics (i.e. max and min values) for each matrix, and save the output in a 70x2 result matrix (where each row would correspond to the consecutively named SUBJ_ matrix).
I am struggling with both stages - how to use the names of individual variables in a 'for' loop and how to properly save individual outputs in a combined array.
Many thanks and all the best!
Don't use such variable names, create a big cell array named SUBJ and put each Matrix in it.
r=zeros(numel(SUBJ),2)
for idx=1:numel(SUBJ)
r(idx,1)=min(min(SUBJ{idx}))
r(idx,2)=max(max(SUBJ{idx}))
end
min and max are called twice because first call creates maximum among rows, second call among columns.
Even though this is in principle possible in Matlab, I would not recommend it: too slow and cumbersome to implement.
You could instead use a 3-D matrix (100x100x70) SUBJ which would contain all the SUBJ_1 etc. in one matrix. This would allow you to calculate min/max etc. with just one line of code. Matlab will take care of the loops internally:
OUTPUT(:,1) = min(min(SUBJ,[],1)[],2);
OUTPUT(:,2) = max(max(SUBJ,[],1)[],2);
Like this, OUTPUT(1,1) contains min(min(SUBJ(:,:,1))) and so on...
As to how to use the names of individual variables in a 'for' loop, here gives an example:
SUBJ = [];
for idx = 1:70
term = eval(['SUBJ_',num2str(idx)]);
SUBJ = [SUBJ; max(max(term)),min(min(term))];
end

Detect signal jumps relative to local activity

In Matlab, is it possible to measure local variation of a signal across an entire signal without using for loops? I.e., can I implement the following:
window_length = <something>
for n = 1:(length_of_signal - window_length/2)
global_variance(n) = var(my_signal(1:window_length))
end
in a vectorized format?
If you have the image processing toolbox, you can use STDFILT:
global_std = stdfilt(my_signal(:),ones(window_length,1));
% square to get the variance
global_variance = global_std.^2;
You could create a 2D array where each row is shifted one w.r.t. to the row above, and with the number of rows equal to the window width; then computing the variance is trivial. This doesn't require any toolboxes. Not sure if it's much faster than the for loop though:
longSignal = repmat(mySignal(:), [1 window_length+1]);
longSignal = reshape(longSignal(1:((length_of_signal+1)*window_length)), [length_of_signal+1, window_length])';
global_variance = sum(longSignal.*longSignal, 2);
global_variance = global_variance(1:length_of_signal-window_length));
Note that the second column is shifted down by one relative to the one above - this means that when we have the blocks of data on which we want to operate in rows, so I take the transpose. After that, the sum operator will sum over the first dimension, which gives you a row vector with the results you want. However, there is a bit of wrapping of data going on, so we have to limit to the number of "good" values.
I don't have matlab handy right now (I'm at home), so I was unable to test the above - but I think the general idea should work. It's vectorized - I can't guarantee it's fast...
Check the "moving window standard deviation" function at Matlab Central. Your code would be:
movingstd(my_signal, window_length, 'forward').^2
There's also moving variance code, but it seems to be broken.
The idea is to use filter function.

Vectorize matlab code to map nearest values in two arrays

I have two lists of timestamps and I'm trying to create a map between them that uses the imu_ts as the true time and tries to find the nearest vicon_ts value to it. The output is a 3xd matrix where the first row is the imu_ts index, the third row is the unix time at that index, and the second row is the index of the closest vicon_ts value above the timestamp in the same column.
Here's my code so far and it works, but it's really slow. I'm not sure how to vectorize it.
function tmap = sync_times(imu_ts, vicon_ts)
tstart = max(vicon_ts(1), imu_ts(1));
tstop = min(vicon_ts(end), imu_ts(end));
%trim imu data to
tmap(1,:) = find(imu_ts >= tstart & imu_ts <= tstop);
tmap(3,:) = imu_ts(tmap(1,:));%Use imu_ts as ground truth
%Find nearest indecies in vicon data and map
vic_t = 1;
for i = 1:size(tmap,2)
%
while(vicon_ts(vic_t) < tmap(3,i))
vic_t = vic_t + 1;
end
tmap(2,i) = vic_t;
end
The timestamps are already sorted in ascending order, so this is essentially an O(n) operation but because it's looped it runs slowly. Any vectorized ways to do the same thing?
Edit
It appears to be running faster than I expected or first measured, so this is no longer a critical issue. But I would be interested to see if there are any good solutions to this problem.
Have a look at knnsearch in MATLAB. Use cityblock distance and also put an additional constraint that the data point in vicon_ts should be less than its neighbour in imu_ts. If it is not then take the next index. This is required because cityblock takes absolute distance. Another option (and preferred) is to write your custom distance function.
I believe that your current method is sound, and I would not try and vectorize any further. Vectorization can actually be harmful when you are trying to optimize some inner loops, especially when you know more about the context of your data (e.g. it is sorted) than the Mathworks engineers can know.
Things that I typically look for when I need to optimize some piece of code liek this are:
All arrays are pre-allocated (this is the biggest driver of performance)
Fast inner loops use simple code (Matlab does pretty effective JIT on basic commands, but must interpret others.)
Take advantage of any special data features that you have, e.g. use sort appropriate algorithms and early exit conditions from some loops.
You're already doing all this. I recommend no change.
A good start might be to get rid of the while, try something like:
for i = 1:size(tmap,2)
C = max(0,tmap(3,:)-vicon_ts(i));
tmap(2,i) = find(C==min(C));
end

What's the best way to iterate through columns of a matrix?

I want to apply a function to all columns in a matrix with MATLAB. For example, I'd like to be able to call smooth on every column of a matrix, instead of having smooth treat the matrix as a vector (which is the default behaviour if you call smooth(matrix)).
I'm sure there must be a more idiomatic way to do this, but I can't find it, so I've defined a map_column function:
function result = map_column(m, func)
result = m;
for col = 1:size(m,2)
result(:,col) = func(m(:,col));
end
end
which I can call with:
smoothed = map_column(input, #(c) (smooth(c, 9)));
Is there anything wrong with this code? How could I improve it?
The MATLAB "for" statement actually loops over the columns of whatever's supplied - normally, this just results in a sequence of scalars since the vector passed into for (as in your example above) is a row vector. This means that you can rewrite the above code like this:
function result = map_column(m, func)
result = [];
for m_col = m
result = horzcat(result, func(m_col));
end
If func does not return a column vector, then you can add something like
f = func(m_col);
result = horzcat(result, f(:));
to force it into a column.
Your solution is fine.
Note that horizcat exacts a substantial performance penalty for large matrices. It makes the code be O(N^2) instead of O(N). For a 100x10,000 matrix, your implementation takes 2.6s on my machine, the horizcat one takes 64.5s. For a 100x5000 matrix, the horizcat implementation takes 15.7s.
If you wanted, you could generalize your function a little and make it be able to iterate over the final dimension or even over arbitrary dimensions (not just columns).
Maybe you could always transform the matrix with the ' operator and then transform the result back.
smoothed = smooth(input', 9)';
That at least works with the fft function.
A way to cause an implicit loop across the columns of a matrix is to use cellfun. That is, you must first convert the matrix to a cell array, each cell will hold one column. Then call cellfun. For example:
A = randn(10,5);
See that here I've computed the standard deviation for each column.
cellfun(#std,mat2cell(A,size(A,1),ones(1,size(A,2))))
ans =
0.78681 1.1473 0.89789 0.66635 1.3482
Of course, many functions in MATLAB are already set up to work on rows or columns of an array as the user indicates. This is true of std of course, but this is a convenient way to test that cellfun worked successfully.
std(A,[],1)
ans =
0.78681 1.1473 0.89789 0.66635 1.3482
Don't forget to preallocate the result matrix if you are dealing with large matrices. Otherwise your CPU will spend lots of cycles repeatedly re-allocating the matrix every time it adds a new row/column.
If this is a common use-case for your function, it would perhaps be a good idea to make the function iterate through the columns automatically if the input is not a vector.
This doesn't exactly solve your problem but it would simplify the functions' usage. In that case, the output should be a matrix, too.
You can also transform the matrix to one long column by using m(:,:) = m(:). However, it depends on your function if this would make sense.