支持向量机(SVM)是一种流行的分类技术。虽然提出时间到现在有70来年了,但在90年代获得了很好的发展和扩展,在人像识别、文本分类、手写字符识别、生物信息学等模式识别问题中有得到应用。然而,对于不熟悉SVM的初学者来说,往往会因为错过了一些简单但重要的步骤而得到不理想的结果。
LIBSVM(A Library for Support Vector Machines)支持向量机库,是台湾大学林智仁(Lin Chih-Jen)教授等开发设计的一个简单、易于使用和快速有效的SVM模式识别与回归的软件包,是目前使用最广泛的支持向量机(SVM)包。包含标准SVM算法、概率输出、支持向量回归、多分类SVM等功能,其源代码由C编写,并有JAVA、Python、R、MATLAB等语言的调用接口、基于CUDA的GPU加速和其它功能性组件,例如多核并行计算、模型交叉验证等

1、安装SVM库

同样的,可以新建一个虚拟环境来进行全新安装
conda create -n mylibsvm python=3.7
激活环境
activate mylibsvm
安装时,依然建议带上豆瓣镜像,速度快

pip install libsvm-official -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
pip install -U liblinear-official -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

2、heart_scale数据集

2.1、下载并对数据集内容格式的熟悉

数据集的内容需符合LIBSVM格式的要求,实质是一个文本文件,我们打开看下,如图:

下载地址(里面还包括了自己制作数据集,后面有介绍):heart_scale数据集  

2.2、训练并预测 

代码都比较简单,导入libsvm库,加载数据集,进行训练即可

from libsvm.svmutil import *
y, x = svm_read_problem('heart_scale')
m = svm_train(y[:200], x[:200], '-c 4')
'''
*.*
optimization finished, #iter = 257
nu = 0.351161
obj = -225.628984, rho = 0.636110
nSV = 91, nBSV = 49
Total nSV = 91
'''

 看下预测的效果,总共是270个样本!

p_label, p_acc, p_val = svm_predict(y, x, m) #全部预测
#Accuracy = 89.2593% (241/270) (classification)

p_label, p_acc, p_val = svm_predict(y[10:], x[10:], m)#第10个开始预测
#Accuracy = 89.6154% (233/260) (classification)

其中svm_train第三个可选参数,内容如下(当然自己也可以help(svm_train)看到):

    options:
        -s svm_type : set type of SVM (default 0)
            0 -- C-SVC        (multi-class classification)
            1 -- nu-SVC        (multi-class classification)
            2 -- one-class SVM
            3 -- epsilon-SVR    (regression)
            4 -- nu-SVR        (regression)
        -t kernel_type : set type of kernel function (default 2)
            0 -- linear: u'*v
            1 -- polynomial: (gamma*u'*v + coef0)^degree
            2 -- radial basis function: exp(-gamma*|u-v|^2)
            3 -- sigmoid: tanh(gamma*u'*v + coef0)
            4 -- precomputed kernel (kernel values in training_set_file)
        -d degree : set degree in kernel function (default 3)
        -g gamma : set gamma in kernel function (default 1/num_features)
        -r coef0 : set coef0 in kernel function (default 0)
        -c cost : set the parameter C of C-SVC, epsilon-SVR, and nu-SVR (default 1)
        -n nu : set the parameter nu of nu-SVC, one-class SVM, and nu-SVR (default 0.5)
        -p epsilon : set the epsilon in loss function of epsilon-SVR (default 0.1)
        -m cachesize : set cache memory size in MB (default 100)
        -e epsilon : set tolerance of termination criterion (default 0.001)
        -h shrinking : whether to use the shrinking heuristics, 0 or 1 (default 1)
        -b probability_estimates : whether to train a model for probability estimates, 0 or 1 (default 0)
        -wi weight : set the parameter C of class i to weight*C, for C-SVC (default 1)
        -v n: n-fold cross validation mode
        -q : quiet mode (no outputs) 

其中-s svm_type预测类型,默认是c_svc,分类和回归,区别就是输出标签,分类是准确的离散值,比如说狗的品种,上面例子中的+1和-1,而回归是连续值,比如说预测房价:
Kaggle房价预测的练习(K折交叉验证)
线性回归(Linear Regression)模型的构建和实现

-t kernel_type默认是2,为径向基函数rbf(或叫高斯核函数),如果设置为0就是线性函数

3、实用函数

3.1、模型相关

除了svm_train训练模型之外,还有一种方式可以加载模型:

svm_save_model('heart_scale.model', m) #保存模型
m = svm_load_model('heart_scale.model') #加载模型
p_label, p_acc, p_val = svm_predict(y, x, m)
#Accuracy = 89.2593% (241/270) (classification)
ACC, MSE, SCC = evaluations(y, p_label)
#ACC:89.25925925925927,MSE:0.42962962962962964,SCC:0.6120173609153937

3.2、svm_node

构建节点,初始化特征索引与特征值

from libsvm.svm import *
idx=1
val=10
node = svm_node(idx, val)

3.3、gen_svm_nodearray

svm直接调用C接口,所有参数和返回值都是ctypes格式

from libsvm.svm import *
prob = svm_problem([1,-1], [{1:1, 3:1}, {1:-1,3:-1}])
param = svm_parameter('-c 4')
m = libsvm.svm_train(prob, param)
#这里的m是指向svm_model的ctypes指针,所以需要做转换
x0, max_idx = gen_svm_nodearray({1:1, 3:1})#转换成svm_nodearray,是ctypes的结构
print(list(x0)[0],list(x0)[1],list(x0)[2])#1:1 3:1 -1:0
print(max_idx)#3
label = libsvm.svm_predict(m, x0)

3.4、其余一些函数

svm_type = model.get_svm_type()
nr_class = model.get_nr_class()
class_labels = model.get_labels()#类别标签[1, -1]
support_vectors = model.get_SV()#支持向量[{1: 1.0, 3: 1.0}, {1: -1.0, 3: -1.0}]

4、安装虚拟环境

可视化一个演示示例,这样便于大家更直观感受。

为了在JupyterLab中显示,我们创建一个新的虚拟环境,先激活所在环境再进行相关安装:

activate mylibsvm
conda install -c conda-forge jupyterlab
conda install ipykernel
python -m ipykernel install --user --name=mylibsvm --display-name mylibsvm

可以查看是否安装成功:jupyter kernelspec list

然后就可以输入命令:jupyter lab,来到WEB界面进行交互了。

5、LIBSVM格式数据集

这里我们将从Excel读取内容,写入到一个符合LIBSVM格式的文件(实质是一个文本),自己来做一个数据集,可以先在EXCEL里面写入

然后就从EXCEL文件里面读取并写入到一个符合LIBSVM格式的文件即可 

代码如下:

from libsvm.svm import *
from libsvm.svmutil import *
import openpyxl
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

def gen_svmfile():
    wb = openpyxl.load_workbook("test/s.xlsx")
    sheet1 = wb['Sheet1']
    with open("test/s_scale", 'w') as f:
        for i in range(1,sheet1.max_row):
            midu = sheet1.cell(i+1,2).value
            tangfen = sheet1.cell(i+1,3).value
            youzhi = sheet1.cell(i+1,4).value
            line = str(youzhi) + " 1:" + str(midu) + " 2:" + str(tangfen)
            print(line)
            f.writelines(line + "\n")
gen_svmfile()
'''
1 1:0.697 2:0.46
1 1:0.774 2:0.376
1 1:0.634 2:0.264
1 1:0.608 2:0.318
1 1:0.556 2:0.215
1 1:0.403 2:0.237
1 1:0.481 2:0.149
1 1:0.437 2:0.211
0 1:0.666 2:0.091
0 1:0.243 2:0.267
0 1:0.245 2:0.057
0 1:0.343 2:0.099
0 1:0.639 2:0.161
0 1:0.657 2:0.198
0 1:0.36 2:0.37
0 1:0.593 2:0.042
0 1:0.719 2:0.103
'''

如果提示相关模块没有安装的情况,类似下面这样安装即可:

pip install openpyxl -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

6、分类可视化

有了数据集之后,我们来看下对水果是否优质进行分类,代码如下:

y, x = svm_read_problem("test/s_scale")
m = svm_train(y, x, '-t 0 -c 100')#线性函数
#m = svm_train(y, x, '-t 2 -c 100')#径向基函数
#m = svm_train(y, x, '-t 2 -c 10000')
x1 = [mapi[1] for mapi in x]
x2 = [mapi[2] for mapi in x]
x = np.c_[x1,x2]

np_x = np.asarray(x)
np_y = np.asarray(y)
N, M = 100, 100

x1_min, x2_min = np_x.min(axis=0)
x1_max, x2_max = np_x.max(axis=0)

x1_min -= 0.1
x2_min -= 0.1
x1_max += 0.1 
x2_max += 0.1

t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, M)
grid_x, grid_y = np.meshgrid(t1,t2)

grid = np.stack([grid_x.flat, grid_y.flat], axis=1)

y_fake = np.zeros((N*M,))
p_label, _, _ = svm_predict(y_fake, grid, m)

cm_light = mpl.colors.ListedColormap(['#DC143C', '#87CEEB'])#颜色更改用来区分下面散点图
plt.pcolormesh(grid_x, grid_y, np.array(p_label).reshape(grid_x.shape), cmap=cm_light)#cm_light直接换成'cool'也可以
#散点图,直观查看制作的那几个点的情况
plt.scatter(x[:,0], x[:,1], s=30, c=y, marker='o')

plt.show()

效果图(-t 0线性函数)svm_train(y, x, '-t 0 -c 100'):

径向基函数(-t 2高斯核函数):svm_train(y, x, '-t 2 -c 100'),效果图如下:

还可以通过提高参数c来提高分类的准确率svm_train(y, x, '-t 2 -c 10000')

7、np.c_和np.stack

代码当中有两个知识点附带说明下,常用来做数据变换的。
np.c_:拼接的作用,我们分别看下不同维度是如何做拼接的

#一维数组
a1=np.arange(10)
b1=np.arange(10,20)
print(a1,b1)#[0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19]
print(np.c_[a1,b1])
print(np.c_[a1,b1].shape)#(10, 2)


#二维数组
a2=np.arange(10).reshape(2,5)
b2=np.arange(10,20).reshape(2,5)
print(a2,b2)
'''
[[0 1 2 3 4]
 [5 6 7 8 9]] 

[[10 11 12 13 14]
 [15 16 17 18 19]]
'''
print(np.c_[a2,b2].shape)#(2, 10)

#另外一个相反的拼接就是np.r_
print(np.r_[a2,b2].shape)#(4, 5)

我们看形状就很明白了,哪个维度的值不变,哪个维度的值在增加。

np.stack:数组按指定维进行堆叠

所以这里我们只需要关注指定的维度,就能够知道如何堆叠:

#一维数组
a1=np.arange(10)
b1=np.arange(10,20)
print(a1,b1)
print(np.stack([a1,b1]))#默认是axis=0
print(np.stack([a1,b1],axis=0).shape)#(2, 10)
print(np.stack([a1,b1],axis=1).shape)#(10, 2)
#注意观察axis指定位置在第一维和第二维的区别。

#二维数组
a2=np.arange(10).reshape(2,5)
b2=np.arange(10,20).reshape(2,5)
print(a2,b2)
print(np.stack([a2,b2],axis=0).shape)#(2, 2, 5)
print(np.stack([a2,b2],axis=1).shape)#(2, 2, 5)
#这里形状一样,不过内容不一样:
#axis=0的情况
[[[ 0  1  2  3  4]
  [ 5  6  7  8  9]]

 [[10 11 12 13 14]
  [15 16 17 18 19]]]

#axis=1的情况
[[[ 0  1  2  3  4]
  [10 11 12 13 14]]

 [[ 5  6  7  8  9]
  [15 16 17 18 19]]]

官方站点:https://www.csie.ntu.edu.tw/~cjlin/libsvm/
A Practical Guide to Support Vector Classification(支持向量分类实用指南)
其他版本:https://pypi.org/project/libsvm-official/#files

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐