MATLAB function matrix parameter - matlab

I've seen a blog post about computing the K-nearest neighbor as follows:
function test_targets = knn(train_patterns, train_targets, test_patterns, K)
% Hubungi budi santosa di budi_s#ie.its.ac.id
% untuk laporan kesalahan (bug).
% Implementasi the Nearest neighbor algorithm
% Inputs:
% train_patterns - Train patterns (obs x dim) D x N
% train_targets - Train targets 1 x N (classes)
% test_patterns - Test patterns D x M (M testing)
% K - jumlah nearest neighbors
%
% Outputs
% test_targets - Predicted targets
L = length(train_targets);
Uc = unique(train_targets);
if (L < K),
error(’tetangga lebih banyak dari jumlah titik training’)
end
N = size(test_patterns, 1);
test_targets = zeros(N,1);
for i = 1:N,
jar=(train_patterns - repmat(test_patterns(i,:),L,1)).^2;
dist = sum(jar,2);%jarak tiap titik data test terhadap data training
[m, indices] = sort(dist);%urutkan jarak dr yg terkecil
yt=train_targets(indices(1:K));%ambil K jarak terkecil dan periksa labelnya
n = hist(yt, Uc);%menempatkan data testing ke kelas mana (tergantung Uc)
[m, best] = max(n);%mencari frekuensi maksimum kelas mana paling banyak dari K tetangga terdekat
test_targets(i) = Uc(best);
end
My problem is that I keep getting the following MATLAB message:
??? Error using ==> minus
Matrix dimensions must agree.
I have 2 matrices:
A is NxD A =
670.00 1630.00 2380.00 1
721.00 1680.00 2400.00 1
750.00 1710.00 2440.00 1
660.00 1800.00 2150.00 1
660.00 1800.00 2150.00 1
680.00 1958.00 2542.00 1
440.00 1120.00 2210.00 2
400.00 1070.00 2280.00 2
B is MxD B =
750.00 1710.00 2440.00 1
680.00 1910.00 2440.00 1
500.00 1000.00 2325.00 2
500.00 1000.00 2325.00 2
As you can see, the 4th column says the class of the example. I am using the function like:
train_patterns = A(:,:) %HOW TO PASS A??, A(:,1:3)? A(1:size(B,1),:) ?? which????
train_targets = A(:,4) %pass the column 4 as vector of classes
test_patterns = B(:,1:3) %pass only the 3 columns
Knn = 3
So the output must be a vector 1 x M with the prediction of all B examples. How can I accomplish this?

You need to transpose A and B to go from NxD to DxN (using the ' operator).
Thus:
train_patterns = A(:,1:3)'; %'# 3-by-N
train_targets = A(:,4)'; %'# 1-by-N
test_patterns = B(:,1:3)'; %'# 3-by-M (last column will be used by you for checking)

Related

Multiply inverse matrix with another one

I want to multiply two matrices, the first matrix is the inverse of A, and the second matrix is B,
input('Enter The first Matrix')
A = [ 1 2 3 ; 4 5 6 ; 7 8 0 ]
[m n] = size(A)
if m==n
if det(A)==0
disp('inverse does not exist')
else
invv=inv(A)
disp(invv)
end
else
disp('Number of rows and columns are not equel , no inverse')
end
input('Enter The second Matrix')
B = [ 1 ; 1 ; 1 ]
How can I verify that the number of columns in the first matrix is equal to the number of rows in the second matrix, so that they can be multiplied?
function [X] = dot_inv(X,x)
% X - numeric array
% x - cell array of numeric vectors
% DIM - dimensions to omit (asumes ndims(X) = numel(x))
% Y - inner product obtained by summing the products of X and x along DIM
% initialise dimensions
%--------------------------------------------------------------------------
[m n] = size(X)
if m==n
if det(X)==0
error('Error. \n inverse does not exist.')
else
X=inv(X)
end
else
error('Error. \n Number of rows and columns are not equel , no inverse!')
end
if iscell(x)
DIM = (1:numel(x)) + ndims(X) - numel(x);
else
DIM = 1;
x = {x};
end
% inner product using recursive summation (and bsxfun)
%--------------------------------------------------------------------------
for d = 1:numel(x)
s = ones(1,ndims(X));
s(DIM(d)) = numel(x{d});
X = bsxfun(#times,X,reshape(full(x{d}),s));
X = sum(X,DIM(d));
end
% eliminate singleton dimensions
%--------------------------------------------------------------------------
X = squeeze(X);
return

PDF and CDF plot for central limit theorem using Matlab

I am struggling to plot the PDF and CDF graphs of where
Sn=X1+X2+X3+....+Xn
using central limit theorem where n = 1; 2; 3; 4; 5; 10; 20; 40
I am taking Xi to be a uniform continuous random variable for values between (0,3).
Here is what i have done so far -
close all
%different sizes of input X
%N=[1 5 10 50];
N = [1 2 3 4 5 10 20 40];
%interval (1,6) for random variables
a=0;
b=3;
%to store sum of differnet sizes of input
for i=1:length(N)
%generates uniform random numbers in the interval
X = a + (b-a).*rand(N(i),1);
S=zeros(1,length(X));
S=cumsum(X);
cd=cdf('Uniform',S,0,3);
plot(cd);
hold on;
end
legend('n=1','n=2','n=3','n=4','n=5','n=10','n=20','n=40');
title('CDF PLOT')
figure;
for i=1:length(N)
%generates uniform random numbers in the interval
X = a + (b-a).*rand(N(i),1);
S=zeros(1,length(X));
S=cumsum(X);
cd=pdf('Uniform',S,0,3);
plot(cd);
hold on;
end
legend('n=1','n=2','n=3','n=4','n=5','n=10','n=20','n=40');
title('PDF PLOT')
My output is nowhere near what I am expecting any help is much appreciated.
This can be done with vectorization using rand() and cumsum().
For example, the code below generates 40 replications of 10000 samples of a Uniform(0,3) distribution and stores in X. To meet the Central Limit Theorem (CLT) assumptions, they are independent and identically distributed (i.i.d.). Then cumsum() transforms this into 10000 copies of the Sn = X1 + X2 + ... where the first row is n = 10000copies of Sn = X1, the 5th row is n copies of S_5 = X1 + X2 + X3 + X4 + X5. The last row is n copies of S_40.
% MATLAB R2019a
% Setup
N = [1:5 10 20 40]; % values of n we are interested in
LB = 0; % lowerbound for X ~ Uniform(LB,UB)
UB = 3; % upperbound for X ~ Uniform(LB,UB)
n = 10000; % Number of copies (samples) for each random variable
% Generate random variates
X = LB + (UB - LB)*rand(max(N),n); % X ~ Uniform(LB,UB) (i.i.d.)
Sn = cumsum(X);
You can see from the image that the n = 2 case, the sum is indeed a Triangular(0,3,6) distribution. For the n = 40 case, the sum is approximately Normally distributed (Gaussian) with mean 60 (40*mean(X) = 40*1.5 = 60). This shows the convergence in distribution for both the probability density function (PDF) and the cumulative distribution function (CDF).
Note: The CLT is often stated with convergence in distribution to a Normal distribution with zero mean as it has been shifted. Shifting the results by subtracting mean(Sn) = n*mean(X) = n*0.5*(LB+UB) from Sn gets this done.
Code below isn't the gold standard but it produced the image.
figure
s(11) = subplot(6,2,1) % n = 1
histogram(Sn(1,:),'Normalization','pdf')
title(s(11),'n = 1')
s(12) = subplot(6,2,2)
cdfplot(Sn(1,:))
title(s(12),'n = 1')
s(21) = subplot(6,2,3) % n = 2
histogram(Sn(2,:),'Normalization','pdf')
title(s(21),'n = 2')
s(22) = subplot(6,2,4)
cdfplot(Sn(2,:))
title(s(22),'n = 2')
s(31) = subplot(6,2,5) % n = 5
histogram(Sn(5,:),'Normalization','pdf')
title(s(31),'n = 5')
s(32) = subplot(6,2,6)
cdfplot(Sn(5,:))
title(s(32),'n = 5')
s(41) = subplot(6,2,7) % n = 10
histogram(Sn(10,:),'Normalization','pdf')
title(s(41),'n = 10')
s(42) = subplot(6,2,8)
cdfplot(Sn(10,:))
title(s(42),'n = 10')
s(51) = subplot(6,2,9) % n = 20
histogram(Sn(20,:),'Normalization','pdf')
title(s(51),'n = 20')
s(52) = subplot(6,2,10)
cdfplot(Sn(20,:))
title(s(52),'n = 20')
s(61) = subplot(6,2,11) % n = 40
histogram(Sn(40,:),'Normalization','pdf')
title(s(61),'n = 40')
s(62) = subplot(6,2,12)
cdfplot(Sn(40,:))
title(s(62),'n = 40')
sgtitle({'PDF (left) and CDF (right) for Sn with n \in \{1, 2, 5, 10, 20, 40\}';'note different axis scales'})
for tgt = [11:10:61 12:10:62]
xlabel(s(tgt),'Sn')
if rem(tgt,2) == 1
ylabel(s(tgt),'pdf')
else % rem(tgt,2) == 0
ylabel(s(tgt),'cdf')
end
end
Key functions used for plot: histogram() from base MATLAB and cdfplot() from the Statistics toolbox. Note this could be done manually without requiring the Statistics toolbox with a few lines to obtain the cdf and then just calling plot().
There was some concern in comments over the variance of Sn.
Note the variance of Sn is given by (n/12)*(UB-LB)^2 (derivation below). Monte Carlo simulation shows our samples of Sn do have the correct variance; indeed, it converges to this as n gets larger. Simply call var(Sn(40,:)).
% with n = 10000
var(Sn(40,:)) % var(S_40) = 30 (will vary slightly depending on random seed)
(40/12)*((UB-LB)^2) % 29.9505
You can see the convergence is very good by S_40:
step = 0.01;
Domain = 40:step:80;
mu = 40*(LB+UB)/2;
sigma = sqrt((40/12)*((UB-LB)^2));
figure, hold on
histogram(Sn(40,:),'Normalization','pdf')
plot(Domain,normpdf(Domain,mu,sigma),'r-','LineWidth',1.4)
ylabel('pdf')
xlabel('S_n')
Derivation of mean and variance for Sn:
For the expectation (mean), the second equality holds by linearity of expectation. The third equality holds since X_i are identically distributed.
The discrete version of this is posted here.

Vectorize the sum of outer products of coresponding columns of two matrices using Matlab/Octave

Suppose I have two matrices A and B which are made up of column vectors as follows.
A = [a_1,a_2,...,a_N];
B = [b_1,b_2,...,b_N];
Is there any way to vectorize the calculation of the sum of outer products for every column in A with the corresponding column in B. Here is my non-vectorized solution.
S = zeros(size(A,1), size(B,1));
for n=1:N
S = S + A(:,n)*B(:,n)'; % S = S + a_n * b_n'
end
Any help would be greatly appreciated.
you are not clear on what N is, but I assume that N = number of column vectors - which means you are simply doing A * B'
A = rand(3,4);
B = rand(3,4);
N = size(A,2);
S = zeros(size(A,1), size(B,1));
for n=1:N
S = S + A(:,n)*B(:,n)'; % S = S + a_n * b_n'
end
%Check that you are doing A*B'
S == A*B'
>> ans =
1 1 1
1 1 1
1 1 1

What is a quick way to compute the euclidean norm of two sets of vectors?

I know that MATLAB works better when most or everything is vectorized. I have two set of vectors X and T. For every vector x in X I want to compute:
this is because I want to compute:
which can be easily expressed as MATLAB linear algebra operations as I wrote above with a dot product. I am hoping that I can speed this up by having those vectors, instead of computing each f(x) with a for loop. Ideally I could have it all vectorized and compute:
I've been think about this for some time now, but it doesn't seem to be a a nice way were a function takes two vectors and computes the norm between each one of them, with out me having to explicitly write the for loop.
i.e. I've implemented the trivial code:
function [ f ] = f_start( x, c, t )
% Computes f^*(x) = sum_i c_i exp( - || x_i - t_i ||^2)
% Inputs:
% x = data point (D x 1)
% c = weights (K x 1)
% t = centers (D x K)
% Outputs:
% f = f^*(x) = sum_k c_k exp( - || x - t_k ||^2)
[~, K] = size(t);
f = 0;
for k=1:K
c_k = c(k);
t_k = t(:, k);
norm_squared = norm(x - t_k, 2)^2;
f = f + c_k * exp( -1 * norm_squared );
end
end
but I was hoping there was a less naive way to do this!
I think you want pdist2 (Statistics Toolbox):
X = [1 2 3;
4 5 6];
T = [1 2 3;
1 2 4;
7 8 9];
result = pdist2(X,T);
gives
result =
0 1.0000 10.3923
5.1962 4.6904 5.1962
Equivalently, if you don't have that toolbox, use bsxfun as follows:
result = squeeze(sqrt(sum(bsxfun(#minus, X, permute(T, [3 2 1])).^2, 2)));
Another method just for kicks
X = [1 2 3;
4 5 6].';
T = [1 2 3;
1 2 4;
7 8 9].';
tT = repmat(T,[1,size(X,2)]);
tX = reshape(repmat(X,[size(T,2),1]),size(tT));
res=reshape(sqrt(sum((tT-tX).^2)).',[size(T,2),size(X,2)]).'

Matlab Generating a Matrix

I am trying to generate a matrix in matlab which I will use to solve a polynomial regression formula.
Here is how I am trying to generate the matrix:
I have an input vector X containing N elements and an integer d. d is the integer to know how many times we will add a new column to the matrix we are trying to generate int he following way.
N = [X^d X^{d-1} ... X^2 X O]
O is a vector of same length as X with all 1's.
Everytime d > 2 it does not work.
Can you see any errors in my code (i am new to matlab):
function [ PR ] = PolyRegress( X, Y, d )
O = ones(length(X), 1)
N = [X O]
for j = 2:d
tmp = power(X, j)
N = [tmp N]
end
%TO DO: compute PR
end
It looks like the matlab function vander already does what you want to do.
The VANDER function will only generate powers of the vector upto d = length(X)-1. For a more general solution, you can use the BSXFUN function (works with any value of d):
N = bsxfun(#power, X(:), d:-1:0)
Example:
>> X = (1:.5:2);
>> d = 5;
>> N = bsxfun(#power, X(:), d:-1:0)
N =
1 1 1 1 1 1
7.5938 5.0625 3.375 2.25 1.5 1
32 16 8 4 2 1
I'm not sure if this is the order you want, but it can be easily reversed: use 0:d instead of d:-1:0...