Machine Learning 之 SVM实现(个人认为最好的算法)

SVM.py

#coding=utf-8
"""
      主要思想及算法流程来自李航的《统计学习方法》
      《理解SVM的三重境界》
      yi={1,-1}
      难点:
      KKT条件
      SMO算法
"""
import time
import random
import numpy as np
import math
import copy
a=np.matrix([[1.2,3.1,3.1]])
#print a.astype(int)
#print a.A

class SVM:
      def __init__(self,data,kernel,maxIter,C,epsilon):
            self.trainData=data
            self.C=C  #惩罚因子
            self.kernel=kernel
            self.maxIter=maxIter
            self.epsilon=epsilon
            self.a=[0 for i in range(len(self.trainData))]
            self.w=[0 for i in range(len(self.trainData[0][0]))]
            self.eCache=[[0,0] for i in range(len(self.trainData))]
            self.b=0
            self.xL=[self.trainData[i][0] for i in range(len(self.trainData))]
            self.yL=[self.trainData[i][1] for i in range(len(self.trainData))]

      def train(self):
            #support_Vector=self.__SMO()
            self.__SMO()
            self.__update()

      def __kernel(self,A,B):
            #核函数 是对输入的向量进行变形 从低维映射到高维度
            res=0
            if self.kernel=='Line':
                  res=self.__Tdot(A,B)
            elif self.kernel[0]=='Gauss':
                  K=0
                  for m in range(len(A)):
                       K+=(A[m]-B[m])**2 
                  res=math.exp(-0.5*K/(self.kernel[1]**2))
            return res


      def __Tdot(self,A,B):
            res=0
            for k in range(len(A)):
                  res+=A[k]*B[k]
            return res


      def __SMO(self):
            #SMO是基于 KKT 条件的迭代求解最优化问题算法
            #SMO是SVM的核心算法
            support_Vector=[]
            self.a=[0 for i in range(len(self.trainData))]
            pre_a=copy.deepcopy(self.a)
            for it in range(self.maxIter):
                  flag=1
                  for i in range(len(self.xL)):
                        #print self.a
                        #更新 self.a  使用 机器学习实战的求解思路
                        #计算 j更新
                        diff=0
                        self.__update()
                        #选择有最大误差的j 丹麦理工大学的算法是 对j在数据集上循环, 随机选取i 显然效率不是很高
                        #机器学习实战 硬币书表述正常 代码混乱且有错误 启发式搜索
                        Ei=self.__calE(self.xL[i],self.yL[i])
                        j,Ej=self.__chooseJ(i,Ei)
                        #计算 L H
                        (L,H)=self.__calLH(pre_a,j,i)
                        #思路是先表示为self.a[j] 的唯一变量的函数 再进行求导(一阶导数=0 更新)
                        kij=self.__kernel(self.xL[i],self.xL[i])+self.__kernel(self.xL[j],self.xL[j])-2*self.__kernel(self.xL[i],self.xL[j])
                        #print kij,"aa"
                        if(kij==0):
                              continue
                        self.a[j] = pre_a[j] + float(1.0*self.yL[j]*(Ei-Ej))/kij
                        #下届是L 也就是截距,小于0时为0
                        #上届是H 也就是最大值,大于H时为H
                        self.a[j] = min(self.a[j], H)
                        self.a[j] = max(self.a[j], L)
                        #self.a[j] = min(self.a[j], H)
                        #print L,H
                        self.eCache[j]=[1,self.__calE(self.xL[j],self.yL[j])]
                        self.a[i] = pre_a[i]+self.yL[i]*self.yL[j]*(pre_a[j]-self.a[j])
                        self.eCache[i]=[1,self.__calE(self.xL[i],self.yL[i])]
                        diff=sum([abs(pre_a[m]-self.a[m]) for m in range(len(self.a))])
                        #print diff,pre_a,self.a
                        if diff < self.epsilon:
                              flag=0
                        pre_a=copy.deepcopy(self.a)
                  if flag==0:
                        print it,"break"
                        break

            #return support_Vector

      def __chooseJ(self,i,Ei):
            self.eCache[i]=[1,Ei]
            chooseList=[]
            #print self.eCache
            #从误差缓存中得到备选的j的列表 chooseList  误差缓存的作用:解决初始选择问题
            for p in range(len(self.eCache)):
                  if self.eCache[p][0]!=0 and p!=i:
                        chooseList.append(p)
            if len(chooseList)>1:
                  delta_E=0
                  maxE=0
                  j=0
                  Ej=0
                  for k in chooseList:
                        Ek=self.__calE(self.xL[k],self.yL[k])
                        delta_E=abs(Ek-Ei)
                        if delta_E>maxE:
                              maxE=delta_E
                              j=k
                              Ej=Ek
                  return j,Ej
            else:
                  #最初始状态
                  j=self.__randJ(i)
                  Ej=self.__calE(self.xL[j],self.yL[j])
                  return j,Ej

      def __randJ(self,i):
            j=i
            while(j==i):
                  j=random.randint(0,len(self.xL)-1)
            return j

      def __calLH(self,pre_a,j,i):
            if(self.yL[j]!= self.yL[i]):
                  return (max(0,pre_a[j]-pre_a[i]),min(self.C,self.C-pre_a[i]+pre_a[j]))
            else:
                  return (max(0,-self.C+pre_a[i]+pre_a[j]),min(self.C,pre_a[i]+pre_a[j]))

      def __calE(self,x,y):
            #print x,y
            y_,q=self.predict(x)
            return y_-y

      def __calW(self):
            self.w=[0 for i in range(len(self.trainData[0][0]))]
            for i in range(len(self.trainData)):
                  for j in range(len(self.w)):
                        self.w[j]+=self.a[i]*self.yL[i]*self.xL[i][j]

      def __update(self):
            #更新 self.b 和 self.w
            self.__calW()
            #得到了self.w 下面求b
            #print self.a
            maxf1=-99999
            min1=99999
            for k in range(len(self.trainData)):
                  y_v=self.__Tdot(self.w,self.xL[k])
                  #print y_v
                  if self.yL[k]==-1:
                        if y_v>maxf1:
                              maxf1=y_v
                  else:
                        if y_v<min1:
                              min1=y_v
            self.b=-0.5*(maxf1+min1)

      def predict(self,testData):
            pre_value=0
            #从trainData 改成 suport_Vector
            for i in range(len(self.trainData)):
                  pre_value+=self.a[i]*self.yL[i]*self.__kernel(self.xL[i],testData)
            pre_value+=self.b
            #print pre_value,"pre_value"
            if pre_value<0:
                  y=-1
            else:
                  y=1
            return y,abs(pre_value-0)

      def save(self):
            pass




def LoadSVM():
      pass

#coding=utf-8
from SVM import *

data=[
        [[1,1],1],
        [[2,1],1],
        [[1,0],1],
        [[3,7],-1],
        [[4,8],-1],
        [[4,10],-1],
      ]

testSVM.py


#如果为gauss核的话  ['Gauss',标准差]
svm=SVM(data,'Line',1000,0.02,0.001)
svm.train()
print svm.predict([4,0])
print svm.a
print svm.w
print svm.b
  • 2
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Scala 是一种功能强大的静态类型、面向对象和函数式编程语言,它非常适合在 Scala 中实现支持向量机(Support Vector Machine, SVM算法SVM 是一种常用的监督学习算法,尤其在分类和回归问题中表现出色,因为它能够找到最优超平面进行决策。 在 Scala 中实现 SVM,你可以使用开源库如 Smile(Scalable Machine Learning Library)或 Breeze(专为 Scala 设计的数值计算库),它们提供了现成的 SVM 实现和相关的工具。 以下是一个简单的步骤概述: 1. **引入库**:如果你还没安装,首先需要添加对应库到你的项目依赖中,例如在 SBT (Scala Build Tool) 项目中添加 Smile 或者 Breeze。 ```scala libraryDependencies += "com.github.haifengl" %% "smile-core" % "2.6.0" ``` 2. **数据预处理**:将数据集转换成适合 SVM 输入的格式,通常包括特征向量和对应的标签。 3. **模型创建**:使用 Smile 或 Breeze 的 SVM 类,如 `LinearSVC` 或 `SMO` 来创建模型。 ```scala import smile.classification._ import breeze.linalg.DenseVector val svm = LinearSVC() ``` 4. **训练模型**:使用数据集对模型进行训练。 ```scala val data = ... // 从文件或数据库读取的数据 val (inputs, labels) = data.map { case features, label => DenseVector(features), label }.unzip svm.train(inputs, labels) ``` 5. **预测和评估**:对新的数据点进行预测,并使用交叉验证等方法评估模型性能。 ```scala val testData = ... // 预测用的数据 val predictions = svm.predict(testData) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值