兵王问题详解+python实现

本文基于浙江大学胡浩基老师对于《机器学习》讲解的第二章  支持向量机 的实例:兵王问题的转述。胡老师使用了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]

                                                    newX = \frac{X - mean(X)}{std(X)}

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代表全部)
'''

出现了预料之外的错误,解决无法。下次继续

 

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值