import numpy as np from utils import common import matplotlib.pyplot as plt from tqdm import tqdm import scipy.spatial.distance as ssd

导入所需的库

def RBF_kernel(sigma): def kernel(x, y): ''' :param x: N x d :param y: M x d :return: N x M ''' dist = ssd.cdist(x, y, 'euclidean') # 计算欧氏距离 return np.exp(-np.square(dist) * sigma) # 计算RBF核函数的值

return kernel

定义RBF核函数

def auto_scale(X): X_var = np.var(X,ddof=1) # 计算X的方差 sigma = 1.0 / (X.shape[1] * X_var) if X_var != 0 else 1.0 # 计算自动缩放的参数sigma return sigma

自动缩放数据

def linear_kernel(): def kernel(x, y): ''' :param x: N x d :param y: M x d :return: N x M ''' return x @ y.T # 计算线性核函数的值

return kernel

定义线性核函数

class SVM: def init(self, C, kernel, max_iter=500,show_fitting_bar=True): self.kernel = kernel # 核函数 self.C = C # 惩罚参数 self.max_iter = max_iter # 最大迭代次数 self.biary_encoder = common.BinaryEncoder() # 二进制编码器 self.tqdm = tqdm if show_fitting_bar else lambda x:x # 进度条显示

def error(self, index):
    pred = (self.alpha * self._label).T @ self.Q[:, index] + self.b  # 计算预测值
    return pred - self._label[index]  # 计算误差

def fit(self, X: np.ndarray, y: np.ndarray, tol: float = 1e-3):
    '''
    :param X: N x d
    :param y: N
    :param tol: scalar
    :return:
    '''
    N, d = X.shape
    self._X = X  # 训练数据
    self._label = self.biary_encoder.fit_transform(y)  # 标签编码
    self.Q = self.kernel(X, X)  # 计算核矩阵
    self.alpha = np.zeros(N)  # 初始化拉格朗日乘子
    self.b = 0.0  # 初始化截距
    satisfied_count = 0

    for iter_count in self.tqdm(range(self.max_iter)):  # 迭代训练
        alpha_changed_count = 0
        for i in range(N):
            Ei = self.error(i)  # 计算第i个样本的误差
            alphai_old = self.alpha[i].copy()  # 保存旧的拉格朗日乘子
            yi = self._label[i]  # 第i个样本的标签

            # 选择违反KKT条件的alpha i
            if (yi * Ei < -tol and alphai_old < self.C) or (yi * Ei > tol and alphai_old > 0):
                # 随机选择alpha j
                j = np.random.randint(0, N)
                while j == i:
                    j = np.random.randint(0, N)
                yj = self._label[j]  # 第j个样本的标签
                Ej = self.error(j)  # 计算第j个样本的误差
                alphaj_old = self.alpha[j].copy()  # 保存旧的拉格朗日乘子

                # 计算边界L和H
                if yi == yj:
                    L = max(0.0, alphai_old + alphaj_old - self.C)
                    H = min(self.C, alphai_old + alphaj_old)
                else:
                    L = max(0.0, alphaj_old - alphai_old)
                    H = min(self.C, self.C + alphaj_old - alphai_old)

                # 计算eta
                eta = 2.0 * self.Q[i, j] - self.Q[i, i] - self.Q[j, j]
                if eta >= 0:
                    continue

                # 更新alpha j
                self.alpha[j] =alphaj_old - (yj * (Ei - Ej) / eta)

                # 限制alpha j的取值范围
                self.alpha[j] = np.clip(self.alpha[j], L, H)

                # 更新alpha i
                delta_j = alphaj_old - self.alpha[j]
                if np.abs(delta_j) < tol:
                    continue
                self.alpha[i] =alphai_old + yi * yj * delta_j

                # 更新截距b
                bi = self.b - Ei \
                     - yi * (self.alpha[i] - alphai_old) * self.Q[i, i] \
                     - yj * (self.alpha[j] - alphaj_old) * self.Q[i, j]
                bj = self.b - Ej \
                     - yi * (self.alpha[i] - alphai_old) * self.Q[i, j] \
                     - yj * (self.alpha[j] - alphaj_old) * self.Q[j, j]
                if 0.0+tol < self.alpha[i] < self.C-tol:
                    self.b = bi
                elif 0.0+tol < self.alpha[j] < self.C-tol:
                    self.b = bj
                else:
                    self.b = (bi + bj) / 2.0

                alpha_changed_count += 1
        if alpha_changed_count == 0:
            satisfied_count += 1
        else:
            satisfied_count = 0
        if satisfied_count >= 5:
            break

    mask = self.alpha > tol  # 选取大于阈值的拉格朗日乘子
    self.support_vectors = mask  # 支持向量
    self.X_sup = X[mask]  # 支持向量的特征
    self.Y_sup = self._label[mask]  # 支持向量的标签
    self.alpha_sup = self.alpha[mask]  # 支持向量的拉格朗日乘子

    del self._X
    del self._label
    del self.alpha
    del self.Q

def predict_proba(self, X):
    sigma = self.kernel(X, self.X_sup)  # 计算测试样本与支持向量的核矩阵
    sigma = self.Y_sup[np.newaxis, :] * self.alpha_sup[np.newaxis, :] * sigma  # 计算预测值
    y_hat = np.sum(sigma, axis=1) + self.b  # 计算预测概率
    return y_hat

def predict(self, X):
    r = self.predict_proba(X)  # 预测概率
    r[r>0]=1
    r[r<=0]=-1
    r = self.biary_encoder.inverse_transform(r)  # 将预测概率转换为标签
    return r

定义支持向量机类

def plot_boundary():

def generate_data(n_sample=50):
    x1 = np.random.rand(n_sample, 1) * 6 - 2
    y1 = x1 + np.random.normal(0, 0.7, (n_sample, 1))
    x2 = np.random.rand(n_sample, 1) * 6 - 3
    y2 = x2 + np.random.normal(0, 0.7, (n_sample, 1)) + 3
    c1 = np.hstack([x1, y1, np.ones_like(x1) * -1])
    c2 = np.hstack([x2, y2, np.ones_like(x2)])
    data_with_label = np.vstack([c1, c2])
    data, label = data_with_label[:, :-1], data_with_label[:, -1]

    return data, label

import matplotlib.pyplot as plt
np.random.seed(1)
X,y = generate_data(50)
kernels = [RBF_kernel(1.0),linear_kernel()]
plt.figure(figsize=(10,5))
for i,kernel in enumerate(kernels):
    plt.subplot(1,2,i+1)
    model = SVM(C=1, kernel=kernel,max_iter=1000)
    model.fit(X, y, tol=1e-5)
    sv = model.support_vectors

    plt.scatter(X[sv, 0], X[sv, 1], c=y[sv], marker='*',
                linewidths=0.5, edgecolors=(0, 0, 0, 1))
    plt.scatter(X[~sv, 0], X[~sv, 1], c=y[~sv],
                linewidths=0.5, edgecolors=(0, 0, 0, 1))
    xvals = np.linspace(-3, 6, 200)
    yvals = np.linspace(-3, 6, 200)
    xx, yy = np.meshgrid(xvals, yvals)

    pred = model.predict_proba(np.c_[xx.ravel(), yy.ravel()])
    zz = np.reshape(pred, xx.shape)
    plt.pcolormesh(xx, yy, zz, zorder=0)
    plt.contour(xx, yy, zz, levels=(-1, 0, 1), colors='w', linewidths=1.5, zorder=1, linestyles='solid')

    plt.xlim([
import numpy as npfrom utils import commonimport matplotlibpyplot as pltfrom tqdm import tqdmimport scipyspatialdistance as ssddef RBF_kernelsigma def kernelx y param x N x d

原文地址: http://www.cveoy.top/t/topic/iLXB 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录