SVM支持向量机算法

参考资料:http://www.cppblog.com/sunrise/archive/2012/08/06/186474.html           
       http://blog.csdn.net/sunanger_wang/article/details/7887218

我的数据挖掘算法代码:https://github.com/linyiqun/DataMiningAlgorithm

介绍

svm(support vector machine)是一种用来进行模式识别,模式分类的机器学习算法。svm的主要思想可以概括为2点:(1)、针对线性可分情况进行分析。(2)、对于线性不可分的情况,通过使用核函数,将低维线性不可分空间转化为高维线性可分的情况,然后在进行分析。目前已经有实现好的svm的算法包,在本文的后半部分会给出我实现好的基于libsvm包的svm分类代码。

SVM算法原理

svm算法的具体原理得要分成2部分,一个是线性可分的情况,一个是线性不可分的情况,下面说说线性可分的情况:

线性可分的情况

下面是一个二维空间的形式:

中间的那条线就是划分的分割线,我们可以用f(X)=w*x+b,  w,x在这里都是向量的形式。向这样的分割线,只要稍稍移动一下,又会有一个正确的目标线,因此我们要找的一个目标解,当然是找出分割的临界条件。

比如上面所示的情况,最佳的分类情况,应该是上面的margin的大小最大的时候,保证了分类的最准确。这里省去了一些数学的推理证明。要使用下面这个最大化:

反过来说,就是要使分母位置最小:

就是让||w||最小,当然这里会有个限制条件,就是这个线的应该有分类的作用,也就是说,样本数据代入公式,至少会有分类,于是限制条件就来了:

s.t的意思是subject to,也就是在后面这个限制条件。这就是问题的最终表达形式。后面这个式子会经过一系列的转换,最终变成这个样子:

这个就是我们需要最终优化的式子。至此,得到了线性可分问题的优化式子。如果此时你问我如何去解这个问题,很抱歉的告诉你,我也不知道(悔恨当初高数没学好....)

线性不可分的情况

同样给出一张图:

我们只能找出这样的条曲线将ab这个条线段进行分割。这时,就用到了在开始部分介绍的4个核函数。

选择不同的核函数,可以生成不同的SVM,常用的核函数有以下4种:

⑴线性核函数K(x,y)=x·y;

⑵多项式核函数K(x,y)=[(x·y)+1]^d;

径向基函数K(x,y)=exp(-|x-y|^2/d^2)

⑷二层神经网络核函数K(x,y)=tanh(a(x·y)+b)

但是在有的时候为了数据的容错性和准确性,我们会加入惩罚因子C和ε阈值(保证容错性)

限制条件为:

上面为线性可分的情况,不可分的情况可通过核函数自动转为线性可分情况。在整个过程中,省去了主要的推理过程,详细的可以点击最上方提供的2个链接。

svm的算法实现

这里提供我利用libsvm库做一个模式分类。主要的过程为:

1、输入训练集数据。

2、提供训练集数据构建svm_problem参数。

3、设定svm_param参数中的svm类型和核函数类型。

4、通过svm_problem和svm_param构建分类模型model。

5、最后通过模型和测试数据输出预测值。

SVMTool工具类代码:

package DataMining_SVM;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import DataMining_SVM.libsvm.svm;
import DataMining_SVM.libsvm.svm_model;
import DataMining_SVM.libsvm.svm_node;
import DataMining_SVM.libsvm.svm_parameter;
import DataMining_SVM.libsvm.svm_problem;

/**
 * SVM支持向量机工具类
 *
 * @author lyq
 *
 */
public class SVMTool {
	// 训练集数据文件路径
	private String trainDataPath;
	// svm_problem对象,用于构造svm model模型
	private svm_problem sProblem;
	// svm参数,里面有svm支持向量机的类型和不同 的svm的核函数类型
	private svm_parameter sParam;

	public SVMTool(String trainDataPath) {
		this.trainDataPath = trainDataPath;

		// 初始化svm相关变量
		sProblem = initSvmProblem();
		sParam = initSvmParam();
	}

	/**
	 * 初始化操作,根据训练集数据构造分类模型
	 */
	private void initOperation(){

	}

	/**
	 * svm_problem对象,训练集数据的相关信息配置
	 *
	 * @return
	 */
	private svm_problem initSvmProblem() {
		List<Double> label = new ArrayList<Double>();
		List<svm_node[]> nodeSet = new ArrayList<svm_node[]>();
		getData(nodeSet, label, trainDataPath);

		int dataRange = nodeSet.get(0).length;
		svm_node[][] datas = new svm_node[nodeSet.size()][dataRange]; // 训练集的向量表
		for (int i = 0; i < datas.length; i++) {
			for (int j = 0; j < dataRange; j++) {
				datas[i][j] = nodeSet.get(i)[j];
			}
		}
		double[] lables = new double[label.size()]; // a,b 对应的lable
		for (int i = 0; i < lables.length; i++) {
			lables[i] = label.get(i);
		}

		// 定义svm_problem对象
		svm_problem problem = new svm_problem();
		problem.l = nodeSet.size(); // 向量个数
		problem.x = datas; // 训练集向量表
		problem.y = lables; // 对应的lable数组

		return problem;
	}

	/**
	 * 初始化svm支持向量机的参数,包括svm的类型和核函数的类型
	 *
	 * @return
	 */
	private svm_parameter initSvmParam() {
		// 定义svm_parameter对象
		svm_parameter param = new svm_parameter();
		param.svm_type = svm_parameter.EPSILON_SVR;
		// 设置svm的核函数类型为线型
		param.kernel_type = svm_parameter.LINEAR;
		// 后面的参数配置只针对训练集的数据
		param.cache_size = 100;
		param.eps = 0.00001;
		param.C = 1.9;

		return param;
	}

	/**
	 * 通过svm方式预测数据的类型
	 *
	 * @param testDataPath
	 */
	public void svmPredictData(String testDataPath) {
		// 获取测试数据
		List<Double> testlabel = new ArrayList<Double>();
		List<svm_node[]> testnodeSet = new ArrayList<svm_node[]>();
		getData(testnodeSet, testlabel, testDataPath);
		int dataRange = testnodeSet.get(0).length;

		svm_node[][] testdatas = new svm_node[testnodeSet.size()][dataRange]; // 训练集的向量表
		for (int i = 0; i < testdatas.length; i++) {
			for (int j = 0; j < dataRange; j++) {
				testdatas[i][j] = testnodeSet.get(i)[j];
			}
		}
		// 测试数据的真实值,在后面将会与svm的预测值做比较
		double[] testlables = new double[testlabel.size()]; // a,b 对应的lable
		for (int i = 0; i < testlables.length; i++) {
			testlables[i] = testlabel.get(i);
		}

		// 如果参数没有问题,则svm.svm_check_parameter()函数返回null,否则返回error描述。
		// 对svm的配置参数叫验证,因为有些参数只针对部分的支持向量机的类型
		System.out.println(svm.svm_check_parameter(sProblem, sParam));
		System.out.println("------------检验参数-----------");
		// 训练SVM分类模型
		svm_model model = svm.svm_train(sProblem, sParam);

		// 预测测试数据的lable
		double err = 0.0;
		for (int i = 0; i < testdatas.length; i++) {
			double truevalue = testlables[i];
			// 测试数据真实值
			System.out.print(truevalue + " ");
			double predictValue = svm.svm_predict(model, testdatas[i]);
			// 测试数据预测值
			System.out.println(predictValue);
		}
	}

	/**
	 * 从文件中获取数据
	 *
	 * @param nodeSet
	 *            向量节点
	 * @param label
	 *            节点值类型值
	 * @param filename
	 *            数据文件地址
	 */
	private void getData(List<svm_node[]> nodeSet, List<Double> label,
			String filename) {
		try {

			FileReader fr = new FileReader(new File(filename));
			BufferedReader br = new BufferedReader(fr);
			String line = null;
			while ((line = br.readLine()) != null) {
				String[] datas = line.split(",");
				svm_node[] vector = new svm_node[datas.length - 1];
				for (int i = 0; i < datas.length - 1; i++) {
					svm_node node = new svm_node();
					node.index = i + 1;
					node.value = Double.parseDouble(datas[i]);
					vector[i] = node;
				}
				nodeSet.add(vector);
				double lablevalue = Double.parseDouble(datas[datas.length - 1]);
				label.add(lablevalue);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

调用类:

/**
 * SVM支持向量机场景调用类
 * @author lyq
 *
 */
public class Client {
	public static void main(String[] args){
		//训练集数据文件路径
		String trainDataPath = "C:\\Users\\lyq\\Desktop\\icon\\trainInput.txt";
		//测试数据文件路径
		String testDataPath = "C:\\Users\\lyq\\Desktop\\icon\\testInput.txt";

		SVMTool tool = new SVMTool(trainDataPath);
		//对测试数据进行svm支持向量机分类
		tool.svmPredictData(testDataPath);
	}

}

输入文件的内容:

训练集数据trainInput.txt:

17.6,17.7,17.7,17.7,17.8
17.7,17.7,17.7,17.8,17.8
17.7,17.7,17.8,17.8,17.9
17.7,17.8,17.8,17.9,18
17.8,17.8,17.9,18,18.1
17.8,17.9,18,18.1,18.2
17.9,18,18.1,18.2,18.4
18,18.1,18.2,18.4,18.6
18.1,18.2,18.4,18.6,18.7
18.2,18.4,18.6,18.7,18.9
18.4,18.6,18.7,18.9,19.1
18.6,18.7,18.9,19.1,19.3

测试数据集testInput.txt:

18.7,18.9,19.1,19.3,19.6
18.9,19.1,19.3,19.6,19.9
19.1,19.3,19.6,19.9,20.2
19.3,19.6,19.9,20.2,20.6
19.6,19.9,20.2,20.6,21
19.9,20.2,20.6,21,21.5
20.2,20.6,21,21.5,22

输出为:

null
------------检验参数-----------
..................*
optimization finished, #iter = 452
nu = 0.8563102916247203
obj = -0.8743284941628513, rho = 3.4446523008525705
nSV = 12, nBSV = 9
19.6 19.55027201691905
19.9 19.8455473606175
20.2 20.175593628188604
20.6 20.54041081963737
21.0 20.955769858833488
21.5 21.405899821905447
22.0 21.94590866154817

时间: 2024-08-26 14:17:04

SVM支持向量机算法的相关文章

跟我学算法-svm支持向量机算法推导

Svm算法又称为支持向量机,是一种有监督的学习分类算法,目的是为了找到两个支持点,用来使得平面到达这两个支持点的距离最近. 通俗的说:找到一条直线,使得离该线最近的点与该线的距离最远. 我使用手写进行了推导 求解实例 软间隔,通过设置C,使得目标函数的松弛因子发生变化,松弛因子越大,表示分类越不严格 高斯核变化做映射,指的是把低维转换成高维,解决低维不可分的情况 原文地址:https://www.cnblogs.com/my-love-is-python/p/9784226.html

支持向量机(SVM)算法

支持向量机(support vector machine)是一种分类算法,通过寻求结构化风险最小来提高学习机泛化能力,实现经验风险和置信范围的最小化,从而达到在统计样本量较少的情况下,亦能获得良好统计规律的目的.通俗来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,即支持向量机的学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解. 具体原理: 1. 在n维空间中找到一个分类超平面,将空间上的点分类.如下图是线性分类的例子. 2. 一般而言,一个点距离超平面的

【机器学习算法-python实现】svm支持向量机(2)—简化版SMO算法

(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景知识 通过上一节我们通过引入拉格朗日乗子得到支持向量机变形公式.详细变法可以参考这位大神的博客--地址 参照拉格朗日公式F(x1,x2,...λ)=f(x1,x2,...)-λg(x1,x2...).我们把上面的式子变型为: 约束条件就变成了: 下面就根据最小优化算法SMO(Sequential Minimal Optimization).找出距离分隔面最近的点,也就是支持向量集.如下图的蓝色点所示.

[分类算法] :SVM支持向量机

Support vector machines 支持向量机,简称SVM 分类算法的目的是学会一个分类函数或者分类模型(分类器),能够把数据库中的数据项映射给定类别中的某一个,从而可以预测未知类别. SVM是一种监督式学习的方法. 支持向量:支持或支撑平面上把两类类别划分开来的超平面的向量点 机:就是算法,机器学习常把一些算法看作是一个机器 超平面: n维空间中, 满足n元一次方程a1x1+a2x2+...+anxn=b的点(x1,x2,...,xn)的全体就叫空间的一张超平面(即广义平面). 具

【机器学习算法-python实现】svm支持向量机(3)—核函数

(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景知识 前面我们提到的数据集都是线性可分的,这样我们可以用SMO等方法找到支持向量的集合.然而当我们遇到线性不可分的数据集时候,是不是svm就不起作用了呢?这里用到了一种方法叫做核函数,它将低维度的数据转换成高纬度的从而实现线性可分. 可能有的人不明白为什么低维度的数据集转换成高维度的就可以实现线性可分,下面摘抄一个网上的例子解释一下.看下面这个图,我们设红色的区域是一组数据 ,而直线ab除了红色区域以

机器学习--支持向量机 (SVM)算法的原理及优缺点

一.支持向量机 (SVM)算法的原理 支持向量机(Support Vector Machine,常简称为SVM)是一种监督式学习的方法,可广泛地应用于统计分类以及回归分析.它是将向量映射到一个更高维的空间里,在这个空间里建立有一个最大间隔超平面.在分开数据的超平面的两边建有两个互相平行的超平面,分隔超平面使两个平行超平面的距离最大化.假定平行超平面间的距离或差距越大,分类器的总误差越小. 对于线性可分的支持向量机求解问题实际上可转化为一个带约束条件的最优化求解问题: 推理过程:      结果:

SVM -支持向量机原理详解与实践之四

SVM -支持向量机原理详解与实践之四 SVM原理分析 SMO算法分析 SMO即Sequential minmal optimization, 是最快的二次规划的优化算法,特使对线性SVM和稀疏数据性能更优.在正式介绍SMO算法之前,首先要了解坐标上升法. 坐标上升法(Coordinate ascent) 坐标上升法(Coordinate Ascent)简单点说就是它每次通过更新函数中的一维,通过多次的迭代以达到优化函数的目的. 坐标上升法原理讲解 为了更加通用的表示算法的求解过程,我们将算法表

SVM -支持向量机原理详解与实践之二

SVM -支持向量机原理详解与实践之二 SVM原理分析 以下内容接上篇. 拉格朗日对偶性(Largrange duality)深入分析 前面提到了支持向量机的凸优化问题中拉格朗日对偶性的重要性. 因为通过应用拉格朗日对偶性我们可以寻找到最优超平面的二次最优化, 所以以下可以将寻找最优超平面二次最优化(原问题),总结为以下几个步骤: 在原始权重空间的带约束的优化问题.(注意带约束) 对优化问题建立拉格朗日函数 推导出机器的最优化条件 最后就是在对偶空间解决带拉格朗日乘子的优化问题. 注:以上这个四

SVM -支持向量机原理详解与实践之三

SVM -支持向量机原理详解与实践之三 什么是核 什么是核,核其实就是一种特殊的函数,更确切的说是核技巧(Kernel trick),清楚的明白这一点很重要. 为什么说是核技巧呢?回顾到我们的对偶问题:     映射到特征空间后约束条件不变,则为:     在原始特征空间中主要是求,也就是和的内积(Inner Product),也称数量积(Scalar Product)或是点积(Dot Product),映射到特征空间后就变成了求,也就是和的映射到特征空间之后的内积,就如我前面所提到的在原始空间