在做SVM实际应用时,检索资料大多都推荐了libsvm,这是台湾大学教授林智仁等开发的一个包,查看了很多教程,大多表述模糊,经过自己动手实践摸索,终于有一点小体悟,分享并记录。
- 软件安装
libsvm实际上是一个linux工具,但其开发者也做了python包,本文主要讲述在linux上python里配置并使用libsvm。libsvm官方网站,下载tar.gz压缩包文件并解压tar -zxvf *.tar.gz
,进入解压后目录make
,进入解压后目录的python子目录中make
,此时解压目录下生成了libsvm.so.2文件,将其拷贝至自己python环境下的/lib/python3.6目录下,python子目录下的各*.py文件拷贝至自己python环境下的lib/python3.6/site-packages目录下,加入环境变量export PYTHONPATH=/home/user/envis/test/liblinear-2.30/python:$PAYTHONPATH
。进入jupyter notebook运行以下代码,无报错说明安装成功。liblinear安装方法同libsvm安装方法基本一致。
import svmutil
from svmutil import *
另外安装libsvm后还需安装gnuplot软件,下载后解压安装包,进入执行make
和make install
后,将路径加入环境变量。
- libsvm使用
如果不是一线搞算法研发的人员,有时候对于机器学习的算法原理其实掌握得并不是很透彻,工作中学习和了解一个算法,我们更想知道的是:该算法适用什么问题?如何应用?用哪个工具或包可以实现其应用?现在主要回答后两个问题。
- 首先libsvm需要输入什么数据:输入数据矩阵,每行代表一个样本,第一列为label,本文做二分类,此时第一列值可以为0和1或者为-1和+1,之后的每列数据为一个特征,每个特征需要有一个index。数据格式如下:
[label] [index1]:[value1] [index2]:[value2] ...
以下python代码可以把txt输入格式文件
[label] [value1] [value2]转换为[label] [index1]:[value1] [index2]:[value2]格式
readin = open('home/user/input_feature.txt', 'r')
#write data file
output = open('home/user/revise_feature.txt', 'r')
try:
the_line = readin.readline()
while the_line:
# delete the \n
the_line = the_line.strip('\n')
index = 0;
output_line = ''
for sub_line in the_line.split('\t'):
#the label col
if index == 0:
output_line = sub_line
#the features cols
if sub_line != 'NULL' and index != 0:
the_text = ' ' + str(index) + ':' + sub_line
output_line = output_line + the_text
index = index + 1
output_line = output_line + '\n'
output.write(output_line)
the_line = readin.readline()
finally:
readin.close()
- 获得合适格式的文件之后,以下代码可以建立svm分类器并输出其判别准确率。我们可以将数据集分为训练集和测试集,训练集建模并进行自判,测试集用模型判别。
y,x=svm_read_problem('home/user/revise_feature.txt')
m = svm_train(y, x, '-c 0.5 -g 0.0078125')
p_label, p_acc, p_val = svm_predict(y,x, m)
test_y,test_x =svm_read_problem('home/user/test_feature.txt')
p_label, p_acc, p_val = svm_predict(test_y,test_x, m)
-
libsvm建模优化
用以上方法做出的模型分类效果不佳,这时可以考虑建模优化问题。libsvm有以下几个可以考虑的地方。- svm-scale:功能是将所有特征默认normalization到[-1,1]范围,有参数可指定上下限。-s参数可将其缩放规则存在文件中。-r参数可指定按某种缩放规则缩放本次输入文件,实际应用中可将训练集的缩放规则用于测试集缩放。经normalization后的数据再用来建模。
svm-scale -l -10 -u 10 -s trian.range input.txt > out.txt
2. grid.py:在libsvm的tools目录下,有grid.py工具,功能是通过网格搜索寻找最佳的svm训练超参数c值和g值。输出结果会在终端显示,如果终端有X11转发功能,还会实时显示图片,经过网格搜索会给出最佳c值和g值,用于svm训练。但该方法并不能保证找出的c值和g值是合理的,还需判断。python grid.py input.txt
- libsvm一些参数解释
libsvm在训练时也可以直接使用命令行语句,而无需进入jupyter notebook。
svmtrain [options] input [model]
-s svm类型:SVM设置类型(默认0)
0 -- C-SVC:C-支持向量分类机;参数C为惩罚系数,C越大表示对错误分类的惩罚越大,适当的参数C对分类Accuracy很关键。
1 --v-SVC:v-支持向量分类机;由于C的选取比较困难,用另一个参数v代替C。C是“无意义”的,v是有意义的。(与C_SVC其实采用的模型相同,但是它们的参数C的范围不同,C_SVC采用的是0到正无穷,该类型是[0,1]。)
2 – 一类SVM:单类别-支持向量机,不需要类标号,用于支持向量的密度估计和聚类。
3 -- e -SVR:ε-支持向量回归机,不敏感损失函数,对样本点来说,存在着一个不为目标函数提供任何损失值的区域。
4 -- v-SVR:n-支持向量回归机,由于EPSILON_SVR需要事先确定参数,然而在某些情况下选择合适的参数却不是一件容易的事情。而NU_SVR能够自动计算参数。
显然,后两者是针对回归问题的,分类问题与回归问题最大的不同就是label,分类的label是类别,比如+1,-1,回归的label是目标值,可能为任意值。
- 总结
以上是一些基本用法以及不全面的总结,遗憾的是在我的测试数据上libsvm的效果不佳,经过normalization以及网格搜索最佳超参数后效果仍然较差,有待进一步摸索和学习。
- 背景知识补充
在做测试前也检索了不少资料。摘抄一部分资料,主要是关于libsvm到底适用于解决什么样的问题。
libsvm用来解决通用典型的分类问题,liblinear适用于大规模数据的线性模型和高维稀疏特征问题。
非线性分类不一定比线性分类器好,尤其是在样本极其有限而特征维度很高的情况下,因为这是kernel map通常不准确,很可能错误划分类别空间,乃至比线性分类效果更差。
有几点经验性的东西:
- 如果特征远远大于样本数,使用线性核就可以。
- 特征数和样本数都很大,如文档分类,一般使用线性核。
- 特征数远小于样本数,一般用RBF,若一定要用线性核,用liblinear时-s 2选项较好。
- 问题
经过一系列检索总结实践,我的数据集属于特征数远远大于样本数的数据集,但是在svm做分类时不知是否应该先进行特征工程来减少特征。另外就是截至目前,svm的方法在我的数据集上表现仍然很差,不知是因为svm不适用于解决该问题还是我的优化仍不到位。
探索是一个艰难的过程。永远没有能百分百分正确的模型。