今天做了一个用SVC分类经典Iris数据集的训练。
在数据预处理上出了点奇怪的岔子,对原始数据中的string转到float这步一直不成功,转换函数没错,用的是load.txt里面的converters,一直报错。但是被我机智(愚蠢)地手动处理完了,在csv文件里面用excel编辑直接手动批量转换,再导出txt。
其他步骤基本上按部就班。
import numpy as np
import pandas as pd
import sklearn.model_selection as sm
from sklearn.svm import SVC
import matplotlib as mpl
def iris_type(s):
it = {b'Iris-setosa': 0, b'Iris-versicolor': 1, b'Iris-virginica': 2}
return it[s]
path = '/Users/zj/Desktop/Iris数据集/iris3.txt'
data = np.loadtxt(path, dtype=float, delimiter=',')
# 用np.loadtxt('路径', dtype=数据类型, delimiter='分隔符')导入数据
print(data)
x, y = np.split(data, (4,), axis=1)
# 用np.split(数据集,(分割位置,),axis=1(水平分割)或者0(垂直分割))
print(x, y)
x_train, x_test, y_train, y_test = sm.train_test_split(x, y, random_state=1, train_size=0.6)
# 格式:x_train, x_test, y_train, y_test(四个顺序不能变) = sklearn,model_selection.train_test_split(x训练特征数据集,y训练结果数据集,random_state=随机种子,train_size=训练集占比)
clf = SVC(C=0.1, kernel='linear', decision_function_shape='ovr')
# clf = SVC(C=0.1, kernel='rbf', decision_function_shape='ovr')
# 用clf=SVC()做训练器,C越大训练越精确但是容易overfit,kernel=''就是训练的核函数,默认rbf高斯核,linear为线性核,decision_function_shape='ovo或ovr',ovo就是one vs one,一对一分类,ovr就是one vs other,一对多分类
clf.fit(x_train, y_train)
# 训练器.fit(训练特征数据集,训练结果数据集)
print('在训练集上的精度:', clf.score(x_train,y_train))
# clf.score(测试集,目标结果)得到用clf在测试集上分类得到的结果和目标结果相比的精度,这里得到的是用训练集训练出来的clf在训练集上的精度
y_hat = clf.predict(x_train)
# 用clf.predict(训练集)得到clf在该训练集上的分类结果,一般用y_hat表示
print(clf.score(x_train, y_hat))
# clf在x_train上分类出来的结果就是y_hat,目标结果也是y_hat所以精度当然是百分百
print('测试集上的精度', clf.score(x_test,y_test))
结果如下:
下面对结果绘图
用法见代码中备注,很详细:
x1_min, x1_max = x[:, 0].min(), x[:, 0].max()
# 这里指的是x1取x数据库里面第0列的数据(也就是第一个属性值),用x[:,0].min()取第0列数据里面的最小值,:冒号放在行的位置的意思就是取所有行
x2_min, x2_max = x[:, 1].min(), x[:, 1].max()
x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
# np.mgrid的用法见另一篇博客,这里相当于在x1的min和max之间分了200份,x2也是,分别表示两个二维坐标
# np.mgrid和np.linspace、np.meshgrid很像,以后了解
grid_test = np.stack((x1.flat, x2.flat), axis=1)
# np.stack(arras,axis=)将x1和x2推在一起得到二维坐标集
grid_hat = clf.predict(grid_test)
# 将grid_test坐标集(属性值)输入到clf中分类,得到输出y(花类别)
grid_hat = grid_hat.reshape(x1.shape)
# array1.reshape(array2.shape)将array1转化成array2的shape,便于画图
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
# 预先设定好颜色,做色卡,色卡=mpl.colors.ListedColormap(['颜色1','颜色2'...])
plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
# plt.pcolormesh(x1,x2,分类结果, cmap=颜色)用于自动画分色块分类图,x1和x2分别为横纵坐标为分类依据(但是该函数本身不具有分类功能),自动用cmap给的颜色给图像(x1-x2)依据分类结果分色块。
plt.scatter(x[:, 0], x[:, 1], c=y, edgecolors='k', s=50, cmap=cm_dark)
plt.xlabel(u'length', fontsize=13)
plt.ylabel(u'width', fontsize=13)
plt.xlim(x1_min, x1_max)
# 设定坐标轴区间范围,plt.xlim(始值,终值)
plt.ylim(x2_min, x2_max)
plt.title(u'iris SVM', fontsize=15)
# 常规plt画点图将数据点画出来
plt.show()
结果如下:
其中用到了np.grid和np.stack函数,我特意查了一下用法见另一篇博客:https://blog.csdn.net/weixin_46813313/article/details/113117583
总结:
- 用plt.pcolormesh画色块分类图很实用。
- 用np.grid和np.stack做坐标集几乎是所有数据绘图必备,原理要理解:
- 取出数据集各属性的max和min
- 在各属性max和min里面取样,grid,注意同shape
- 将各属性取得的样本值stack起来形成坐标(input)
- 将坐标带入clf,得到output
- 将output reshap成和属性一样, 作为另一个维
- 将input的各属性作为轴(横、纵),设置坐标轴范围,xlim和ylim
- 依据output绘图,用pcolormesh自动分类
- 再把样本点(input坐标)画上去