Python机器学习16——相关向量机(RVM)

news2025/8/3 22:02:59

本系列基本不讲数学原理,只从代码角度去让读者们利用最简洁的Python代码实现机器学习方法。


背景介绍

学机器学习的应该都知道支持向量机(SVM),这个方法在深度学习兴起之前算是很热门的分类方法,在机器学习里面,分类算法属SVM效果比较好,回归算法属随机森林(RF)的效果比较好。

虽然目前在深度学习神经网络算法的面前,它们的效果都已经黯然失色。但是学术界还是不少人使用这些传统的算法,因为数学理论强,很受老师们喜欢。

相关向量机(RVM)也是,它是一种基于贝叶斯框架的方法,核心思想是先验后验概率找最大似然,在科研领域中,关于使用RVM的文章不在少数。

但是由于我们最常用的sklearn库没有rvm的接口......所以没办法直接调用,这篇博客就是补充这个空白的。rvm使用Python实现相关向量机,并且做成我们最为熟悉的sklearn库接口,方便使用。

 


算法原理

我这里就不多介绍原理了,感兴趣同学直接看这个pdf,讲的还是不错的。

https://files-cdn.cnblogs.com/files/axlute/RVMExplained.pdf

 


代码实现

定义RVM的类,回归和分类都有。

"""Relevance Vector Machine classes for regression and classification."""
import numpy as np

from scipy.optimize import minimize
from scipy.special import expit

from sklearn.base import BaseEstimator, RegressorMixin, ClassifierMixin
from sklearn.metrics.pairwise import (
    linear_kernel,
    rbf_kernel,
    polynomial_kernel
)
from sklearn.multiclass import OneVsOneClassifier
from sklearn.utils.validation import check_X_y


class BaseRVM(BaseEstimator):

    """Base Relevance Vector Machine class.

    Implementation of Mike Tipping's Relevance Vector Machine using the
    scikit-learn API. Add a posterior over weights method and a predict
    in subclass to use for classification or regression.
    """

    def __init__(
        self,
        kernel='rbf',
        degree=3,
        coef1=None,
        coef0=0.0,
        n_iter=3000,
        tol=1e-3,
        alpha=1e-6,
        threshold_alpha=1e9,
        beta=1.e-6,
        beta_fixed=False,
        bias_used=True,
        verbose=False
    ):
        """Copy params to object properties, no validation."""
        self.kernel = kernel
        self.degree = degree
        self.coef1 = coef1
        self.coef0 = coef0
        self.n_iter = n_iter
        self.tol = tol
        self.alpha = alpha
        self.threshold_alpha = threshold_alpha
        self.beta = beta
        self.beta_fixed = beta_fixed
        self.bias_used = bias_used
        self.verbose = verbose

    def get_params(self, deep=True):
        """Return parameters as a dictionary."""
        params = {
            'kernel': self.kernel,
            'degree': self.degree,
            'coef1': self.coef1,
            'coef0': self.coef0,
            'n_iter': self.n_iter,
            'tol': self.tol,
            'alpha': self.alpha,
            'threshold_alpha': self.threshold_alpha,
            'beta': self.beta,
            'beta_fixed': self.beta_fixed,
            'bias_used': self.bias_used,
            'verbose': self.verbose
        }
        return params

    def set_params(self, **parameters):
        """Set parameters using kwargs."""
        for parameter, value in parameters.items():
            setattr(self, parameter, value)
        return self

    def _apply_kernel(self, x, y):
        """Apply the selected kernel function to the data."""
        if self.kernel == 'linear':
            phi = linear_kernel(x, y)
        elif self.kernel == 'rbf':
            phi = rbf_kernel(x, y, self.coef1)
        elif self.kernel == 'poly':
            phi = polynomial_kernel(x, y, self.degree, self.coef1, self.coef0)
        elif callable(self.kernel):
            phi = self.kernel(x, y)
            if len(phi.shape) != 2:
                raise ValueError(
                    "Custom kernel function did not return 2D matrix"
                )
            if phi.shape[0] != x.shape[0]:
                raise ValueError(
                    "Custom kernel function did not return matrix with rows"
                    " equal to number of data points."""
                )
        else:
            raise ValueError("Kernel selection is invalid.")

        if self.bias_used:
            phi = np.append(phi, np.ones((phi.shape[0], 1)), axis=1)

        return phi

    def _prune(self):
        """Remove basis functions based on alpha values."""
        keep_alpha = self.alpha_ < self.threshold_alpha

        if not np.any(keep_alpha):
            keep_alpha[0] = True
            if self.bias_used:
                keep_alpha[-1] = True

        if self.bias_used:
            if not keep_alpha[-1]:
                self.bias_used = False
            self.relevance_ = self.relevance_[keep_alpha[:-1]]
        else:
            self.relevance_ = self.relevance_[keep_alpha]

        self.alpha_ = self.alpha_[keep_alpha]
        self.alpha_old = self.alpha_old[keep_alpha]
        self.gamma = self.gamma[keep_alpha]
        self.phi = self.phi[:, keep_alpha]
        self.sigma_ = self.sigma_[np.ix_(keep_alpha, keep_alpha)]
        self.m_ = self.m_[keep_alpha]

    def fit(self, X, y):
        """Fit the RVR to the training data."""
        X, y = check_X_y(X, y)

        n_samples, n_features = X.shape

        self.phi = self._apply_kernel(X, X)

        n_basis_functions = self.phi.shape[1]

        self.relevance_ = X
        self.y = y

        self.alpha_ = self.alpha * np.ones(n_basis_functions)
        self.beta_ = self.beta

        self.m_ = np.zeros(n_basis_functions)

        self.alpha_old = self.alpha_

        for i in range(self.n_iter):
            self._posterior()

            self.gamma = 1 - self.alpha_*np.diag(self.sigma_)
            self.alpha_ = self.gamma/(self.m_ ** 2)

            if not self.beta_fixed:
                self.beta_ = (n_samples - np.sum(self.gamma))/(
                    np.sum((y - np.dot(self.phi, self.m_)) ** 2))

            self._prune()

            if self.verbose:
                print("Iteration: {}".format(i))
                print("Alpha: {}".format(self.alpha_))
                print("Beta: {}".format(self.beta_))
                print("Gamma: {}".format(self.gamma))
                print("m: {}".format(self.m_))
                print("Relevance Vectors: {}".format(self.relevance_.shape[0]))
                print()

            delta = np.amax(np.absolute(self.alpha_ - self.alpha_old))

            if delta < self.tol and i > 1:
                break

            self.alpha_old = self.alpha_

        if self.bias_used:
            self.bias = self.m_[-1]
        else:
            self.bias = None

        return self


class RVR(BaseRVM, RegressorMixin):

    """Relevance Vector Machine Regression.

    Implementation of Mike Tipping's Relevance Vector Machine for regression
    using the scikit-learn API.
    """

    def _posterior(self):
        """Compute the posterior distriubtion over weights."""
        i_s = np.diag(self.alpha_) + self.beta_ * np.dot(self.phi.T, self.phi)
        self.sigma_ = np.linalg.inv(i_s)
        self.m_ = self.beta_ * np.dot(self.sigma_, np.dot(self.phi.T, self.y))

    def predict(self, X, eval_MSE=False):
        """Evaluate the RVR model at x."""
        phi = self._apply_kernel(X, self.relevance_)

        y = np.dot(phi, self.m_)

        if eval_MSE:
            MSE = (1/self.beta_) + np.dot(phi, np.dot(self.sigma_, phi.T))
            return y, MSE[:, 0]
        else:
            return y


class RVC(BaseRVM, ClassifierMixin):

    """Relevance Vector Machine Classification.

    Implementation of Mike Tipping's Relevance Vector Machine for
    classification using the scikit-learn API.
    """

    def __init__(self, n_iter_posterior=50, **kwargs):
        """Copy params to object properties, no validation."""
        self.n_iter_posterior = n_iter_posterior
        super(RVC, self).__init__(**kwargs)

    def get_params(self, deep=True):
        """Return parameters as a dictionary."""
        params = super(RVC, self).get_params(deep=deep)
        params['n_iter_posterior'] = self.n_iter_posterior
        return params

    def _classify(self, m, phi):
        return expit(np.dot(phi, m))

    def _log_posterior(self, m, alpha, phi, t):

        y = self._classify(m, phi)

        log_p = -1 * (np.sum(np.log(y[t == 1]), 0) +
                      np.sum(np.log(1-y[t == 0]), 0))
        log_p = log_p + 0.5*np.dot(m.T, np.dot(np.diag(alpha), m))

        jacobian = np.dot(np.diag(alpha), m) - np.dot(phi.T, (t-y))

        return log_p, jacobian

    def _hessian(self, m, alpha, phi, t):
        y = self._classify(m, phi)
        B = np.diag(y*(1-y))
        return np.diag(alpha) + np.dot(phi.T, np.dot(B, phi))

    def _posterior(self):
        result = minimize(
            fun=self._log_posterior,
            hess=self._hessian,
            x0=self.m_,
            args=(self.alpha_, self.phi, self.t),
            method='Newton-CG',
            jac=True,
            options={
                'maxiter': self.n_iter_posterior
            }
        )

        self.m_ = result.x
        self.sigma_ = np.linalg.inv(
            self._hessian(self.m_, self.alpha_, self.phi, self.t)
        )

    def fit(self, X, y):
        """Check target values and fit model."""
        self.classes_ = np.unique(y)
        n_classes = len(self.classes_)

        if n_classes < 2:
            raise ValueError("Need 2 or more classes.")
        elif n_classes == 2:
            self.t = np.zeros(y.shape)
            self.t[y == self.classes_[1]] = 1
            return super(RVC, self).fit(X, self.t)
        else:
            self.multi_ = None
            self.multi_ = OneVsOneClassifier(self)
            self.multi_.fit(X, y)
            return self

    def predict_proba(self, X):
        """Return an array of class probabilities."""
        phi = self._apply_kernel(X, self.relevance_)
        y = self._classify(self.m_, phi)
        return np.column_stack((1-y, y))

    def predict(self, X):
        """Return an array of classes for each input."""
        if len(self.classes_) == 2:
            y = self.predict_proba(X)
            res = np.empty(y.shape[0], dtype=self.classes_.dtype)
            res[y[:, 1] <= 0.5] = self.classes_[0]
            res[y[:, 1] >= 0.5] = self.classes_[1]
            return res
        else:
            return self.multi_.predict(X)

好了,下面就可以像别的sklearn库里面的包一样使用了。

 


代码测试

我们对分类问题和回归问题都测试一下,并且和支持向量机做对比。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold, StratifiedKFold
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import plot_confusion_matrix
 
from sklearn.svm import SVC
from sklearn.svm import SVR
from sklearn.datasets import load_boston
from sklearn.datasets import load_breast_cancer

分类测试

分类我们使用经典的鸢尾花数据集

iris = load_breast_cancer() #加载数据
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test =  train_test_split(X, y, test_size=0.2, stratify=y, random_state=0)

scaler = StandardScaler()
scaler.fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)

支持向量机,不同核函数的效果:

#线性核函数
model = SVC(kernel="linear", random_state=123)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#二次多项式核
model = SVC(kernel="poly", degree=2, random_state=123)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#三次多项式
model = SVC(kernel="poly", degree=3, random_state=123)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#径向核
model = SVC(kernel="rbf", random_state=123)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#S核
model = SVC(kernel="sigmoid",random_state=123)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

相关向量机(RVM)效果:

model = RVC(kernel="linear")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

model = RVC(kernel="rbf")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

model = RVC(kernel="poly")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

 

效果差不多。 


回归测试

回归使用波士顿数据集

# Support Vector Regression with Boston Housing Data
X, y = load_boston(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1)
 
scaler = StandardScaler()
scaler.fit(X_train)
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)

支持向量机效果:(不同核函数)

 #线性核函数
model = SVR(kernel="linear")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#二次多项式核
model = SVR(kernel="poly", degree=2)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#三次多项式
model = SVR(kernel="poly", degree=3)
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#径向核
model = SVR(kernel="rbf")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))
#S核
model = SVR(kernel="sigmoid")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

 相关向量机(RVM)效果:

model = RVR(kernel="linear")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

model = RVR(kernel="rbf")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

model = RVR(kernel="poly")
model.fit(X_train_s, y_train)
print(model.score(X_test_s, y_test))

可以看到,在回归问题上,相关向量机比支持向量机的效果要好。

结论:

分类用SVM,回归用RVM 

当然我这里只用了两个sklearn自带的数据集测试,结论肯定有点武断,有兴趣的同学可以用于别的数据集,然后做多次K折交叉验证,进一步对比他们的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/15881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go: 通过Fiber构建微服务

文章目录简介1. 微服务2. Fiber&#xff1f;Fiber集成及使用1.安装fiber2. 简单使用3.简单实例小结简介 1. 微服务 微服务或微服务架构是一种体系结构风格&#xff0c;可以将应用程序构建成一个服务的集合&#xff1a; Maintainable 可维修Testable 可测试的Loosely coupled…

毫米波雷达基础知识系列——FFT

毫米波雷达基础知识系列——FFT及DSP优化实现FFT来源FFT为什么快FFT的种类基2FFT推导FFT来源 FFT来源于DFT离散傅里叶变换&#xff0c;DFT的计算公式为&#xff1a; X(k)∑n0N−1x(n)WNknX(k) \sum_{n0}^{N-1} x(n)W_{N}^{kn} X(k)n0∑N−1​x(n)WNkn​ 为什么不直接用DFT计算…

【 java 常用类】日期相关 API 操作

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

ZYNQ之FPGA学习----MMCM/PLL IP核使用实验

1 MMCM/PLL IP核介绍 PLL 的英文全称是 Phase Locked Loop&#xff0c;即锁相环&#xff0c;是一种反馈控制电路。PLL 对时钟网络进行系统级的时钟管理和偏移控制&#xff0c;具有时钟倍频、分频、相位偏移和可编程占空比的功能 Xilinx 7 系列器件中的时钟资源包含了时钟管理…

Kata3.0.0 x LifseaOS x 龙蜥内核三管齐下!带你体验最新的安全容器之旅

文/云原生SIG 北京时间 2022 年 10 月 10 日&#xff0c;袋鼠 RunD 安全容器&#xff08;Rust Kata runtime Dragonball VMM&#xff09;正式作为安全容器上游 Kata Container 3.0.0 release 版本的重要特性发布。 龙蜥体验包 安全容器作为龙蜥云原生重要项目&#xff0c;我…

EEG微状态预测并发fMRI动态功能连接状态

前言 静息态功能磁共振成像(rs-fMRI)测量的大脑功能连接在多个时间尺度上有所不同&#xff0c;并确定了循环的动态功能连接(dFC)状态。这些发现与不同的认知和病理状态有关&#xff0c;有可能作为疾病的生物标志物&#xff0c;但它们的神经基础仍然存在争议。在静息态EEG研究中…

docker常见问题汇总(持续更新中)

Docker pull 时报错如下&#xff1a; -bash-4.2# docker pull hub.yj.com/test/dep_client:test Error response from daemon: Get http://hub.yj.com/v2/: dial tcp: lookup hub.yj.com on 218.2.135.1:53: server misbehaving如下图&#xff1a; 原因解析&#xff1a; 本地…

【算法系列】非线性最小二乘-高斯牛顿法

系列文章目录 【算法系列】卡尔曼滤波算法 【算法系列】非线性最小二乘求解-直接求解法 【算法系列】非线性最小二乘求解-梯度下降法 【算法系列】非线性最小二乘-高斯牛顿法 文章目录 系列文章 文章目录 前言 一、牛顿法 二、高斯-牛顿法 1.由牛顿法推导 2.直接展…

深度学习入门(四十三)计算机视觉——锚框

深度学习入门&#xff08;四十三&#xff09;计算机视觉——锚框前言计算机视觉——锚框课件锚框IoU交并比赋予锚框符号使用非极大值抑制&#xff08;NMS&#xff09;输出总结教材1 生成多个锚框2 交并比&#xff08;IoU&#xff09;3 在训练数据中标注锚框3.1 将真实边界框分配…

UE5笔记【二】添加实体和材质。后处理体积影响全局和局部。

材质 将平面赋予材质&#xff0c;显示不同的样式和纹理。 除了拖拽方式&#xff1a;还可以下拉列表的方式选择。 添加实例对象 可以添加引擎中关于room的内容&#xff0c;使得上一篇中所讲内容&#xff0c;更加直白查看。比如光影。 构造一个场景。 后处理体积 用途&#xff…

显示控件——半圆进度条

该控件是指定一个图标&#xff08;半圆条&#xff09;&#xff0c;通过沿圆弧方向滑动实现视觉调节的效果。滑动范围对应变量地址数据&#xff0c;显示位置通过变量设定。可以配合“半圆进度条触控”触摸控件进行设置。 位置信息&#xff1a;控件在工程页面区域的位置 “X”“Y…

基于Java Web的汽车租赁系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

本地环境OPC数据读写模拟[Python3+OpenOPC+MatrikonOPCSimulation]

在win10本地环境下&#xff0c;通过python3和OpenOPC包与MatrikonOPCServer进行读写交互&#xff0c;模拟工厂数据读写 Python3 第一个坑&#xff0c;64位的Python似乎是和后面的OpenOPC不兼容&#xff0c;装了调用会出类似"OpenOPC.OPCError: Dispatch: 没有注册类"…

全球电子商务交易预计将在2022年假日季增长15%,消费者情绪乐观

• 感恩节到网购星期一之间的电子商务交易预计将增长10%• 新冠疫情限制措施解除后&#xff0c;旅游和票务行业持续保持强劲增长• 受通货膨胀与库存有限的共同影响&#xff0c;2022年的零售销售与2021年相比略显疲软• 欺诈者瞄准电子产品、旅游和活动等高价值品类&#xff0c…

Libuv实现帧率控制

Libuv实现帧率控制 概念 服务端帧率控制&#xff0c;保证在一段固定的时间内执行完所有事情&#xff08;包括网络I/O等&#xff09;&#xff0c;如果有空余时间&#xff0c;那么我们Sleep等待一段时间。如果超时我们需要追帧。 注意点 只要在程序中只有一个进程的情况下控制服…

pytorch MNIST 手写数字识别 + 使用自己的测试集 + 数据增强后再训练

文章目录1. MNIST 手写数字识别2. 聚焦数据集扩充后的模型训练3. pytorch 手写数字识别基本实现3.1完整代码及 MNIST 测试集测试结果3.1.1代码3.1.2 MNIST 测试集测试结果3.2 使用自己的图片进行测试3.2.1 测试图片预处理代码3.2.2 测试图片结果4. 数据增强4.1 手动读取 MNIST …

11月更新!一口气上线20+新功能,3D架构拓扑图更具趣味性

优维EasyOps全平台又双叒叕上新功能了&#xff01; 不瞒各位小伙伴 写今天这篇文章时 我的手一直在抖 是激动的&#xff0c;这次要介绍的更新太牛了 尽管鹿小U已经 非常认真地研究过这20多个新功能 仍然无法用文字描述出 这次功能批量上新 「厉害程度」的十分之一 啥也…

【软件工程】实验1

文章目录实验一 软件需求分析实验目的实验内容「软件开发文档管理」软件开发过程涉及的文档软件开发阶段开发过程文档「软件开发文档管理」需求获取1. 功能需求2. 非功能需求「软件开发文档管理」需求分析、需求规格说明1. 需求概述1.1 功能需求1.2 非功能需求2. 用例模型2.1 用…

中证1000期指上市带来的交易机会

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

玩转UE4/UE5动画系统:UE5的运行时(动态)重定向治好了我的精神内耗

本文参考了油管UP主&#xff1a;AngelV的教程 前言 UE5中新的动画资源的&#xff08;静态&#xff09;重定向方法比UE4好用很多&#xff0c;但这种静态的重定向方式依然很让人头疼&#xff0c;因为我们需要对于每一个需要的动画资源为每一个目标骨架生成一套资源备份。尽管个过…