Calculating and printing uncertainties of fits after the "normal" display of fit-parameters
3 views (last 30 days)
Show older comments
Claudius Simon Appel
on 3 Sep 2020
Commented: Claudius Simon Appel
on 6 Sep 2020
Hello,
I am storing multiple fits in a cell array "fits". Currently I am just using celldisp to obtain f.e. the following:
>> celldisp(fit)
fit{1} =
Linear model Poly1:
y(x) = p1*x + p2
Coefficients (with 95% confidence bounds):
p1 = 0.00226 (0.002015, 0.002506)
p2 = 0.004049 (0.003472, 0.004627)
fit{2} =
Linear model Poly1:
y(x) = p1*x + p2
Coefficients (with 95% confidence bounds):
p1 = 0.004422 (0.004302, 0.004542)
p2 = 0.003982 (0.0037, 0.004264)
Now I am trying to print the following instead to the command window:
Fit{1} = % What I would like to print instead
Linear model Poly1:
y(x) = p1*x + p2
Coefficients (with 95% confidence bounds):
p1 = 0.00226 (0.002015, 0.002506) +- 0.000246 % (values obtained by calculating upper bound - value outside brackets)
p2 = 0.004049 (0.003472, 0.004627) +- 0.000578 % (i.e 0.004627-0.004049=0.000578 and so on)
Fit{2} =
Linear model Poly1:
y(x) = p1*x + p2
Coefficients (with 95% confidence bounds):
p1 = 0.004422 (0.004302, 0.004542) +- 0.00012
p2 = 0.003982 (0.0037, 0.004264) +- 0.000282
My first idea was to then extract the values from the different fits:
for j=1:1:numel(fit)
% Extract All Data:
Coeffvalues{j}=coeffvalues(fit{j}); % get the p1 and p2 values
Confintvalues{j}=confint(fit{j}); % get the corresponding confidence bounds
end
for j=1:1:numel(Coeffvalues)
Confintcalcvals=Confintvalues{j}(2,:)';
for k=1:1:length(Coeffvalues{1,1})
Difference(j,k)= Confintcalcvals(k)-Coeffvalues{1,j}(k); % Row j contains the diffs for fit j, position k is for the respective value
end
end
Difference % contains the differences to be inserted into the displayed fit messages, one row per fit
Now I should have all data I need in nice sorted columns, one per parameter.
My problem now is that I have no clue whatsoever how to emulate the message given when fits are displayed, and then add these values at the correct positions. For instance, I couldn't figure out how to access the string of the cfit-object containing the fit equation, since I assume I would have to rebuild the entire message string by string, which I only now realise could become a pain in the ass if we have a differing number of Coefficients. No clue how to do that automatically aside from coding it for the first X possibilities and just hope you won't encounter a fit with more than X parameters. I assume this is not the best way.
This gets worse since I have to make the entire process loopable so it repeats for whatever number of fits I end up having.
Thank you & stay save.
C.A.
0 Comments
Accepted Answer
Uday Pradhan
on 6 Sep 2020
Hi Claudius,
I would suggest to create a custom display function for this task. I have created a function that I describe below. You may refer and use this or create your own if this gives you a better and/or efficient idea.
function celldispForFits(someCell) %someCell is the cell of fits
s = inputname(1);
for i = 1:numel(someCell)
modelDetails=evalc('disp(someCell{i})'); %get the display message as a char array
strMessage = editMessage(modelDetails,someCell{i}); %get the updated message
fprintf('\n');
disp([s subs(i,size(someCell)) ' =']) %taken this from the original celldisp function
fprintf('\n');
disp(strMessage);
end
function s = subs(i,siz)
%SUBS Display subscripts
if length(siz)==2 && any(any(siz==1))
v = cell(1,1);
else
v = cell(size(siz));
end
[v{1:end}] = ind2sub(siz,i);
s = ['{' int2str(v{1})];
for i=2:length(v)
s = [s ',' int2str(v{i})];
end
s = [s '}'];
end
end
In a separate file, I created the function "editMessage" which edits the original message and applies the changes that you have mentioned in your question.
function s = editMessage(modelDetails,f) %f = fit Object, modelDetails the original displayed message
displayStr = split(modelDetails,newline); %split the message with respect to newline delimiter
displayStr = displayStr(~cellfun('isempty',displayStr)); %remove the empty arrays that may occur
var = 4; %line number in the message from which editing is required
for i = 1 : numel(displayStr) %loop through each line in the message
k = 1;
while displayStr{i}(k) == ' '
k = k + 1; %for each line search for the first word
end
str = "";
while displayStr{i}(k) ~= ' '
str = str + displayStr{i}(k);
k = k + 1; %get the first word in the line
end
if str == "Coefficients"
var = i + 1; %if the word is Coefficients store the next line number
break; %this is the line number from which we need to start editing the message
end
end
coeffVals = coeffvalues(f);
confidenceInt = confint(f);
toAdd = [""]; %new edits to be inserted
for i = 1:numel(coeffVals)
toAdd(i) = num2str(confidenceInt(2,i) - coeffVals(i));
%upper bound - value
end
idx = 1;
for i = var : numel(displayStr) %from the line number in var till the end
displayStr{i} = displayStr{i} + " +- " + toAdd(idx); %make the required edits
idx = idx + 1;
end
finalStr = "";
for i = 1:numel(displayStr)
finalStr = finalStr + displayStr(i) + newline; %create the new message to display
end
s = finalStr;
end
These functions make the assumption that the lines that need editing occur after the line "Coefficients (with ...) :" and are not context - aware. I have tested these on some fits that I created and seems to work well on those examples. Hope this will help you.
3 Comments
Uday Pradhan
on 6 Sep 2020
Edited: Uday Pradhan
on 6 Sep 2020
You can use "precision" argument of the "num2str" function to display numbers in the exponential function. For example you may use :
toAdd(i) = num2str(confidenceInt(2,i) - coeffVals(i),'%10.2e');
%this stores each value in exponential format with two decimal places
A caveat to this approach is that every number will be displayed in the exponential format. You may use an "if" statement to deal with only larger numbers to be displayed in this form.
if confidenceInt(2,i) - coeffVals(i) > 1e5
toAdd(i) = num2str(confidenceInt(2,i) - coeffVals(i),'%10.2e');
else
toAdd(i) = num2str(confidenceInt(2,i) - coeffVals(i));
end
This is extra work but that's all I can think of right now. You are free to make changes and include my code in yours but do accept my answer so that other community members may benefit from it when they come across similar doubts.
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!