本文基于浙江大学胡浩基老师对于《机器学习》讲解的第二章 支持向量机 的实例:兵王问题的转述。胡老师使用了MATLAB完成该项目,但是,本人对于matlab的使用还是在本科。现在更想精通python,接下来对问题阐述,并使用python对该问题进行解答。
问题描述
在国际象棋中,存在着一种残局的现象。剩余三子,分别是黑方的王,白方的王和兵,那么无论这三子在棋盘的布局如何,只有两种结果,白方胜利和逼和。这就是一个二分类问题。(对于两种结果的二分类问题,可以使用支持向量机进行解决。)如果想要听胡老师的讲解,点击如下链接。
机器学习_浙江大学_中国大学MOOC(慕课)
数据分布
关于这个数据集krkopt.data,大家可以在UCL上下载,或者去下载胡老师分享在githup上的内容。
UCL:UCI Machine Learning Repository
此处展示部分数据集内容:
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus']=False # 用来正常显示负号
# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有行
pd.set_option('display.max_rows', None)
# 设置value的显示长度为100,默认为50
pd.set_option('max_colwidth', 100)
# 设置1000列的时候才换行
pd.set_option('display.width', 1000)
data = pd.read_csv("E:/Chen Jingwen's folder/untitled/dateset_cjw/Krkopt/krkopt.data")
data.dropna(inplace = True)
print(data)
可以看出共有28056个数据(从0到28055)。其中数据有六维(类似a 1 b 3 c 2),最后的draw和(zero~sixteen)为标签。
对数据的解读:
类似a 1 b 3 c 2:代表:黑方的王在如图a1的位置,白方的 王在b3的位置,白兵在c2 的位置。
draw:代表此时只能和棋
zero~sixteen:代表此时黑方被将死所需要的步数。(zero代表此时轮到白方走,且已经将死)
数据预处理:
数据检查:
首先,我们对于数据进行一个简单的检查,查看是否有缺失项:
print(data.isnull().sum())
isnull()是用来判断各列是否有空值的方法。sum()再对出现的次数进行加和计算。
这里的第一行其实是各列的列名。由于没有设置,再使用dataframe时直接使用了第一行的数据作为列名。(这里偷个懒,不改了。)(但后续处理的时候修改a=1时,会出错,所以设置了以下的参数,使未命名的列名变为数字,但对于机器仍然从0开始计数。)
偷懒结果在后续的处理中出现了一个问题:
数据偏移:
在pandas读取数据集时将第一行作为了数据的列索引。导致数据只有28056个,实际上老师发的数据集里有28057个数据。使用header = None 参数,使得读取时,消除数据偏移的影响。
data = pd.read_csv("E:/Chen Jingwen's folder/untitled/dateset_cjw/Krkopt/krkopt.data",header=None)
我们也确实发现该数据集并没有空白项的情况,但是有没有缺少整行的情况。我们只需要进行计数即可。
print(data.iloc[:,0].size)
.iloc[:,0 ] 代表着输出dataframe中的第一列。.size 代表着 对输出的所有列的大小计算。
表明数据有28057个,也就是没有行缺失。ok,进入下一步。
修改数据和标签
措施:(1)将a~h 这8个字母,修改为1~8。
(2)由于是二分类问题。我们应该只设置两类标签,对此,将draw(和棋)设置为一类(正样本),将zero~sixteen(将死)设置为另一类(负样本)。
将正样本设置为 +1 ,负样本设置为-1。
因为机器只识别数字信息。
样本数据化
按照上述要求进行处理。
for i in [0,2,4]:
#这里是对数据集里相应的字母进行变形。
data.loc[data[i] == 'a',i] = 1
#这是一个二维数组,当识别第0,2,4列,且满足条件时,将对该列所有满足条件的数据进行修改。
data.loc[data[i] == 'b',i] = 2
data.loc[data[i] == 'c',i] = 3
data.loc[data[i] == 'd',i] = 4
data.loc[data[i] == 'e',i] = 5
data.loc[data[i] == 'f',i] = 6
data.loc[data[i] == 'g',i] = 7
data.loc[data[i] == 'h',i] = 8
#再对标签进行变形
data.loc[data[6] == 'draw',6] = 1
data.loc[data[6] != 'draw',6] = -1
打印出来并显示:
此时,整个数据集全部变为数值数据。即可利用支持向量机对其处理。
数据归一化
对数据进行归一化,使所有数据聚集在某个小范围里,但是其分布不会变化。
该数据集样本中有六个维度(除去标签+-1),对每个维度进行求解均值和标准差。
for i in range(6):
data[i] = (data[i] - data[i].mean()) / data[i].std()
data = data.iloc[:,:6]
data.iloc[:,:6]代表对数据集切片,两个冒号:第一个代表选择所有的行,第二个代表选择0~5这六维。
数据划分训练集和测试集
将原完整数据集划分为5000训练集,剩余的作为测试集。利用train_test_split()函数。此处需要原数据完全打乱,实现数据的随机性。
X_train, X_test, y_train, y_test = train_test_split(X_data,data[6],test_size = 0.821785001425719)
'''
train_tese_split()函数代表 对数据集进行训练集和测试集的划分。
X_train, X_test, y_train, y_test = train_test_split(train_data, train_target, test_size, random_state, shuffle)
变量描述:
X_train:划分的训练数据集
X_test:划分的训练测试集
y_train:划分的训练标签
y_test:划分的测试标签
test_size:分割比例,默认为0.25。代表测试集占完整数据集的比例
random_state:随机数种子应用于分割前对数据的洗牌。
可以是int,RandomState实例或None,默认值=None。
设成定值意味着,对于同一个数据集,只有第一次运行是随机的,
随后多次分割只要random_state相同,则划分结果也相同。
shuffle:是否在分割前对完整数据进行洗牌(打乱),默认为True,打乱
'''
寻找C和gamma的粗略范围
C和gamma的值需要进行测试,对于C:先选取了(100~200)的十个值(以10为间隔),
对于gamm:从1~10依次判断,但是需要除以10 。
设置初识正确率为0
Cscale = [i for i in range(100,201,10)]
'''
range(start,stop,[step])的使用方法
设定起始值和结束值,第三个参数代表每次的跨度。默认为1,不可为0.
这几个值都是人工设定的,由经验得来。也就是一个一个实验,找到最合适的组合值
'''
gammaScale = [i/10 for i in range(1,11)]
cv_scores = 0
数据建模以及交叉验证
本实验采用高斯核(rbf)进行建模,他有两个参数C和gamma。
交叉验证的相关知识可以看《机器学习》P26
#我们采用RBF 高斯核进行训练,参数为C 和 gamma。
for i in Cscale:
for j in gammaScale:
model = SVC(kernel = 'rbf', C = i, gamma = j)
scores = cross_val_score(model, X_train,y_train, cv = 5, scoring = 'accuracy')
if scores.mean() > cv_scores:
cv_scores = scores.mean()#此处就是找最佳的正确率(C和gamma的组合,主义这也只是粗略估计而已)
savei = i
savej = j*100#为了更精确的寻找gamma的值
'''
交叉验证:可缓解过拟合问题。并验证模型的表现,从而调参。
cross_val_score(estimator,
X, y=None,
scoring=None,
cv=None,
n_jobs=1,
verbose=0,
fit_params=None,
pre_dispatch=‘2*n_jobs’
)
变量描述:
estimator:估计方法对象(分类器)
X:数据特征(Features)
y:数据标签(Labels)
scoring:调用方法:
包括accuracy:预测值和真实值之间的正确率和
mean_squared_error等等)
默认为None。
cv:几折交叉验证
n_jobs:同时工作的cpu个数(-1代表全部)
'''
出现了预料之外的错误,解决无法。下次继续