matlab store multiple outputs of function from loop in matrix - matlab

i am trying to save the output of the following function (it gives two outputs for every iteration of input 1, the rest remains the same).
The function creates a stress testing for an interbank market, testing for the effects (output is capital_losses and defaulted_banks) of default of every bank in the sample, i.e. input1 must go from 1:(length(input2), 4 in the code provided here, 300+ in the final code, so i need a loop
here a sample of one iteration with bank 3 defaulting
input1 = 3; % default_bank
input2=[100000;200000;300000;400000]; % capital levels in the function
input3 = ...
[70000, 15000, 24000, 52453;
23420, 24252, 10000, 35354;
98763, 45666, 96555, 05000;
09800, 54444, 04336, 67520]; % interbank loans in the function
input4 = 1;
input5 = .35;
input6 = 1;
% function calls on above inputs
[capital_losses defaulted_banks] = interbank_model( ...
input1, input2, input3, input4, input5, input6)
this is the standard output for one iteration with default_bank=3, but I need this for 300+, so a loop would be helpful...
capital_losses3 =
1.0e+05 *
0.5857
0.2598
3.0000
0.0609
defaulted_banks3 =
0
0
1
0
I would like to get the output for every defaulted bank, i.e. default_bank=1:4 to be displayed by the for loop as follows:
capital_losses_all =
1.0e+05 *
1.0000 0.2320 0.5857 0.5857
0.2867 2.0000 0.2598 0.2598
1.0716 0.4917 3.0000 3.0000
0.2816 0.6682 0.0609 0.0609
defaulted_banks_all =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
This was manually generated, but how do i store the values in matrices?
Thanks for your help. (I had a similar question before but the editing and commenting got very confusing so here's my improved cry for help... )
Chris

Very general answer (adapt for your need):
valuesThatChange = [1 3 5 4 2]; % different for each iteration in the loop
% values that don't change:
a=1;
b=2;
c=3;
N = numel(valuesThatChange);
% create storage for results:
results = zeros(4, N);
% loop N times
for ii=1:N
results(:,ii) = functionCall(valuesThatChange(ii), a, b, c); % returns a 4 element result
end
Now you have the result from your function for each loop in a 4xN matrix.

Related

How does the colon operator work in MATLAB?

As noted in this answer by Sam Roberts and this other answer by gnovice, MATLAB's colon operator (start:step:stop) creates a vector of values in a different way that linspace does. In particular, Sam Roberts states:
The colon operator adds increments to the starting point, and subtracts decrements from the end point to reach a middle point. In this way, it ensures that the output vector is as symmetric as possible.
However, offical documentation about this from The MathWorks has been deleted from their site.
If Sam's description is correct, wouldn't the errors in the step sizes be symmetric?
>> step = 1/3;
>> C = 0:step:5;
>> diff(C) - step
ans =
1.0e-15 *
Columns 1 through 10
0 0 0.0555 -0.0555 -0.0555 0.1665 -0.2776 0.6106 -0.2776 0.1665
Columns 11 through 15
0.1665 -0.2776 -0.2776 0.6106 -0.2776
Interesting things to note about the colon operator:
Its values depend on its length:
>> step = 1/3;
>> C = 0:step:5;
>> X = 0:step:3;
>> C(1:10) - X
ans =
1.0e-15 *
0 0 0 0 0 -0.2220 0 -0.4441 0.4441 0
It can generate repeated values if they are rounded:
>> E = 1-eps : eps/4 : 1+eps;
>> E-1
ans =
1.0e-15 *
-0.2220 -0.2220 -0.1110 0 0 0 0 0.2220 0.2220
There is a tolerance for the last value, if the step size creates a value just above the end, this end value is still used:
>> A = 0 : step : 5-2*eps(5)
A =
Columns 1 through 10
0 0.3333 0.6667 1.0000 1.3333 1.6667 2.0000 2.3333 2.6667 3.0000
Columns 11 through 16
3.3333 3.6667 4.0000 4.3333 4.6667 5.0000
>> A(end) == 5 - 2*eps(5)
ans =
logical
1
>> step*15 - 5
ans =
0
The deleted page referred to by Sam's answer is still archived by the Way Back Machine. Luckily, even the attached M-file colonop is there too. And it seems that this function still matches what MATLAB does (I'm on R2017a):
>> all(0:step:5 == colonop(0,step,5))
ans =
logical
1
>> all(-pi:pi/21:pi == colonop(-pi,pi/21,pi))
ans =
logical
1
I'll replicate here what the function does for the general case (there are some shortcuts for generating integer vectors and handling special cases). I'm replacing the function's variable names with more meaningful ones. The inputs are start, step and stop.
First it computes how many steps there are in between start and stop. If the last step exceeds stop by more than a tolerance, it is not taken:
n = round((stop-start)/step);
tol = 2.0*eps*max(abs(start),abs(stop));
sig = sign(step);
if sig*(start+n*step - stop) > tol
n = n - 1;
end
This explains the last observation mentioned in the question.
Next, it computes the value of the last element, and makes sure that it does not exceed the stop value, even if it allowed to go past it in the previous computation.
last = start + n*step;
if sig*(last-stop) > -tol
last = stop;
end
This is why the lasat value in the vector A in the question actually has the stop value as the last value.
Next, it computes the output array in two parts, as advertised: the left and right halves of the array are filled independently:
out = zeros(1,n+1);
k = 0:floor(n/2);
out(1+k) = start + k*step;
out(n+1-k) = last - k*step;
Note that they are not filled by incrementing, but by computing an integer array and multiplying it by the step size, just like linspace does. This exaplains the observation about array E in the question. The difference is that the right half of the array is filled by subtracting those values from the last value.
As a final step, for odd-sized arrays, the middle value is computed separately to ensure it lies exactly half-way the two end points:
if mod(n,2) == 0
out(n/2+1) = (start+last)/2;
end
The full function colonop is copied at the bottom.
Note that filling the left and right side of the array separately does not mean that the errors in step sizes should be perfectly symmetric. These errors are given by roundoff errors. But it does make a difference where the stop point is not reached exactly by the step size, as in the case of array A in the question. In this case, the slightly shorter step size is taken in the middle of the array, rather than at the end:
>> step=1/3;
>> A = 0 : step : 5-2*eps(5);
>> A/step-(0:15)
ans =
1.0e-14 *
Columns 1 through 10
0 0 0 0 0 0 0 -0.0888 -0.4441 -0.5329
Columns 11 through 16
-0.3553 -0.3553 -0.5329 -0.5329 -0.3553 -0.5329
But even in the case where the stop point is reached exactly, some additional error accumulates in the middle. Take for example the array C in the question. This error accumulation does not happen with linspace:
C = 0:1/3:5;
lims = eps(C);
subplot(2,1,1)
plot(diff(C)-1/3,'o-')
hold on
plot(lims,'k:')
plot(-lims,'k:')
plot([1,15],[0,0],'k:')
ylabel('error')
title('0:1/3:5')
L = linspace(0,5,16);
subplot(2,1,2)
plot(diff(L)-1/3,'x-')
hold on
plot(lims,'k:')
plot(-lims,'k:')
plot([1,15],[0,0],'k:')
title('linspace(0,5,16)')
ylabel('error')
colonop:
function out = colonop(start,step,stop)
% COLONOP Demonstrate how the built-in a:d:b is constructed.
%
% v = colonop(a,b) constructs v = a:1:b.
% v = colonop(a,d,b) constructs v = a:d:b.
%
% v = a:d:b is not constructed using repeated addition. If the
% textual representation of d in the source code cannot be
% exactly represented in binary floating point, then repeated
% addition will appear to have accumlated roundoff error. In
% some cases, d may be so small that the floating point number
% nearest a+d is actually a. Here are two imporant examples.
%
% v = 1-eps : eps/4 : 1+eps is the nine floating point numbers
% closest to v = 1 + (-4:1:4)*eps/4. Since the spacing of the
% floating point numbers between 1-eps and 1 is eps/2 and the
% spacing between 1 and 1+eps is eps,
% v = [1-eps 1-eps 1-eps/2 1 1 1 1 1+eps 1+eps].
%
% Even though 0.01 is not exactly represented in binary,
% v = -1 : 0.01 : 1 consists of 201 floating points numbers
% centered symmetrically about zero.
%
% Ideally, in exact arithmetic, for b > a and d > 0,
% v = a:d:b should be the vector of length n+1 generated by
% v = a + (0:n)*d where n = floor((b-a)/d).
% In floating point arithmetic, the delicate computatations
% are the value of n, the value of the right hand end point,
% c = a+n*d, and symmetry about the mid-point.
if nargin < 3
stop = step;
step = 1;
end
tol = 2.0*eps*max(abs(start),abs(stop));
sig = sign(step);
% Exceptional cases.
if ~isfinite(start) || ~isfinite(step) || ~isfinite(stop)
out = NaN;
return
elseif step == 0 || start < stop && step < 0 || stop < start && step > 0
% Result is empty.
out = zeros(1,0);
return
end
% n = number of intervals = length(v) - 1.
if start == floor(start) && step == 1
% Consecutive integers.
n = floor(stop) - start;
elseif start == floor(start) && step == floor(step)
% Integers with spacing > 1.
q = floor(start/step);
r = start - q*step;
n = floor((stop-r)/step) - q;
else
% General case.
n = round((stop-start)/step);
if sig*(start+n*step - stop) > tol
n = n - 1;
end
end
% last = right hand end point.
last = start + n*step;
if sig*(last-stop) > -tol
last = stop;
end
% out should be symmetric about the mid-point.
out = zeros(1,n+1);
k = 0:floor(n/2);
out(1+k) = start + k*step;
out(n+1-k) = last - k*step;
if mod(n,2) == 0
out(n/2+1) = (start+last)/2;
end

optimization of a linear system of inequalites

We are given four points, assumed to be ordered:
A = sort(randn(1,4))
I want to find the maximum possible number x in the interval 0<x<1 such that
A(1)<x<A(2) or A(3)<x<A(4)
Some examples:
A = [-1.4924 0.3004 1.6630 2.1204], x = 0.3004
A = [-0.4754 0.1353 0.6552 1.3873]; x = 1.0000
A = [-1.0213 -0.4521 -0.0905 0.1000]; x = 0.1000
A = [-1.8258 -0.5790 -0.4568 -0.1950]; x = 0.0000
A = [ 1.5000 2.0000 2.5000 3.0000]; x = 1.0000
Can you suggest a compact code to do this job, without having to list all the possible scenarios using if statements?
Having tried to do this with no if statements, I found that the readability of the code was greatly diminished. Note that there is only a single if statement in the code below while several other if statements could be substituted for the logical comparisons.
All of your tests pass and the code remains very concise (9 lines without the comments and loop over all of the tests).
A = [[-1.4924 0.3004 1.6630 2.1204];
[-0.4754 0.1353 0.6552 1.3873];
[-1.0213 -0.4521 -0.0905 0.1000];
[-1.8258 -0.5790 -0.4568 -0.1950];
[ 1.5000 2.0000 2.5000 3.0000]];
for i = 1:size(A,1)
% Reshape A so that each set of 2 entries are compared
Atmp = reshape(A(i,:),2,2);
% Find any valid entries
Valid = Atmp > 0 & Atmp < 1;
Ind_Valid = find(Valid == 1);
if (~isempty(Ind_Valid))
% If there are valid entries, return:
% max(A(ind),0) if the entry is the 1st of the pair
% max(A(ind),1) if the entry is the 2nd of the pair
max_Ind = max(Ind_Valid);
x = max(Atmp(max_Ind),mod(max_Ind,2))
else
% If there are no valid entries, return:
% 0 if max A < 0
% 1 if max A > 1
x = max(Atmp(:)) > 0
end
end
Output:
x =
0.3004
x =
1
x =
0.1000
x =
0
x =
1

Which one should I use for dimension reduction with PCA in MATLAB, pcacov or eigs?

I'm trying to reduce my training set dimension from 1296*70000 to 128*70000.
I wrote Below code:
A=DicH;
[M N]=size(A);
mu=mean(A,2);%mean of columns
Phi=zeros(M,N);
C=zeros(M,M);
for j=1:N
Phi(:,j)=A(:,j)-mu;
c=Phi(:,j)*(Phi(:,j))';
C=C+c;
end
C=C/N;%Covariance Dictionary
[V,landa] = eigs(C,128);%Eigen Vectors & Eigen Values
E=V'*Phi;%Reduced Dic
%*******************Using Pcacov*****************
%S=zeros(M,1);
%[U,landa] = pcacov(C);%Eigen Vectors & Eigen Values
% for k=1:128;
% S=V(:,k)+S;
% U(:,k)=S;
% end
%E=U'*Phi;%Reduced Dic
I get two different answers! Which one should I use "eigs" or "pcacov"??
You should take advantage of the built-in functions in Matlab, and use the pca function directly, or even the cov function if you want to compare eigs to pcaconv.
Now to answer your question, both return the same eigenvectors but not in the same order. See the following example:
>> load hald
>> covx = cov(ingredients);
>> [COEFF,latent] = pcacov(covx)
COEFF =
-0.0678 -0.6460 0.5673 0.5062
-0.6785 -0.0200 -0.5440 0.4933
0.0290 0.7553 0.4036 0.5156
0.7309 -0.1085 -0.4684 0.4844
latent =
517.7969
67.4964
12.4054
0.2372
>> [V, D] = eigs(covx)
V =
0.5062 0.5673 0.6460 -0.0678
0.4933 -0.5440 0.0200 -0.6785
0.5156 0.4036 -0.7553 0.0290
0.4844 -0.4684 0.1085 0.7309
D =
0.2372 0 0 0
0 12.4054 0 0
0 0 67.4964 0
0 0 0 517.7969
>>
In your code, you overwrite the result of pcavconv in the commented-out section with a transformation of the result of eigs so it is not clear what your are comparing at this point. When using pcacov, you just need to extract the 128 first columns of U.

MATLAB: Get mean of first n values sorted by first column

I have a cell array of 21128x9 cells sorted by column 1 e.g.(massively simplified):
A=[1 3; 1 5; 1 3; 2 1; 2 2; 2 3; 3 5; 3 5]
A =
1 3
1 5
1 3
2 1
2 2
2 3
3 5
3 5
where some values in column 1 are repeated more than others.
what I want to do is get the mean of the second column for each value of the first column, but only for the first two values.
i.e.
ans= 1 4
2 1.5
3 5
I'm attempting to use this basic function
means = accumarray(A(:,1) ,A(:,2),[],#mean);
but i'm not sure how to get it to only apply to the first two values of each group. I assume I'll need a for loop, something along the lines of:
for ;
means = accumarray(A(:,1) ,A(:,2),[],#mean);
end
What I don't know what what the for needs to be.
accumarray passes a vector into the anonymous function, so you can just do, e.g.:
A = [1 3; 1 5; 1 3; 2 1; 2 2; 2 3; 3 5; 3 5];
maxAvgs = 3;
accumarray(A(:, 1), A(:, 2), [], #(x)mean(x(1:min(length(x), maxAvgs))))
ans =
3.6667
2.0000
5.0000
maxAvgs = 2;
accumarray(A(:, 1), A(:, 2), [], #(x)mean(x(1:min(length(x), maxAvgs))))
ans =
4.0000
1.5000
5.0000
Whenever you're unsure in such situations involving anonymous functions, you can write your anonymous function as #(varargin)disp(varargin); this will display the input arguments. In this case this doesn't work because accumarray requires that the function you pass it returns an argument. However, you can still set this as the anonymous function and run your code from a script; set a breakpoint on the line in the editor window, making sure to select 'Anonymous function' for the position of the breakpoint.
Edit:
In my actual data, some have 60 values, some have 120, some have 180.
As an addition, is it possible to then run the mean function on the
next lot of values (i.e. value 61-120, then 121-180)?
To do what you you ask in the comment I suggest creating a function splitMean and passing this to accumarray:
function y = splitMean(x, n)
% If length of x doesn't divide by n, the extra elements will be averaged
% separately
extra = mod(length(x), n);
M = length(x)-extra;
meanData = reshape(x(1:M), M / n, n);
extraMean = [];
if extra > 0, extraMean = mean(x(M+1:end)); end
if ~isempty(meanData)
y = {[mean(meanData).'; extraMean]};
else
y = {extraMean};
end
Then,
maxAvgs = 2;
cell2mat(accumarray(A(:, 1), A(:, 2), [], #(x)splitMean(x, maxAvgs)))
ans =
4.0000
3.0000
1.5000
3.0000
5.0000
%%% Without the cell2mat:
ans =
[2x1 double]
[2x1 double]
[ 5]
This way, you get all the sets of means each group can provide all at once. Note the cell2mat. If you want them split up by group index, then remove this and you will get a cell array.

MATLAB: How to calculate (on) Submatrices without a loop

I want to split a matrix columnwise into 3 segments and do a calculation on it (mean()). Is there a way to get this without a for-loop, as I did in this provided sample?
M = [2 4 9; 50 50 200; 30 0 0];
M = [M 10*M]
N = length(M);
seg = 3 % split in lets say 3 parts
segLen = round(N/seg)
segBeg = (((1:seg)-1) * segLen)+1 % start indices
segEnd = segBeg + segLen -1 % end indices
for i = 1: length(segBeg)
mean(M(:,segBeg(i):segEnd(i)),2)
end
Thank you!
Think outside the box: use the 3rd dimension:
r=reshape(M,size(M,1),segLen,[])
squeeze(mean(r,2))
The first line produces a 3d array with the first matrix at r(:,:,1), the second at r(:,:,2), ... (use M(:,1:seg*segLen) instread of M if the number of columns is not divisible by segLen).
mean(r,2) produces a nrows-by-1-by-seg array, squeeze makes a nrows-by-seg matrix out of it again.
You can use arrayfun together with cell2mat
result = cell2mat(arrayfun(#(x,y) mean(M(:,x:y),2), segBeg, segEnd,...
'UniformOutput', false))
This results in
result =
1.0e+03 *
0.0030 0.0145 0.0650
0.0500 0.3500 1.2500
0.0150 0.1500 0
where each column represents the mean across one submatrix.
Another solution using blockproc (like suggested by #DennisJaheruddin in the comments) could look like this
myFun = #(x) mean(x.data,2);
result2 = blockproc(M, [N, segLen], myFun)
This also results in
result2 =
1.0e+03 *
0.0030 0.0145 0.0650
0.0500 0.3500 1.2500
0.0150 0.1500 0
Note that blockproc can take advantage of parallel processing if the flag 'UseParallel' is set to true, i.e., result2 = blockproc(M, [N, segLen], myFun, 'UseParallel', true)
You can do for your example case
mean1 = mean(M(:,1:segLen))
mean2 = mean(M(:,segLen+1:N-segLen-1))
mean3 = mean(M(:,N-segLen:end))