用sklearn实现 , 也用自己手动实现了一下, 自己手动实现只能说是展示了算法过程 ,但是效果很差 , 没有找到原因, 希望大神斧正!!!
sklearn实现
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
# 构造数据
def create_data():
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
data = np.array(df.iloc[:100, [0, 1, -1]])
for i in range(len(data)):
if data[i,-1] == 0:
data[i,-1] = -1
# print(data)
return data[:,:2], data[:,-1]
X, y = create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
LinearSVC
使用的是线性核函数,k(x,v)=x* v, 只能对线性可分的数据进行分类
from sklearn.svm import LinearSVC
lsvc=LinearSVC(
C=1.0, # 在模型进行软间隔最大化时引入的惩罚发系数C,需要用交叉验证来找到合适的C,噪音点较多时,C选小一点
penalty ='l2', # 正则化系数,仅对线性拟合有用, 一般使用l2, 如果需要稀疏系数时, 可以选l1
dual=True, # 默认是True,即采用对偶形式优化,推荐True
class_weight=None, # 当数据集各类别的样本数严重不平衡的时候用'balanced',否则默认None
multi_class='ovr', # 多分类算法, 建议使用默认值
max_iter=1000, # 最大爹迭代次数, 默认1000
)
lsvc.fit(X_train,y_train)
print('原始问题中的系数:',lsvc.coef_)
print('原始问题中的截距:',lsvc.intercept_)
原始问题中的系数: [[ 1.30179585 -1.96015059]]
原始问题中的截距: [-1.00632957]
score=lsvc.score(X_test,y_test)
print('测试集上的准确率为:',score)
测试集上的准确率为: 1.0
SVC
可选核函数的svm分类器
from sklearn.svm import SVC
svc=SVC(
C=1.0,
kernel='rbf', # 默认的是rbf高斯核函数, 可选'linear'线性核函数,'poly'多项式核函数,'sigmoid'sigmoid核函数
degree=3,
gamma='auto', # 如果kernel选择的是出linear以外的其他函数,需要通过交叉验证对这三个值进行选择
coef0=0.0,
class_weight=None,
decision_function_shape='ovo', # 可选择ovo和ovr, ovr相对简单,分类效果差,建议使用ovo
cache_size=200, # 缓存大小会影响训练速度, 当电脑内存大时 ,建议使用500m- 1000m
max_iter=-1 # 迭代次数默认无限制,直到小于阈值为止
)
svc.fit(X_train,y_train)
print('支持向量的索引',svc.support_)
print('支持向量:',svc.support_vectors_)
print('每个类别的支持向量的数量:',svc.n_support_)
支持向量的索引 [ 5 11 12 19 26 58 59 65 2 21 22 23 43 46 49 50 63 64]
支持向量: [[5.4 3.4]
[5.7 3.8]
[5.8 4. ]
[4.9 3. ]
[4.8 3. ]
[4.5 2.3]
[5.4 3.4]
[4.8 3. ]
[5.7 2.9]
[4.9 2.4]
[5.7 3. ]
[5.6 3. ]
[7. 3.2]
[6. 3.4]
[5.1 2.5]
[5. 2. ]
[5. 2.3]
[5.9 3.2]]
每个类别的支持向量的数量: [ 8 10]
score=svc.score(X_test,y_test)
print("准确率为:",score)
准确率为: 1.0
NuSVC
from sklearn.svm import NuSVC
nusvc=NuSVC(
nu=0.5, # nu代表训练集训练的错误率的上限,或者说支持向量的百分比下限,取值范围为(0,1],默认是0.5.它和惩罚系数C类似,都可以控制惩罚的力度。
kernel='rbf',
degree=3,
gamma='auto', # 如果kernel选择的是出linear以外的其他函数,需要通过交叉验证对这三个值进行选择
coef0=0.0,
class_weight=None,
decision_function_shape='ovo', # 可选择ovo和ovr, ovr相对简单,分类效果差,建议使用ovo
cache_size=200, # 缓存大小会影响训练速度, 当电脑内存大时 ,建议使用500m- 1000m
max_iter=-1 # 迭代次数默认无限制,直到小于阈值为止
)
nusvc.fit(X_train,y_train)
print('支持向量的索引',nusvc.support_)
#print('支持向量:',nusvc.support_vectors_)
print('每个类别的支持向量的数量:',nusvc.n_support_)
支持向量的索引 [ 4 5 6 8 11 12 14 19 26 28 29 36 37 42 54 58 59 61 65 69 2 3 21 22
23 24 31 33 34 43 44 45 46 49 50 53 62 63 64 67]
每个类别的支持向量的数量: [20 20]
score=nusvc.score(X_test,y_test)
print("准确率为:",score)
准确率为: 1.0
手动实现
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import pandas as pd
class SVM(object):
def __init__(self,max_iterations,kernal='linear'):
self.max_iterations=max_iterations
self._kernal=kernal
def _init_params(self,X,Y):
self.m=X.shape[0]
self.n=X.shape[1]
self.X=X
self.Y=Y
self.b=0.0
self.alpha=np.ones(self.m)
self.E=[ self._E(i) for i in range(self.m)]
self.C=1.0
def _k(self,xi,xj):
if self._kernal=='linear':
return sum([xi[i]*xj[i] for i in range(self.n)])
def _g(self,i):
g=0
for j in range(self.m):
g+=self.alpha[j]*self.Y[j]*self._k(self.X[j],self.X[i])+self.b
return g
def _E(self,i):
E=self._g(i)-self.Y[i]
return E
def _KKT(self,i):
y_g=self.Y[i]*self._g(i)
if self.alpha[i]==0:
return y_g>1
elif self.alpha[i]>0 and self.alpha[i]<self.C:
return y_g==1
else:
return y_g<1
def _init_alpha(self):
index_list=[i for i in range(self.m) if 0<self.alpha[i]<self.C]
non_index_list=[i for i in range(self.m) if i not in index_list]
index_list.extend(non_index_list)
for i in index_list:
if self._KKT(i):
continue
E1=self.E[i]
if E1>=0:
j=min(range(self.m),key=lambda x:self.E[x])
else:
j=max(range(self.m),key=lambda x:self.E[x])
return (i,j)
def _compare(self,alpha2,L,H):
if alpha2>H:
return H
elif alpha2<L:
return L
else:
return alpha2
def fit(self,features,labels):
self._init_params(features,labels)
for iter in range(self.max_iterations):
i,j=self._init_alpha()
if self.Y[i]!=self.Y[j]:
L=max(0,self.alpha[j]-self.alpha[i])
H=min(self.C,self.C+self.alpha[j]-self.alpha[i])
elif self.Y[i]==self.Y[j]:
L=max(0,self.alpha[j]+self.alpha[i]-self.C)
H=min(self.C,self.alpha[j]+self.alpha[i])
E1=self.E[i]
E2=self.E[j]
eta=self._k(self.X[i],self.X[i])+self._k(self.X[j],self.X[j])-2*self._k(self.X[i],self.X[j])
if eta<=0:
continue
alpha2_new_unc=self.alpha[j]+self.Y[j]*(E2-E1)/eta
alpha2_new=self._compare(alpha2_new_unc,L,H)
alpha1_new=self.alpha[i]+self.Y[i]*self.Y[j]*(self.alpha[j]-alpha2_new)
b1=-E1 - self.Y[i]*self._k(self.X[i],self.X[i])*(alpha1_new-self.alpha[i])-self.Y[j]*self._k(self.X[j],self.X[i])*(alpha2_new-self.alpha[j])+self.b
b2=-E2 - self.Y[i]*self._k(self.X[i],self.X[j])*(alpha1_new-self.alpha[i])-self.Y[j]*self._k(self.X[j],self.X[j])*(alpha2_new-self.alpha[j])+self.b
if alpha1_new>0 and alpha1_new<self.C:
b_new=b1
elif alpha2_new>0 and alpha2_new<self.C:
b_new=b2
else:
b_new=(b1+b2)/2
self.alpha[i]=alpha1_new
self.alpha[j]=alpha2_new
self.b=b_new
self.E[i]=self.E[i]
self.E[j]=self.E[j]
return 'train done!'
def predict(self,data):
result=0
for i in range(self.m):
result+=self.alpha[i]*self.Y[i]*self._k(self.X[i],data)+self.b
return 1 if result>0 else -1
def score(self,data,labels):
Y_pred=[]
for i in range(len(data)):
y_pred=self.predict(data[i])
Y_pred.append(y_pred)
Y_pred=np.array(Y_pred)
score=1-len(labels[labels+Y_pred==0])/len(labels)
return score
X, y = create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
max_iterations=200
svm=SVM(max_iterations)
svm.fit(X_train,y_train)
score=svm.score(X_test,y_test)
print(score)
0.76
完整代码:https://github.com/TaoistNie/The-road-to-ML/tree/master/SVM