使用libsvm进行简单分类

使用libsvm进行简单分类

参考:http://blog.csdn.net/xuxiatian/article/details/53736549

https://www.cnblogs.com/codingmengmeng/p/6256382.html

http://blog.csdn.net/u013634684/article/details/49646311

http://blog.csdn.net/longxinchen_ml/article/details/50521933

1.安装:

先从libsvm官网下载并解压,得到这个。

img

本来想在vs2015上编译运行libsvm,结果不行,所以最后就以python和exe的方式来使用libsvm。

我忘记了在那里看到的一篇文章说要用vs的命令行工具将libsvm.dll重新编译成64位系统可使用的动态链接库,我之前编译完了,所以我把64位系统可用的libsvm.dll上传到百度云上,需要的同学可以下载一下。

链接: https://pan.baidu.com/s/1c3Ok6wo 密码: uk4m

下载完之后要把这个libsvm.dll拷贝到 C:\Windows\System32 目录下。

另外,以python的方式使用libsvm非常方便,所以我将 libsvm-3.22\python 目录下的 svmutil.py 和 svm.py 拷贝到我python安装目录下的 Lib\site-packages 里面,然后尝试导入svm,成功即可调用它的功能了。

from svmutil import *
from svm import *

img

作为新手的我对libsvm的基本配置就到这里了,接下来是学习如何使用它。

2.使用:

进入 libsvm-3.22\windows 文件夹下有一个 svm-toy.exe 的演示,你可以变换颜色地在背景上添加点,最终svm会将你不同的颜色的点划分出一个分类边界出来。

img

这个是基本演示,但是作为学习,我们应当学会如何使用libsvm这个工具来对我们自己的数据进行分类,生成模型然后来使用。

那接下来看看,如何简单使用libsvm,我觉得数据格式很重要,所以先看看libsvm处理的数据的格式:

(这个是主目录下的样例heart_scale的片段)

+1 1:0.708333 2:1 3:1 4:-0.320755 5:-0.105023 6:-1 7:1 8:-0.419847 9:-1 10:-0.225806 12:1 13:-1 
-1 1:0.583333 2:-1 3:0.333333 4:-0.603774 5:1 6:-1 7:1 8:0.358779 9:-1 10:-0.483871 12:-1 13:1 
+1 1:0.166667 2:1 3:-0.333333 4:-0.433962 5:-0.383562 6:-1 7:-1 8:0.0687023 9:-1 10:-0.903226 11:-1 12:-1 13:1 
-1 1:0.458333 2:1 3:1 4:-0.358491 5:-0.374429 6:-1 7:-1 8:-0.480916 9:1 10:-0.935484 12:-0.333333 13:1 
-1 1:0.875 2:-1 3:-0.333333 4:-0.509434 5:-0.347032 6:-1 7:1 8:-0.236641 9:1 10:-0.935484 11:-1 12:-0.333333 13:-1 
-1 1:0.5 2:1 3:1 4:-0.509434 5:-0.767123 6:-1 7:-1 8:0.0534351 9:-1 10:-0.870968 11:-1 12:-1 13:1 
+1 1:0.125 2:1 3:0.333333 4:-0.320755 5:-0.406393 6:1 7:1 8:0.0839695 9:1 10:-0.806452 12:-0.333333 13:0.5 
+1 1:0.25 2:1 3:1 4:-0.698113 5:-0.484018 6:-1 7:1 8:0.0839695 9:1 10:-0.612903 12:-0.333333 13:1 
+1 1:0.291667 2:1 3:1 4:-0.132075 5:-0.237443 6:-1 7:1 8:0.51145 9:-1 10:-0.612903 12:0.333333 13:1 

以一行为例:

-1 1:0.458333 2:1 3:1 4:-0.358491 5:-0.374429

第一个数字是种类,代表这一行特征是属于哪一个类别的,接下来的1:0.458333 是指第一个特征的数值是0.458333, 依此类推,2:1 代表第二个特征的数值是1。

所以它所有的样本都是以这种形式为数据源,所以不论是训练数据或测试数据都是用这种形式的(修改源代码的方式另当别论),因为刚开始学习,所以我都是用python将自己的数据格式更改成libsvm规定的格式来进行使用。

libsvm的python使用很简单:

from svmutil import *
from svm import *
y, x = svm_read_problem('train.txt') 
yt, xt = svm_read_problem('test.txt')
model = svm_train(y, x ) #利用训练数据生产模型
p_label, p_acc, p_val = svm_predict(yt, xt, model) #利用模型预测测试数据
optimization finished, #iter = 5289
nu = 0.109058
obj = -6694.758270, rho = 3.652696
nSV = 8729, nBSV = 8719
Total nSV = 8729
Accuracy = 98.565% (19713/20000) (classification)

其中:

iter为迭代次数

nu 与前面的操作参数-n nu 相同,

obj为SVM文件转换为的二次规划求解得到的最小值,

rho 为判决函数的常数项b,

nSV 为支持向量个数,

nBSV为边界上的支持向量个数,

Total nSV为支持向量总个数(对于两类来说,因为只有一个分类模型 Total nSV = nSV ,但是对于多类,这个是各个分类模型的 nSV 之和)。

刚开始我只看得懂Accuracy = 98.565%,这些参数的优化的部分还没掌握,预计快了。

因为以前学习了线性分类器以及简单隐层对数据的分类,对于分类的思想有一定的理解。

以螺旋形的两种分类为例:

img

线性分类的相应的python代码如下:

#http://blog.csdn.net/u013634684/article/details/49646311
import numpy as np
from sklearn.linear_model import LogisticRegressionCV
import matplotlib.pyplot as plt

def spiral_line(K,N):
    np.random.seed(1)
    X = np.zeros((N*K,2)) 
    y = np.zeros(N*K, dtype='uint8') 
    for j in xrange(K):
        ix = range(N*j,N*(j+1))
        r = np.linspace(0.0,1,N) 
        t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 
        X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
        y[ix] = j
    return X,y

def plot_decision_boundary(pred_func):
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)

X, y = spiral_line(2,100)
clf = LogisticRegressionCV()
clf.fit(X, y)
plot_decision_boundary(lambda x: clf.predict(x))
plt.title("Logistic Regression")
plt.show()

img

关于简单隐层的python代码如下:

# http://blog.csdn.net/longxinchen_ml/article/details/50521933
import numpy as np
import matplotlib.pyplot as plt

def spiral_line(K,N):
    np.random.seed(1)
    X = np.zeros((N*K,2)) 
    y = np.zeros(N*K, dtype='uint8') 
    for j in xrange(K):
        ix = range(N*j,N*(j+1))
        r = np.linspace(0.0,1,N) 
        t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 
        X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
        y[ix] = j
    return X,y

def plot_decision_boundary(pred_func,X,y):
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)
    plt.show()

D=2
K=2
N=100
X,y=spiral_line(K,N)
h = 100 
W = 0.01 * np.random.randn(D,h)
b = np.zeros((1,h))
W2 = 0.01 * np.random.randn(h,K)
b2 = np.zeros((1,K))

step_size = 1e-0
reg = 1e-3 
num_examples = X.shape[0]
for i in xrange(10000):
  hidden_layer = np.maximum(0, np.dot(X, W) + b) 
  scores = np.dot(hidden_layer, W2) + b2
  exp_scores = np.exp(scores)
  probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
  corect_logprobs = -np.log(probs[range(num_examples),y])
  data_loss = np.sum(corect_logprobs)/num_examples
  reg_loss = 0.5*reg*np.sum(W*W) + 0.5*reg*np.sum(W2*W2)
  loss = data_loss + reg_loss
  if i % 1000 == 0:
    print "iteration %d: loss %f" % (i, loss)
  dscores = probs
  dscores[range(num_examples),y] -= 1
  dscores /= num_examples
  dW2 = np.dot(hidden_layer.T, dscores)
  db2 = np.sum(dscores, axis=0, keepdims=True)
  dhidden = np.dot(dscores, W2.T)
  dhidden[hidden_layer <= 0] = 0
  dW = np.dot(X.T, dhidden)
  db = np.sum(dhidden, axis=0, keepdims=True)
  dW2 += reg * W2
  dW += reg * W
  W += -step_size * dW
  b += -step_size * db
  W2 += -step_size * dW2
  b2 += -step_size * db2

hidden_layer = np.maximum(0, np.dot(X, W) + b)
scores = np.dot(hidden_layer, W2) + b2
predicted_class = np.argmax(scores, axis=1)
print 'training accuracy: %.2f' % (np.mean(predicted_class == y))
plot_decision_boundary(lambda x: np.argmax(np.dot(np.maximum(0, np.dot(x, W) + b), W2) + b2, axis=1),X,y)

使用简单隐层的分类效果还是不错的,能达到 training accuracy: 0.98。但是对于更多的特征,缺陷倒也是十分明显,我这里将之前的对坐标的分类用libsvm实现一下(代码简单,勿喷):

from svmutil import *
from svm import *
import numpy as np

#构建螺旋形,X是坐标的集合,y是标签的集合
def spiral_line(K,N):
    np.random.seed(1)
    X = np.zeros((N*K,2)) 
    y = np.zeros(N*K, dtype='uint8') 
    for j in xrange(K):
        ix = range(N*j,N*(j+1))
        r = np.linspace(0.0,1,N) 
        t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 
        X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
        y[ix] = j
    return X,y

#将训练集以文件的方式并按libsvm规定的数据格式输出保存
N=40000
X,y=spiral_line(2,N)
with open('trainLine.txt', 'w') as fp:
    for i in range(2*N):
        fp.write(str(y[i])+' '+"1:"+str(X[i][0])+' '+"2:"+str(X[i][1])+'\n')
fp.close() 

#将测试集以文件的方式并按libsvm规定的数据格式输出保存
N=10000
X,y=spiral_line(2,N)
with open('testLine.txt', 'w') as fp:
    for i in range(2*N):
        fp.write(str(y[i])+' '+"1:"+str(X[i][0])+' '+"2:"+str(X[i][1])+'\n')
fp.close()


y, x = svm_read_problem('train.txt')
yt, xt = svm_read_problem('test.txt')
model = svm_train(y, x )
p_label, p_acc, p_val = svm_predict(yt, xt, model)

最终生成的trainLine.txt内的数据以一定格式保存(片段如下):

0 1:0.0 2:0.0
0 1:-3.04875103099107e-06 2:2.481403571213165e-05
0 1:-5.262087164743738e-06 2:4.972359041097389e-05
0 1:-1.5949700236967846e-05 2:7.328634472327089e-05
0 1:1.7261698093737954e-05 2:9.850144058678161e-05
0 1:-5.54733633274877e-05 2:0.0001120200305321972
0 1:5.1374285596104965e-05 2:0.00014093192619729124
0 1:-2.6419012083530535e-05 2:0.0001729987488623951

结果如下:

optimization finished, #iter = 5289
nu = 0.109058
obj = -6694.758270, rho = 3.652696
nSV = 8729, nBSV = 8719
Total nSV = 8729
Accuracy = 98.565% (19713/20000) (classification)

只要训练数据足够,测试出来的结果都挺好的,我本来想像之前一样绘制出决策边界,但是这个变量的格式控制我不是很好把握,所以就没弄了,但能得到分类结果已经能完成很多工作了。

讲一下使用exe可执行文件进行训练生成模型的基本步骤(参考博客里有更详细的方法):

将之前的 testLine.txt 和 trainLine.txt 拷贝到 libsvm-3.22\windows 目录下面:

img

命令行进入到 libsvm-3.22\windows 文件夹下,执行 svm-train trainLine.txt 即可生成训练模型:

img

然后在当前目录下就会生成 trainLine.txt.model 的训练模型,当有测试数据的时候可以直接用这个模型来预测。

执行 svm-predict 来进行预测:

svm-predict testLine.txt trainLine.txt.model resule.txt

testLine.txt指测试数据存放位置,trainLine.txt.model 指调用的模型, resule.txt指预测结果存放位置,然后在当前文件夹下就会生成 resule.txt 点进去就都是预测的结果。

猜你喜欢

转载自blog.csdn.net/wuzebiao2016/article/details/79435770