return the squared second norm of vector normsquaredv sumx x for x in v args vector ndarray input vector returns float squared second norm of vector normsquared1 2 5 normsquarednp asarray1 2 5 normsquared0 0 0 support vector classifier args kernel str kernel to use default linear possible choices linear regularization constraint for soft margin data not linearly separable default unbound svckernelasdf traceback most recent call last valueerror unknown kernel asdf svckernelrbf traceback most recent call last valueerror rbf kernel requires gamma svckernelrbf gamma1 traceback most recent call last valueerror gamma must be 0 in the future there could be a default value like in sklearn sklear defgamma 1nfeatures x var wiki previously it was 1nfeatures kernels linear kernel as if no kernel used at all return np dotvector1 vector2 def rbfself vector1 ndarray vector2 ndarray float return np expself gamma normsquaredvector1 vector2 def fitself observations listndarray classes ndarray none self observations observations self classes classes using wolfe s dual to calculate w primal problem minimize 12normsquaredw constraint ynw xn b 1 with l a vector dual problem maximize sumnln 12 sumnsummlnlmynymxn xm constraint self c ln 0 and sumnlnyn 0 then we get w using w sumnlnynxn at the end we can get b meanyn w xn since we use kernels we only need lstar to calculate b and to classify observations n np shapeclasses def tominimizecandidate ndarray float s 0 n np shapecandidate for i in rangen for j in rangen s candidatei candidatej classesi classesj self kernelobservationsi observationsj return 1 2 s sumcandidate lycontraint linearconstraintclasses 0 0 lbounds bounds0 self regularization lstar minimize tominimize np onesn boundslbounds constraintslycontraint x self optimum lstar calculating mean offset of separation plane to points s 0 for i in rangen for j in rangen s classesi classesi self optimumi self kernel observationsi observationsj self offset s n def predictself observation ndarray int s sum self optimumn self classesn self kernelself observationsn observation for n in rangelenself classes return 1 if s self offset 0 else 1 if name main import doctest doctest testmod return the squared second norm of vector norm_squared v sum x x for x in v args vector ndarray input vector returns float squared second norm of vector norm_squared 1 2 5 norm_squared np asarray 1 2 5 norm_squared 0 0 0 support vector classifier args kernel str kernel to use default linear possible choices linear regularization constraint for soft margin data not linearly separable default unbound svc kernel asdf traceback most recent call last valueerror unknown kernel asdf svc kernel rbf traceback most recent call last valueerror rbf kernel requires gamma svc kernel rbf gamma 1 traceback most recent call last valueerror gamma must be 0 in the future there could be a default value like in sklearn sklear def_gamma 1 n_features x var wiki previously it was 1 n_features kernels linear kernel as if no kernel used at all rbf radial basis function kernel note for more information see https en wikipedia org wiki radial_basis_function_kernel args vector1 ndarray first vector vector2 ndarray second vector returns float exp gamma norm_squared vector1 vector2 fits the svc with a set of observations args observations list ndarray list of observations classes ndarray classification of each observation in 1 1 using wolfe s dual to calculate w primal problem minimize 1 2 norm_squared w constraint yn w xn b 1 with l a vector dual problem maximize sum_n ln 1 2 sum_n sum_m ln lm yn ym xn xm constraint self c ln 0 and sum_n ln yn 0 then we get w using w sum_n ln yn xn at the end we can get b mean yn w xn since we use kernels we only need l_star to calculate b and to classify observations opposite of the function to maximize args candidate ndarray candidate array to test return float wolfe s dual result to minimize calculating mean offset of separation plane to points get the expected class of an observation args observation vector observation returns int 1 1 expected class xs np asarray 0 1 np asarray 0 2 np asarray 1 1 np asarray 1 2 y np asarray 1 1 1 1 s svc s fit xs y s predict np asarray 0 1 1 s predict np asarray 1 1 1 s predict np asarray 2 2 1
import numpy as np
from numpy import ndarray
from scipy.optimize import Bounds, LinearConstraint, minimize


def norm_squared(vector: ndarray) -> float:
    
    return np.dot(vector, vector)


class SVC:
    

    def __init__(
        self,
        *,
        regularization: float = np.inf,
        kernel: str = "linear",
        gamma: float = 0.0,
    ) -> None:
        self.regularization = regularization
        self.gamma = gamma
        if kernel == "linear":
            self.kernel = self.__linear
        elif kernel == "rbf":
            if self.gamma == 0:
                raise ValueError("rbf kernel requires gamma")
            if not isinstance(self.gamma, (float, int)):
                raise ValueError("gamma must be float or int")
            if not self.gamma > 0:
                raise ValueError("gamma must be > 0")
            self.kernel = self.__rbf
            
            
            
        else:
            msg = f"Unknown kernel: {kernel}"
            raise ValueError(msg)

    
    def __linear(self, vector1: ndarray, vector2: ndarray) -> float:
        
        return np.dot(vector1, vector2)

    def __rbf(self, vector1: ndarray, vector2: ndarray) -> float:
        
        return np.exp(-(self.gamma * norm_squared(vector1 - vector2)))

    def fit(self, observations: list[ndarray], classes: ndarray) -> None:
        

        self.observations = observations
        self.classes = classes

        (n,) = np.shape(classes)

        def to_minimize(candidate: ndarray) -> float:
            
            s = 0
            (n,) = np.shape(candidate)
            for i in range(n):
                for j in range(n):
                    s += (
                        candidate[i]
                        * candidate[j]
                        * classes[i]
                        * classes[j]
                        * self.kernel(observations[i], observations[j])
                    )
            return 1 / 2 * s - sum(candidate)

        ly_contraint = LinearConstraint(classes, 0, 0)
        l_bounds = Bounds(0, self.regularization)

        l_star = minimize(
            to_minimize, np.ones(n), bounds=l_bounds, constraints=[ly_contraint]
        ).x
        self.optimum = l_star

        
        s = 0
        for i in range(n):
            for j in range(n):
                s += classes[i] - classes[i] * self.optimum[i] * self.kernel(
                    observations[i], observations[j]
                )
        self.offset = s / n

    def predict(self, observation: ndarray) -> int:
        
        s = sum(
            self.optimum[n]
            * self.classes[n]
            * self.kernel(self.observations[n], observation)
            for n in range(len(self.classes))
        )
        return 1 if s + self.offset >= 0 else -1


if __name__ == "__main__":
    import doctest

    doctest.testmod()