Мне нужно реализовать двоичную классификацию SVM вручную (без использования функции прогнозирования), используя модель, обученную функцией fitcsvm. В документации по функции прогнозирования (https://www.mathworks.com/help/stats/classreg.learning.classif.compactclassificationsvm.predict.html) я нашел следующую формулу: Классификационная формула
Я реализовал эту функцию следующим образом:
function pred = svmPredict(model, X)
%SVMPREDICT returns a vector of predictions using a trained SVM model
%(fitcsvm).
% pred = SVMPREDICT(model, X) returns a vector of predictions using a
% trained SVM model (fitcsvm). X is a mxn matrix where there each
% example is a row. model is a svm model returned from fitcsvm.
% predictions pred is a m x 1 column of predictions of {0, 1} values.
%
% Check if we are getting a column vector, if so, then assume that we only
% need to do prediction for a single example
if (size(X, 2) == 1)
% Examples should be in rows
X = X';
end
% Dataset
m = size(X, 1);
p = zeros(m, 1);
pred = zeros(m, 1);
for i = 1:m
prediction = 0;
for j = 1:size(model.X, 1)
prediction = prediction + ...
model.alphas(j) * model.y(j) * ...
model.kernelFunction(X(i,:)', model.X(j,:)');
end
p(i) = prediction + model.b;
end
% Convert predictions into 0 / 1
pred(p >= 0) = 1;
pred(p < 0) = 0;
end
Я реализовал функцию gaussianKernel следующим образом:
function sim = gaussianKernel(x1, x2, gamma)
%RBFKERNEL returns a radial basis function kernel between x1 and x2
% sim = gaussianKernel(x1, x2) returns a gaussian kernel between x1 and x2
% and returns the value in sim
% Ensure that x1 and x2 are column vectors
x1 = x1(:); x2 = x2(:);
% You need to return the following variables correctly.
norma = sqrt(sum((x1-x2).^2,"all"));
%sim = exp(-gamma*sum(norma,'all').^2);
sim= exp(-gamma*norma^2);
Следуя моему основному коду:
clear;
%% Load dataset from file
dataset = readtable('cancer2.txt','PreserveVariableNames',true);
dataset = dataset{:,:}; % table to matrix
%% Preprocessing
% Shuffle examples
dataset = dataset(randperm(size(dataset, 1)),:);
% Separating features and labels
X = dataset(:,1:(end-1));
y = dataset(:,end);
% feature scaling
X = X./max(X);
%% Training, cross validation and test set
m = size(dataset,1);
aux60 = floor(m*0.6);
aux20 = floor(m*0.2);
% Training set
Xtrain = X(1:aux60,:);
ytrain = y(1:aux60,:);
% Cross validation set
Xval = X((aux60+1):(aux60+aux20),:);
yval = y((aux60+1):(aux60+aux20),:);
% Test set
Xtest = X((aux60+aux20+1):end,:);
ytest = y((aux60+aux20+1):end,:);
%% Training
% Grid search
[C,gamma] = gridSearch(Xtrain, ytrain, Xval, yval);
% Fitting
MATLABmodel = fitcsvm(Xtrain,ytrain,'KernelFunction','rbf', 'BoxConstraint',C,'KernelScale',gamma);
%% Classification
% MATLAB function
[p1,~] = predict(MATLABmodel,Xtest);
% My function
mymodel.X = MATLABmodel.SupportVectors;
mymodel.y = MATLABmodel.SupportVectorLabels;
gamma = MATLABmodel.KernelParameters.Scale;
mymodel.kernelFunction = @(x1, x2)gaussianKernel(x1, x2, gamma);
mymodel.b = MATLABmodel.Bias;
mymodel.alphas = MATLABmodel.Alpha;
mymodel.w = 0; % I am using RBF kernel, so w is irrelevant
p2 = svmPredict(mymodel,Xtest);
%% Results
fprintf('\nMATLAB predict function Test Set Accuracy: %f\n', mean(double(p1 == ytest)) * 100);
fprintf('My predict function Test Set Accuracy: %f\n', mean(double(p2 == ytest)) * 100);
Я реализовал функцию gridSearch следующим образом:
function [C, gamma] = gridSearch(X, y, Xval, yval)
%gridSearch returns your choice of C and gamma
%where you select the optimal (C, gamma) learning parameters to use for SVM
%with RBF kernel
% [C, gamma] = gridSearch(X, y, Xval, yval) returns your choice of C and
% gamma. This function to return the optimal C and gamma based on a
% cross-validation set.
C = 1e-2;
gamma = 1e0;
model = fitcsvm(X,y,'KernelFunction','rbf','BoxConstraint',C,'KernelScale',gamma);
[predictions,~] = predict(model,Xval);
error = mean(double(predictions ~= yval));
Cgrid = [1e-2 1e-1 1e0 1e1 1e2 1e3];
gammagrid = [1e-7 1e-6 1e-5 1e-4 1e-3 1e-2 1e-1 1e0 1e1 1e2];
for i=1:length(Cgrid)
for j=1:length(gammagrid)
model = fitcsvm(X,y,'KernelFunction','rbf','BoxConstraint',Cgrid(i),'KernelScale',gammagrid(j));
[predictions,~] = predict(model,Xval);
if mean(double(predictions ~= yval)) < error
error = mean(double(predictions ~= yval));
C = Cgrid(i);
gamma = gammagrid(j);
end
end
end
end
«Cancer.txt» доступен в https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_breast_cancer.html
При запуске кода иногда p1 равен p2, а иногда p1 отличается от p2. Почему это происходит? Что еще делает функция предсказания для классификации примера, отличного от знака f (x)? Я пытаюсь применить это для разных наборов данных, но я получил тот же результат (иногда p1 == p2, а иногда p1 / = p2).