This question already has an answer here:
MatLab function that shifts points to the left or right from a max or minimum point
(1 answer)
Closed 6 years ago.
I have written a script that does the function:
eval(['VCathodicOh3(2,i) =' 'min(' 'data_' varnames{1} '(49000:51000,9));'])
In this, 'VCathodicOh3' is made by taking data from column 9 in different variables that are organized in arrays (they are 1:100000 rows by 10 columns).
I want to, instead of just finding the min, also add something to this function so that it takes the min, finds the point at which that min is at, and then move 4 points to the left of that point.
Ex:
min(data_var(49000:51000,9)) = -3.190
then lets say (50250, -3.190) is the point at which you find the min. I would like the script to move that point -4 (50246, y) and give me the new corresponding value.
You can use the second output of min to tell you the index of the minimum value. You could then decrement this value by 4 to shift it to the left.
a = [5 3 2 1 0]
[~, ind] = min(a);
newval = a(ind-4)
If you have a 2D matrix, you can convert the linear index ind to rows / columns and decrement that:
a = magic(10);
[~, ind] = min(a);
[row,col] = ind2sub(size(a), ind);
newval = a(row, col-4)
As a side note, I would really discourage using dynamic variable names like you are and use a more appropriate data structure such as a cell array or struct. The usage of eval can get out of hand very quickly as I'm sure you've noticed.
Related
This question already has answers here:
On shape-agnostic slicing of ndarrays
(2 answers)
Dynamic slicing of Matlab array
(1 answer)
Closed 4 years ago.
Imagine a function where you want to output a snippet in a user-specified dimension of a n-dimensional matrix
function result=a(x,dim)
window=1:10;
dim=3;
result=x(:,:,window);
end
How can I put window to the desired dimension? E.g. if dim=2; then result=x(:,window,:).
The way I can think of right now is to evaluate a string command that puts window in the correct position - or use a lot of if then else blocks. What's a better way of doing this?
You can do this using a cell array to define your indexes, following the examples here.
Specifically, if you have a matrix
x = ones(7,5,9);
You can define the indexes you want like:
% get all the indexes in all dimensions
all_indexes = {':', ':', ':'};
% get all indexes in dimensions 1 and 3, and just indices 1:4 in dimension 2
indexes_2 = {':', 1:4, ':'};
And then get those indexes from your matrix x like
a = x(all_indexes{:});
b = x(indexes_2{:});
So, you could write a function like
function result=extract_cells(x, dim, window)
% Create blank cell array {':', ':', ...} with entries ':' for each dimension
% Edit (c/o Cris Luengo): need to use ndims(x) to get the number of dimensions
num_dims = ndims(x)
dims = cell(1, num_dims);
dims(:) = {':'};
% Set the specified window of cells in the specified dimension
dims{dim} = window;
% Pick out the required cells
result=x(dims{:});
end
Which could return all the cells in the dimensions other than one specified, and in that direction would return the cells in the range given by window. So in the following code, a and b would be equivalent.
a = extract_cells(x, 2, 1:5);
b = x(:, 1:5, :)
This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 5 years ago.
I want to create all pattern combination which possible occur
For example, I have three ball and I want to pick 3 times. All possible is 27 events but I want to create all possible event in array like this
[1 1 1; 1 1 2; 1 1 3; 1 2 1 ;....]
Dose anyone can help me to write m-file in matlab program, please?
This can be done very easily with base conversion.
If the number of balls does not exceed 10
M = 3; % Number of balls. Must not exceed 10
N = 3; % Number of draws
result = dec2base(0:M^N-1, M)-'0'+1;
Note that dec2base ouputs chars, not numbers, and hence the -'0' part. Characters in arithmetic operations behave like their corresponding ASCII codes. So subtracting '0' transforms characters '0', '1', ..., '9' into the corresponding numbers.
With this approach M cannot exceed 10 because then dec2bin would output '0', '1', ..., '9', 'A', 'B' ... and the character arithmetic would not give the correct result for 'A', 'B', ... But this can be easily solved as follows.
For number of balls up to 36
M = 12; % Number of balls. Must not exceed 36
N = 2; % Number of draws
result = dec2base(0:M^N-1, M)-'0'+1; % same as before
result = result - ('A'-'9'-1)*(result>10); % correction
The new line simply corrects the results for 'A', 'B', ... by subtracting 'A'-'9'-1, to compensate the fact that '9' and 'A' do not have consecutive ASCII codes.
With this approach M cannot exceed 36 because of dec2base restrictions.
You can create the result like this for the specific case:
firstCol = [ones(9,1);2*ones(9,1);3*ones(9,1)];
secondCol = repeat([ones(3,1);2*ones(3,1);3*ones(3,1)],1,3);
thirdCol = repeat([1;2;3],1,9);
result = [firstCol secondCol thirdCol];
First, repeat 9 times 1,2, and 3 for first column. then repeat each of them 3 times for the second column and choose the third column once for each item. Indeed, this generate the all possible choices for each location.
How? If you suppose the first element is 1, you have 3 choice for the second place, and 3 choice for the third place. Hence, you have 9 possible option when the first place is 1. Also, fix the second place, and analyze this. You can generalize this for 2 and 3. The above code, try to generate possibilities based on this explanation.
In the above, ones generate a matrix which all elements are 1 with the specified size and repeat function repeats the specified matrix in the specified size and dimension. You can check the documentation to know more about them.
Hence, You can generalize it for n like the following:
n = 10;
result = zeros(3^n,3);
for idx = 1:n
result(:,idx) = repeat([ones(3^(n-idx),1);2*ones(3^(n-idx),1);3*ones(3^(n-idx),1)],1,3^(idx-1));
end
I'm trying to figure out how to have a function that will find a point that is x number of points away from my set min and max in an array in matlab.
Lets say that I do max(data(row 1:row 2,column)) and it gives me a point. I want to find the value that corresponds to 4 points to the left, and to the right of this value.
So lets say it tells me that the max of column 5 is 1.5 and it is located in row number 5
How would I make the function move it 4 rows/points backwards?
Example:
max(data_10MIN(49000:51000,9)
ans = -3.5226
data_10MIN(50251) = -3.5226, so I would just know that 4 points backwards is 50247, and moving 4 points forwards would be 50255 but how would I have a function do this for me? since max(data_10MIN(49000:51000,9) as a function does not give me the x and y values.
The max function also returns the (first occurence) index of the maximum value. You can simply offset that value and get to your desired 4 points to the left/right.
[maxvalue, idx] = max(data);
left4idx = max(1, idx - 4);
right4idx = min(numel(data), idx+4);
left4_value = data(left4idx);
right4_value = data(right4idx);
(It is a good idea to add a boundary check when adding/subtracting to an index, here I did that using the min/max functions.)
I need to calculate the frequency of each value in another vector in MATLAB.
I can use something like
for i=1:length(pdata)
gt(i)=length(find(pf_test(:,1)==pdata(i,1)));
end
But I prefer not to use loop because my dataset is quite large. Is there anything like histc (which is used to find the frequency of values in one vector) to find the frequency of one vector value in another vector?
If your values are only integers, you could do the following:
range = min(pf_test):max(pf_test);
count = histc(pf_test,range);
gt = count(ismember(range,a));
gt(~ismember(unique(a),b)) = 0;
If you can't guarantee that the values are integers, it's a bit more complicated. One possible method of it would be the following:
%restrict yourself to values that appear in the second vector
filter = ismember(pf_test,pdata);
% sort your first vector (ignore this if it is already sorted)
spf_test = sort(pf_test);
% Find the first and last occurrence of each element
[~,last] = unique(spf_test(filter));
[~,first] = unique(spf_test(filter),'first');
% Initialise gt
gt = zeros(length(pf_test));
% Fill gt
gt(filter) = (last-first)+1;
EDIT: Note that I may have got the vectors the wrong way around - if this doesn't work as expected, switch pf_test and pdata. It wasn't immediately clear to me which was which.
You mention histc. Why are you not using it (in its version with two input parameters)?
>> pdata = [1 1 3 2 3 1 4 4 5];
>> pf_test = 1:6;
>> histc(pdata,pf_test)
ans =
3 1 2 2 1 0
I have two vectors of values and I want to compare them statistically. For simplicity assume A = [2 3 5 10 15] and B = [2.5 3.1 4.8 10 18]. I want to compute the standard deviation, the root mean square error (RMSE), the mean, and present conveniently, maybe as histogram. Can you please help me how to do it so that I understand? I know question is probably simple, but I am new into this. Many thanks!
edited:
This is how I wanted to implement RMSE.
dt = 1;
for k=1:numel(A)
err(k)=sqrt(sum(A(1,1:k)-B(1,1:k))^2/k);
t(k) = dt*k;
end
However it gives me bigger values than I expect, since e.g. 3 and 3.1 differ only in 0.1.
This is how I calculate error between reference value of each cycle with corresponding estimated in that cycle.
Can you tell me, am I doing right, or what's wrong?
abs_err = A-B;
The way you are looping through the vectors is not element by element but rather by increasing the vector length, that is, you are comparing the following at each iteration:
A(1,1:k) B(1,1:k)
-------- --------
k=1 [2] [2.5]
=2 [2 3] [2.5 3.1]
=3 [2 3 5] [2.5 3.1 4.8]
....
At no point do you compare only 2 and 2.1!
Assuming A and B are vectors of identical length (and both are either column or row vectors), then you want functions std(A-B), mean(A-B), and if you look in matlab exchange, you will find a user-contributed rmse(A-B) but you can also compute the RMSE as sqrt(mean((A-B).^2)). As for displaying a histogram, try hist(A-B).
In your case:
dt = 1;
for k=1:numel(A)
stdab(k) = std(A(1,1:k)-B(1,1:k));
meanab(k) = mean(A(1,1:k)-B(1,1:k));
err(k)=sqrt(mean((A(1,1:k)-B(1,1:k)).^2));
t(k) = dt*k;
end
You can also include hist(A(1,1:k)-B(1,1:k)) in the loop if you want to compute histograms for every vector pair difference A(1,1:k)-B(1,1:k).