3.SVM分类步骤
import sys
import os
from subprocess import *
from svmutil import *
from grid import *
3.1 读取或创建LIBSVM格式数据
- 创建数据
# Dense data
>>> y, x = [1,-1], [[1,0,1], [-1,0,-1]]
# Sparse data
>>> y, x = [1,-1], [{1:1, 3:1}, {1:-1,3:-1}]
>>> prob = svm_problem(y, x)
>>> param = svm_parameter('-t 0 -c 4 -b 1')
>>> m = svm_train(prob, param)
- 读取数据
#训练数据
>>> y, x = svm_read_problem('./svmguide1')
#测试数据
>>> y_t, x_t = svm_read_problem('./svmguide1.t')
对于自己创建的数据,需要按LIBSVM的数据格式保存,然后自行选择寻训练、测试样本,在tools文件夹中,提供了subset.py的子样本选择工具。原版的subset工具提供了两种子样本选择模式:
- mod 0:在所有样本中任选n个样本
- mod 1:一共选择n个子样本,但是分配给不同类的指标正比与各类样本数的大小,从而得到一个均衡化的子样本。
另外一种常用的样本选取方法是在各类中随机选取k个样本,为此笔者拓展了一个函数:
def random_selection_mod2(dataset, subset_size):
labels = [line.split(None,1)[0] for line in open(dataset)]
#预定义一个元素为list的字典
label_linenums = defaultdict(list)
#将样本按标签存在字典的list中
for i, label in enumerate(labels):
label_linenums[label] += [i]
l = len(labels)
ret = []
#在每类样本中选取k个训练样本,并存储标签
for label in label_linenums:
linenums = label_linenums[label]
label_size = len(linenums)
ret += [linenums[i] for i in random.sample(xrange(label_size), subset_size)]
return sorted(ret)
- 训练样本选取
filename = 'muufl'
subset_py = "./subset.py"
file = './'+filename+'_t.txt'
subfile = filename+'.sub'
cmd = '{0} -s 2 "{1}" 20 "{2}"'.format(
subset_py, file, subfile)
Popen(cmd, shell = True, stdout = PIPE).stdout
3.2 数据特征归一化
对高维数据来说,不同维度的特征可能具有不同数量级,大量级的特征会使小量级特征失效,导致分类精度下降。LIBSVM提供了svm-scale进行数据的预处理。
- svm-scale
Usage: svm-scale [options] data_filename
options:
-l lower : x scaling lower limit (default -1)
-u upper : x scaling upper limit (default +1)
-y y_lower y_upper : y scaling limits (default: no y scaling)
-s save_filename : save scaling parameters to save_filename
-r restore_filename : restore scaling parameters from restore_filename
- 归一化代码
#设置svm-scale.exe的路径
svmscale_exe = "../svm-scale"
file_train = filename+'.sub'
file_test = './'+filename+'_t.txt'
#对训练样本进行归一化
cmd = '{0} -l 0 -u 1 -s "{1}.range" "{2}" > "{3}.scale"'.format(
svmscale_exe, file_train, file_train, file_train)
Popen(cmd, shell = True, stdout = PIPE).communicate()
#对测试样本以同样的规则进行归一化
cmd = '{0} -r "{1}.range" "{2}" > "{3}.scale"'.format(
svmscale_exe, file_train, file_test, file_test)
Popen(cmd, shell = True, stdout = PIPE).communicate()
3.3 交叉验证寻找最佳参数
tools工具中提供了grid.py进行交叉验证参素选取,适用条件是C-SVM模式并采用RBF核。
- 语法: grid.py [grid_options] [svm_options] dataset
grid_options :
-log2c {begin,end,step | "null"} : set the range of c (default -5,15,2)
begin,end,step -- c_range = 2^{begin,...,begin+k*step,...,end}
"null" -- do not grid with c
-log2g {begin,end,step | "null"} : set the range of g (default 3,-15,-2)
begin,end,step -- g_range = 2^{begin,...,begin+k*step,...,end}
"null" -- do not grid with g
-v n : n-fold cross validation (default 5)
-svmtrain pathname : set svm executable path and name
-gnuplot {pathname | "null"} :
pathname -- set gnuplot executable path and name
"null" -- do not plot
-out {pathname | "null"} : (default dataset.out)
pathname -- set output file path and name
"null" -- do not output file
-png pathname : set graphic output file path and name (default dataset.png)
-resume [pathname] : resume the grid task using an existing output file (default pathname is dataset.out)
Use this option only if some parameters have been checked for the SAME data.
svm_options : additional options for svm-train
The program conducts v-fold cross validation using parameter C (and gamma)
= 2^begin, 2^(begin+step), ..., 2^end.
You can specify where the libsvm executable and gnuplot are using the
-svmtrain and -gnuplot parameters.
- 代码
#输入路径
grid_py = './grid.py'
gnuplot_exe = "/usr/bin/gnuplot"
svmtrain_exe = "../svm-train"
# 方法1
cmd = '{0} -svmtrain "{1}" -gnuplot "{2}" "{3}.scale"'.format(
grid_py, svmtrain_exe, gnuplot_exe, file_train)
f = Popen(cmd, shell = True, stdout = PIPE).stdout
#方法2
cmd = '{0} "{1}.scale"'.format(
grid_py, file_train)
f = Popen(cmd, shell = True, stdout = PIPE).stdout
#读取参数
line = ''
while True:
last_line = line
line = f.readline()
if not line: break
c,g,rate = map(float,last_line.split())
print('Best c={0}, g={1} CV rate={2}'.format(c,g,rate))
3.4 SVM分类
#训练model
y, x = svm_read_problem(file_train+".scale")
prob = svm_problem(y,x)
model = svm_train(prob, '-c {0} -g {1}'.format(c, g))
#用model分类
y_t, x_t = svm_read_problem(file_test+".scale")
p_labs, p_acc, p_vals = svm_predict(y_t, x_t, model)
#评价
(ACC, MSE, SCC) = evaluations(y_t, p_labs)
print('ACC={0}, MSE={1}, SCC={2}'.format(ACC,MSE,SCC))