From ea06f92ca479a5934553ad37c29c51f17faf191a Mon Sep 17 00:00:00 2001 From: Antonello Lobianco Date: Fri, 10 Jun 2022 15:28:29 +0200 Subject: [PATCH] Solves issue #32: KernelPerceptron non working with a single class in training --- Project.toml | 2 +- src/Perceptron/Perceptron.jl | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Project.toml b/Project.toml index 7462c44c..85911c70 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "BetaML" uuid = "024491cd-cc6b-443e-8034-08ea7eb7db2b" authors = ["Antonello Lobianco "] -version = "0.6.0" +version = "0.6.1" [deps] CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" diff --git a/src/Perceptron/Perceptron.jl b/src/Perceptron/Perceptron.jl index 40ff0bee..0b9d64d0 100644 --- a/src/Perceptron/Perceptron.jl +++ b/src/Perceptron/Perceptron.jl @@ -200,7 +200,7 @@ Train a multiclass kernel classifier "perceptron" algorithm based on x and y. # Parameters: * `x`: Feature matrix of the training data (n × d) -* `y`: Associated labels of the training data, in the format of ⨦ 1 +* `y`: Associated labels of the training data * `K`: Kernel function to employ. See `?radialKernel` or `?polynomialKernel`for details or check `?BetaML.Utils` to verify if other kernels are defined (you can alsways define your own kernel) [def: [`radialKernel`](@ref)] * `T`: Maximum number of iterations (aka "epochs") across the whole set (if the set is not fully classified earlier) [def: 100] * `α`: Initial distribution of the errors [def: `zeros(length(y))`] @@ -220,9 +220,8 @@ Train a multiclass kernel classifier "perceptron" algorithm based on x and y. # Example: ```jldoctest -julia> model = kernelPerceptron([1.1 2.1; 5.3 4.2; 1.8 1.7], [-1,1,-1]) -julia> ŷtrain = Perceptron.predict(xtrain,model.x,model.y,model.α, model.classes,K=model.K) -julia> ϵtrain = error(ytrain, mode(ŷtrain)) +julia> model = kernelPerceptron([1.1 1.1; 5.3 4.2; 1.8 1.7; 7.5 5.2;], ["a","c","b","c"]) +julia> ŷtest = Perceptron.predict([10 10; 2.2 2.5; 1 1],model.x,model.y,model.α, model.classes,K=model.K) ``` """ function kernelPerceptron(x, y; K=radialKernel, T=100, α=zeros(Int64,length(y)), nMsgs=0, shuffle=false, rng = Random.GLOBAL_RNG) @@ -234,11 +233,10 @@ function kernelPerceptron(x, y; K=radialKernel, T=100, α=zeros(Int64,length(y)) outX = Array{typeof(x),1}(undef,nModels) outY = Array{Array{Int64,1},1}(undef,nModels) outα = Array{Array{Int64,1},1}(undef,nModels) - modelCounter = 1 for (i,c) in enumerate(yclasses) for (i2,c2) in enumerate(yclasses) - if i2 <= i continue end + if i2 <= i continue end # never false with a single class (always "continue") ids = ( (y .== c) .| (y .== c2) ) thisx = x[ids,:] thisy = y[ids] @@ -257,7 +255,7 @@ end """ kernelPerceptronBinary(x,y;K,T,α,nMsgs,shuffle) -Train a multiclass kernel classifier "perceptron" algorithm based on x and y +Train a binary kernel classifier "perceptron" algorithm based on x and y # Parameters: * `x`: Feature matrix of the training data (n × d) @@ -578,6 +576,10 @@ function predict(x,xtrain,ytrain,α;K=radialKernel) (n,d) = size(x) (ntrain,d2) = size(xtrain) if (d2 != d) error("xtrain and x must have the same dimensions."); end + # corner case all one category + if length(unique(ytrain)) == 1 + return fill(unique(ytrain)[1],n) + end if ( length(ytrain) != ntrain || length(α) != ntrain) error("xtrain, ytrain and α must all have the same length."); end y = zeros(Int64,n) for i in 1:n @@ -616,6 +618,10 @@ function predict(x,xtrain,ytrain,α;K=radialKernel) (n,d) = size(x) nCl = length(classes) y = Array{Dict{Tcl,Float64},1}(undef,n) + # corner case single class in training + if nCl == 1 + return fill(Dict(classes[1] => 100.0),n) + end nModels = Int((nCl * (nCl - 1)) / 2) if !(nModels == length(xtrain) == length(ytrain) == length(α)) error("xtrain, ytrain or α have a length not compatible with the number of classes in this model."); end x = makeMatrix(x)