How to generalized the formula in matlab - matlab

I want to vary the condition for the n-th vector to cover a range of i-values (something like i=2:27).
N=51;
num =2;
W = 3;
i = 2;
string1 = '[';
for n = num:-1:1
string1 = [ string1 'a' num2str(n) ' '];
end
string1 = [ string1 '] = ndgrid(1:W);'];
string2 = 'ind = find(';
for n = 2:num
string2 = [ string2 'a' num2str(n) '>=a' num2str(n-1) '&' ];
end
for n = 1:num
string2 = [ string2 'a' num2str(n) '+'];
end
string2 = [ string2(1:end-1) '==i);' ];
string3 = 'C = [ ';
for n = 1:num
string3 = [ string3 'a' num2str(n) '(ind) ' ];
end
string3 = [ string3 ']' ];
eval(string1);
eval(string2);
eval(string3);
Unfortunately, I have difficulties in understanding how this is a generalization of my initial construct.
Ultimately, I need the matrix p2 (which selects combinations of a1, a2 to an) in a probability analysis.

Here's how you can do it:
N = 5; % number of columns, this was your a1 ... a5
W=3; % unchanged to first example in question
i=6; % unchanged to first example in question
% the following will create a matrix with N-1 columns
% because the last column is determined by the sum of the columns before it
% the a1 .. an-1 columns contains all possible permutations of 1:W
% (this code can be found on the internet)
for ii=1:N-1
dset{1,ii}=1:W;
end
n=numel(dset);
a=cell(n,1);
[a{1:n}]=ndgrid(dset{end:-1:1});
a=reshape(cat(n+1,a{:}),[],n);
a=a(:,end:-1:1);
% next, we sort the rows ascending
% because for you, 1-1-2 is the same as 1-2-1
% and after sorting, we pick the unique rows
a = unique(sort(a,2),'rows');
% next, we populate the last column
% and select those that match your criterion
% in a matrix p2n
p2n = [];
for ii=1:size(a,1)
a(ii,N) = i - sum(a(ii,1:N-1));
if(a(ii,N-1) <= a(ii,N) && a(ii,N)<=W)
p2n=[p2n;a(ii,:)];
end
end
See the comments in the code for explanations.
EDIT
If you want to vary N, i and W, use for-loops for example:
for N=2:4
for i=2:27
for W=3:7
% post code starting at line 11 here
% DO NOT DECLARE N, W, i inside the loops again
% Also, introduce a cell to store all `p2n` matrices:
% place this inside the loop but below the code given above
P2n{N,i,W} = p2n;
end
end
end

Related

Return and call multiple value from function

I am trying to return all values of for loop from my function and also I need to call them outside of the function.But i only get last row of the for loop, I also need previous result of for loop.
Here is my code
i=input('Enter a start row: ');
j=input('Enter a end row: ');
c=input('Enter classifier variable column number:')
search= importfiledataset('search-queries-features.csv',i,j);
[n,p]=size(search);
if j>n
disp('Please enter a smaller number!');
end
[D1,Eps1]=findD(i,j,c,search);
disp(D1);
disp(n1);
function [D1,Eps1] = findD(i,j,c,search) %Find D vlaues with for loop for each classification value
for numOfClassifier = 1 : 100
a = search(search(:,c)==numOfClassifier,:) ;
q1 = a(all(~isnan(a),2),:); % for nan - rows
D1 = a(:,all(~isnan(a))) % for nan - columns WE FIND D1
n1=size(D1,1) %number of record belongs to classification
sampleSpace = size(search,1) %sample space of the priop probability(#of c1 + #of c2 .... cn)
pc1 = n1/sampleSpace %prior probability of the n
mu1 = mean(D1) %mean of D1
Z1 = D1 - mu1 % centered data of D1
Eps1 = (1/n1)*(transpose(Z1)*Z1) %covariance matrix if Z1
numOfClassifier = numOfClassifier + 1;
if search(:,c) ~= numOfClassifier
break
end
end
end
I need to return
D1
Eps1
I want to return the entire values of for loop but I only end up with values from the last row.
You can store the iteration results in a cell array, and return the cell array:
Function returning two cell arrays (I named them allD1 and allEps1):
function [allD1, allEps1] = findD(i,j,c,search)
Initialize the cell arrays to empty cells before the loop:
allD1 = {};
allEps1 = {};
Add D1 and Eps1 to the end of the cell arrays (place it before the line with the break statement):
allD1{end + 1} = D1;
allEps1{end + 1} = Eps1;
Here is the modified code:
i=input('Enter a start row: ');
j=input('Enter a end row: ');
c=input('Enter classifier variable column number:')
search= importfiledataset('search-queries-features.csv',i,j);
[n,p]=size(search);
if j>n
disp('Please enter a smaller number!');
end
[D1,Eps1]=findD(i,j,c,search);
disp(D1);
disp(n1);
function [allD1, allEps1] = findD(i,j,c,search) %Find D vlaues with for loop for each classification value
%Initialize empty cell arrays
allD1 = {};
allEps1 = {};
for numOfClassifier = 1 : 100
a = search(search(:,c)==numOfClassifier,:) ;
q1 = a(all(~isnan(a),2),:); % for nan - rows
D1 = a(:,all(~isnan(a))) % for nan - columns WE FIND D1
n1=size(D1,1) %number of record belongs to classification
sampleSpace = size(search,1) %sample space of the priop probability(#of c1 + #of c2 .... cn)
pc1 = n1/sampleSpace %prior probability of the n
mu1 = mean(D1) %mean of D1
Z1 = D1 - mu1 % centered data of D1
Eps1 = (1/n1)*(transpose(Z1)*Z1) %covariance matrix if Z1
%Add D1 (and Eps1) to the end of the cell array
allD1{end + 1} = D1;
allEps1{end + 1} = Eps1;
numOfClassifier = numOfClassifier + 1;
if search(:,c) ~= numOfClassifier
break
end
end
end
Cell arrays are more general then arrays - cells can store values of different types and shapes, opposed to arrays where all elements must be of the same type.
In your case, multi-dimensional arrays might fit, but it's more confusing.
With cell arrays, each cell holds the result of the matching iteration.
For example: allD1{3} holds the value of D1 in the third iteration.

Merge array rows based on the first digit in a column

I have two arrays, A and B. The first digit of each row is the serial number.
How do I combine A and B to have an array C, such that all rows in A with the same serial number in B are concatenated horizontally?
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765 ]
B = [ 23566;
33425;
65438;
75354 ]
y = ismember(A(:,1), B(:,1), 'rows');
t=find(y);
C= [A(t,1:12),B(t,1:12)];
I need C to be:
C = [ 12345, 00000;
23496, 23566;
32673, 33425;
47542, 00000;
54765, 00000;
65436, 00000;
75343, 75354]
My approach would be the following, extract the leading digits of both arrays and compare those:
a=num2str(A)-'0';
b=num2str(B)-'0';
[ida,idb]=ismember(a(:,1),b(:,1));
Now get the sorting index of A
[~,ids]=sort(a(:,1));
Create output array
C=zeros(size(A,1),2);
Finally assign and sort output
C(:,1)=A;
C(ida,2)=B(idb(idb>0));
%sort result
C=C(ids,:)
If it's only the first digit, we only need to check if the first digit (i.e. floor(A/1e4)) matches 0 to 9, and index accordingly...
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zero(; A]; Bz = [0; B];
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, floor( A/1e4 ) );
[~,ib] = ismember( 0:9, floor( B/1e4 ) );
% Assign to C and discard unmatched rows
C = [Az(ia+1), Bz(ib+1)];
C( all( C==0, 2 ), : ) = [];
Note that keeping things numeric with the floor operation should always be preferable to flipping between numeric and character data with things like num2str...
Edit
You changed the scope of the question by commenting with new data. Here is the same method, written to be more generic so it handles A and B with more columns and different magnitude IDs
% Add some zeros at the front to make indexing work with the unmatched ismember outputs
Az = [zeros(1,size(A,2)); A]; Bz = [zeros(1,size(A,2)); B];
% Function for getting first digit
f = #(x) floor(x./(10.^floor(log10(x))));
% Find the indices for 0 to 9 within the first digits of A and B
[~,ia] = ismember( 0:9, f(A(:,1)) );
[~,ib] = ismember( 0:9, f(B(:,1)) );
% Assign to C and discard unmatched rows
C = [Az(ia+1,:), Bz(ib+1,:)];
C( all( C==0, 2 ), : ) = [];
First of all, the whole script. At first glance, I couldn't find a solution without using loops.
A = [ 12345;
47542;
32673;
65436;
75343;
23496;
54765; ]
B = [ 23566;
33425;
65438;
75354; ]
A = sort(A); % Sort A and B.
B = sort(B);
A_str = int2str(A); % Convert integers to chars.
B_str = int2str(B);
A_sn = A_str(:, 1); % Extract first columns.
B_sn = B_str(:, 1); % Basically, these are the serial numbers.
C = zeros(size(A, 1), size(A, 2) * 2); % Initialize C.
C(:, 1) = A; % First column of C is just A.
for i = 1:length(A_sn) % For all serial numbers in A...
for j = 1:length(B_sn) % For all serial numbers in B...
if (A_sn(i) == B_sn(j)) % Check if serial number in B equals the serial number in A.
C(i, 2) = B(j); % If so, set i-th row in C to the corresponding value in B.
end
end
end
C
Results in:
A =
12345
47542
32673
65436
75343
23496
54765
B =
23566
33425
65438
75354
C =
12345 0
23496 23566
32673 33425
47542 0
54765 0
65436 65438
75343 75354

Exclude value by the calculation

I have an array A (I have written so as to make it similar to the matrix that I am using) :
%%%%%%%%%%%%% This is Matrix %%%%%%%%%%%%%%%%%%%%
a = 3; b = 240; c = 10; d = 30; e = 1;
mtx1 = a.*rand(30,1) + a;
mtx2 = round((b-c).*rand(30,1));
mtx3 = round((d-e).*rand(30,1));
mtx4 = -9999.*ones(30,1);
A = [mtx1 mtx2 mtx3 mtx4];
for i = 10:12
for ii = 17 :19
A(i,:)= -9999;
A(ii,:)= 999;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I would calculate some statistical values, excluding from the calculation the values **-9999 and 999.
the statistical values must be calculated with respect to each column.
the columns represent respectively: the wind speed, direction, and
other parameters
I wrote a code but it is not correct
[nr,ncc]=size(A);
for i=1:ncc
B = A(:,i); %// Temp Vector
Oup=1; Odw=1; %// for Vector Control
while Oup>0 %// || Odw>0 % Oup>0 OR Odw>0 , Oup>0 && (AND) Odw>0
B=sort(B,'descend');
U = find(B<999 & B>-9999); % find for each column of the temp
%vector
Oup = length(U); % Calculates the length
B(U)=[]; % Delete values -9999 and 9999
end
% calculates parameters with the vector temp
count(i)=length(B);
med(i)=mean(B);
devst(i)=std(B);
mediana(i)=median(B);
vari(i)=var(B);
kurt(i)=kurtosis(B);
Asimm(i)=skewness(B);
Interv(i)=range(B);
Mass(i)=max(B);
Mini(i)=min(B);
if length(B)<nr
B(length(B)+1:nr)=nan;
end
C(:,i)=B(:); %//reconstruction of the original matrix
end
would you have any suggestions?
If your data set is in A, and you want to operate on it with a function f, just use logical indexing, i.e.:
f(A( ~(A==999 & A==-9999) )) =...
Alternatively, use find and linear indexing:
ind = find( ~(A==999 & A==-9999) );
f(A(ind)) = ....

MATLAB displaying a table [duplicate]

I want to use MATLAB's printmat do display a matrix with labels. But this doesn't work for complex numbers:
N = 5;
x = rand(N,1);
y = rand(N,1);
z = x + 1i*y;
printmat([x,y,z],'fftdemo','N=1 2 3 4 5','x y x+iy');
Output:
fftdemo =
x y x+iy
N=1 0.84072 0.34998 0.84072
2 0.25428 0.19660 0.25428
3 0.81428 0.25108 0.81428
4 0.24352 0.61604 0.24352
5 0.92926 0.47329 0.92926
As you can see the imaginary part of z isn't printed.
Is there a way to get Matlab to display complex numbers or another way to achieve this?
Any print function in matlab will only print real value of imaginary number. TO get both the parts you must call them explicitly.So correct usage would be
printmat([x,y,real(z),imag(z)],'fftdemo','N=1 2 3 4 5','x y x iy');
But this wont be of any use now since both are parts are getting printed twice.
Here is a slightly altered version of printmat that will print complex numbers. Feel free to fiddle around a bit more with it for better looks :)
function [] = printmat2(a,name,rlab,clab)
%PRINTMAT Print matrix with labels.
% PRINTMAT(A,NAME,RLAB,CLAB) prints the matrix A with the row labels
% RLAB and column labels CLAB. NAME is a string used to name the
% matrix. RLAB and CLAB are string variables that contain the row
% and column labels delimited by spaces. For example, the string
%
% RLAB = 'alpha beta gamma';
%
% defines 'alpha' as the label for the first row, 'beta' for the
% second row and 'gamma' for the third row. RLAB and CLAB must
% contain the same number of space delimited labels as there are
% rows and columns respectively.
%
% PRINTMAT(A,NAME) prints the matrix A with numerical row and column
% labels. PRINTMAT(A) prints the matrix A without a name.
%
% See also: PRINTSYS.
% Clay M. Thompson 9-24-90
% Copyright 1986-2002 The MathWorks, Inc.
% $Revision: 1.10 $ $Date: 2002/04/10 06:32:35 $
error(nargchk(1,4,nargin));
space = ' ';
[nrows,ncols] = size(a);
if nargin<2, name = []; end
if nargin==3, error('Wrong number of input arguments.'); end
if nargin<4,
rlab = []; clab = [];
for i=1:nrows, rlab = [rlab, sprintf('--%d--> ',i)]; end
for i=1:ncols, clab = [clab, sprintf('--%d--> ',i)]; end
rlab=rlab(1:length(rlab)-1);
clab=clab(1:length(clab)-1);
end
col_per_scrn=5;
len=12;
if (nrows==0)|(ncols==0),
if ~isempty(name), disp(' '), disp(sprintf('%s = ',name)), end
disp(' ')
disp(' []')
disp(' ')
return
end
% Remove extra spaces (delimiters)
ndx1 = find(clab==' ');
ndx2 = find([ndx1,0]==[-1,ndx1+1]);
if ~isempty(clab), clab(ndx1(ndx2))=[]; end
ndx1 = find(rlab==' ');
ndx2 = find([ndx1,0]==[-1,ndx1+1]);
if ~isempty(rlab), rlab(ndx1(ndx2))=[]; end
% Determine position of delimiters
cpos = find(clab==' ');
if length(cpos)<ncols-1, error('Not enough column labels.'); end
cpos = [0,cpos,length(clab)+1];
rpos = find(rlab==' ');
if length(rpos)<nrows-1, error('Not enough row labels.'); end
rpos = [0,rpos,length(rlab)+1];
col=1;
n = min(col_per_scrn-1,ncols-1);
disp(' ')
if ~isempty(name), disp(sprintf('%s = ',name)), end % Print name
while col<=ncols
% Print labels
s = space(ones(1,len+1));
for j=0:n,
lab = clab(cpos(col+j)+1:cpos(col+j+1)-1);
if length(lab)>len,
lab=lab(1:len);
else
lab=[space(ones(1,len-length(lab))),lab]; end
s= [s,' ',lab];
end
disp(setstr(s))
for i=1:nrows,
s = rlab(rpos(i)+1:rpos(i+1)-1);
if length(s)>len, s=s(1:len); else s=[space(ones(1,len-length(s))),s]; end
s = [' ',s];
for j=0:n,
element = a(i,col+j);
if imag(element) ~= 0
s=[s,sprintf('%12.5f + %12.5fi',[real(element) imag(element)])];
else
if element==0,
s=[s,' 0'];
elseif (element>=1.e6)|(element<=-1.e5)|(abs(element)<.0001)
s=[s,sprintf(' %12.5e',element)];
else
s=[s,sprintf(' %12.5f',element)];
end
end
end
disp(s)
end % for
col = col+col_per_scrn;
disp(' ')
if (ncols-col<n), n=ncols-col; end
end % while
% end printmat

Use zero based matrix in MATLAB

Could the following equation be possible in MATLAB?
Suppose we have given data of length N, and we want to consider a linear equation among the some L nubmers and find coefficients ai. Is this possible? Because if yes, then coefficients can be solved by
a = pinv(D)*d
where D is a given matrix and d is a left vector.
The above equation comes from the following linear models
k = L, L+1, L+2, N-1
I have tested this code with some fixed f.
unction [a] = find_coeficient(y,N,L)
Lp = L + 1;
Np = N + 1;
d = y(L:N-1);
D=[];
for ii=Lp:(Np-1)
% Index into the y vector for each row of D
D = vertcat(D, y(ii:-1:(ii-Lp+1))');
end
a = D\d;
end
Is it correct?
This is absolutely possible in MATLAB. However, 0 indexes are not natively supported. You will need to do a "change of variables" by letting the index in each element be index+1. Here's a bit of an example:
% Generate some data
N = 40;
y = 10 * randn(N,1);
% Select an L value
L = N - 4 + 1;
d = y(L:N);
D = reshape(y,4,10);
% Solve the equation using the '\' rather than the pseudo inverse
b = D\d
For more information on the divide operator, see Systems of Linear Equations.
OK, I've thought through this a bit more. Part of the confusion here is the change of variable limits. The substitution applies to the indexing variable, not the size of the data, so L and N are unchanged, but the index is adjusted to keep it from falling off the edge of the array. So in the formula, just add 1 to every element index.
y[L] = [ y[L-1] y[L-2] ... y[0] ] * a1
.
.
y[N-1] = [ y[N-2] y[N-3] ... y[N-L-1] ] * aL
becomes:
y[L+1] = [ y[L-1+1] y[L-2+1] ... y[0+1] ] * a1
.
.
y[N-1+1] = [ y[N-2+1] y[N-3+1] ... y[N-L-1+1] ] * aL
=
y[L+1] = [ y[L] y[L-1] ... y[1] ] * a1
.
.
y[N] = [ y[N-1] y[N-2] ... y[N-L] ] * aL
Which we can then use to complete our script:
function a = find_coeficient(y,N,L)
d = y((L+1):N);
D=[];
for ii=L:(N-1)
% index into the y vector for each row of D
D = vertcat(D, y(ii:-1:(ii-L+1))');
end
a = D\d;
end