python实现机器学习算法

‘’’
数据集:Mnist
训练集数量:60000(实际使用:10000)
测试集数量:10000(实际使用:1000)
层数:40

运行结果:
正确率:97%
运行时长:65m
‘’’

import time
import numpy as np

def loadData(fileName):
‘’’
加载文件
:param fileName:要加载的文件路径
:return: 数据集和标签集
‘’’
# 存放数据及标记
dataArr = []
labelArr = []
# 读取文件
fr = open(fileName)
# 遍历文件中的每一行
for line in fr.readlines():
# 获取当前行,并按“,”切割成字段放入列表中
# strip:去掉每行字符串首尾指定的字符(默认空格或换行符)
# split:按照指定的字符将字符串切割成每个字段,返回列表形式
curLine = line.strip().split(’,’)
# 将每行中除标记外的数据放入数据集中(curLine[0]为标记信息)
# 在放入的同时将原先字符串形式的数据转换为整型
# 此外将数据进行了二值化处理,大于128的转换成1,小于的转换成0,方便后续计算
dataArr.append([int(int(num) > 128) for num in curLine[1:]])
# 将标记信息放入标记集中
# 放入的同时将标记转换为整型

    # 转换成二分类任务
    # 标签0设置为1,反之为-1
    if int(curLine[0]) == 0:
        labelArr.append(1)
    else:
        labelArr.append(-1)
# 返回数据集和标记
return dataArr, labelArr

def calc_e_Gx(trainDataArr, trainLabelArr, n, div, rule, D):
‘’’
计算分类错误率
:param trainDataArr:训练数据集数字
:param trainLabelArr: 训练标签集数组
:param n: 要操作的特征
:param div:划分点
:param rule:正反例标签
:param D:权值分布D
:return:预测结果, 分类误差率
‘’’
# 初始化分类误差率为0
e = 0
# 将训练数据矩阵中特征为n的那一列单独剥出来做成数组。因为其他元素我们并不需要,
# 直接对庞大的训练集进行操作的话会很慢
x = trainDataArr[:, n]
# 同样将标签也转换成数组格式,x和y的转换只是单纯为了提高运行速度
# 测试过相对直接操作而言性能提升很大
y = trainLabelArr
predict = []

# 依据小于和大于的标签依据实际情况会不同,在这里直接进行设置
if rule == 'LisOne':
    L = 1
    H = -1
else:
    L = -1
    H = 1

# 遍历所有样本的特征m
for i in range(trainDataArr.shape[0]):
    if x[i] < div:
        # 如果小于划分点,则预测为L
        # 如果设置小于div为1,那么L就是1,
        # 如果设置小于div为-1,L就是-1
        predict.append(L)
        # 如果预测错误,分类错误率要加上该分错的样本的权值(8.1式)
        if y[i] != L:
            e += D[i]
    elif x[i] >= div:
        # 与上面思想一样
        predict.append(H)
        if y[i] != H:
            e += D[i]
# 返回预测结果和分类错误率e
# 预测结果其实是为了后面做准备的,在算法8.1第四步式8.4中exp内部有个Gx,要用在那个地方
# 以此来更新新的D
return np.array(predict), e

def createSigleBoostingTree(trainDataArr, trainLabelArr, D):
‘’’
创建单层提升树
:param trainDataArr:训练数据集数组
:param trainLabelArr: 训练标签集数组
:param D: 算法8.1中的D
:return: 创建的单层提升树
‘’’

# 获得样本数目及特征数量
m, n = np.shape(trainDataArr)
# 单层树的字典,用于存放当前层提升树的参数
# 也可以认为该字典代表了一层提升树
sigleBoostTree = {}
# 初始化分类误差率,分类误差率在算法8.1步骤(2)(b)有提到
# 误差率最高也只能100%,因此初始化为1
sigleBoostTree['e'] = 1

# 对每一个特征进行遍历,寻找用于划分的最合适的特征
for i in range(n):
    # 因为特征已经经过二值化,只能为0和1,因此分切分时分为-0.5, 0.5, 1.5三挡进行切割
    for div in [-0.5, 0.5, 1.5]:
        # 在单个特征内对正反例进行划分时,有两种情况:
        # 可能是小于某值的为1,大于某值得为-1,也可能小于某值得是-1,反之为1
        # 因此在寻找最佳提升树的同时对于两种情况也需要遍历运行
        # LisOne:Low is one:小于某值得是1
        # HisOne:High is one:大于某值得是1
        for rule in ['LisOne', 'HisOne']:
            # 按照第i个特征,以值div进行切割,进行当前设置得到的预测和分类错误率
            Gx, e = calc_e_Gx(trainDataArr, trainLabelArr, i, div, rule, D)
            # 如果分类错误率e小于当前最小的e,那么将它作为最小的分类错误率保存
            if e < sigleBoostTree['e']:
                sigleBoostTree['e'] = e
                # 同时也需要存储最优划分点、划分规则、预测结果、特征索引
                # 以便进行D更新和后续预测使用
                sigleBoostTree['div'] = div
                sigleBoostTree['rule'] = rule
                sigleBoostTree['Gx'] = Gx
                sigleBoostTree['feature'] = i
# 返回单层的提升树
return sigleBoostTree

def createBosstingTree(trainDataList, trainLabelList, treeNum=50):
‘’’
创建提升树
创建算法依据“8.1.2 AdaBoost算法” 算法8.1
:param trainDataList:训练数据集
:param trainLabelList: 训练测试集
:param treeNum: 树的层数
:return: 提升树
‘’’
# 将数据和标签转化为数组形式
trainDataArr = np.array(trainDataList)
trainLabelArr = np.array(trainLabelList)
# 没增加一层数后,当前最终预测结果列表
finallpredict = [0] * len(trainLabelArr)
# 获得训练集数量以及特征个数
m, n = np.shape(trainDataArr)

# 依据算法8.1步骤(1)初始化D为1/N
D = [1 / m] * m
# 初始化提升树列表,每个位置为一层
tree = []
# 循环创建提升树
for i in range(treeNum):
    # 得到当前层的提升树
    curTree = createSigleBoostingTree(trainDataArr, trainLabelArr, D)
    # 根据式8.2计算当前层的alpha
    alpha = 1 / 2 * np.log((1 - curTree['e']) / curTree['e'])
    # 获得当前层的预测结果,用于下一步更新D
    Gx = curTree['Gx']
    # 依据式8.4更新D
    # 考虑到该式每次只更新D中的一个w,要循环进行更新知道所有w更新结束会很复杂(其实
    # 不是时间上的复杂,只是让人感觉每次单独更新一个很累),所以该式以向量相乘的形式,
    # 一个式子将所有w全部更新完。
    # 该式需要线性代数基础,如果不太熟练建议补充相关知识,当然了,单独更新w也一点问题
    # 没有
    # np.multiply(trainLabelArr, Gx):exp中的y*Gm(x),结果是一个行向量,内部为yi*Gm(xi)
    # np.exp(-1 * alpha * np.multiply(trainLabelArr, Gx)):上面求出来的行向量内部全体
    # 成员再乘以-αm,然后取对数,和书上式子一样,只不过书上式子内是一个数,这里是一个向量
    # D是一个行向量,取代了式中的wmi,然后D求和为Zm
    # 书中的式子最后得出来一个数w,所有数w组合形成新的D
    # 这里是直接得到一个向量,向量内元素是所有的w
    # 本质上结果是相同的
    D = np.multiply(D, np.exp(-1 * alpha * np.multiply(trainLabelArr, Gx))) / sum(D)
    # 在当前层参数中增加alpha参数,预测的时候需要用到
    curTree['alpha'] = alpha
    # 将当前层添加到提升树索引中。
    tree.append(curTree)

    # -----以下代码用来辅助,可以去掉---------------
    # 根据8.6式将结果加上当前层乘以α,得到目前的最终输出预测
    finallpredict += alpha * Gx
    # 计算当前最终预测输出与实际标签之间的误差
    error = sum([1 for i in range(len(trainDataList)) if np.sign(finallpredict[i]) != trainLabelArr[i]])
    # 计算当前最终误差率
    finallError = error / len(trainDataList)
    # 如果误差为0,提前退出即可,因为没有必要再计算算了
    if finallError == 0:
        return tree
    # 打印一些信息
    print('iter:%d:%d, sigle error:%.4f, finall error:%.4f' % (i, treeNum, curTree['e'], finallError))
# 返回整个提升树
return tree

def predict(x, div, rule, feature):
‘’’
输出单独层预测结果
:param x: 预测样本
:param div: 划分点
:param rule: 划分规则
:param feature: 进行操作的特征
:return:
‘’’
# 依据划分规则定义小于及大于划分点的标签
if rule == ‘LisOne’:
L = 1
H = -1
else:
L = -1
H = 1

# 判断预测结果
if x[feature] < div:
    return L
else:
    return H

def test(testDataList, testLabelList, tree):
‘’’
测试
:param testDataList:测试数据集
:param testLabelList: 测试标签集
:param tree: 提升树
:return: 准确率
‘’’
# 错误率计数值
errorCnt = 0
# 遍历每一个测试样本
for i in range(len(testDataList)):
# 预测结果值,初始为0
result = 0
# 依据算法8.1式8.6
# 预测式子是一个求和式,对于每一层的结果都要进行一次累加
# 遍历每层的树
for curTree in tree:
# 获取该层参数
div = curTree[‘div’]
rule = curTree[‘rule’]
feature = curTree[‘feature’]
alpha = curTree[‘alpha’]
# 将当前层结果加入预测中
result += alpha * predict(testDataList[i], div, rule, feature)
# 预测结果取sign值,如果大于0 sign为1,反之为0
if np.sign(result) != testLabelList[i]:
errorCnt += 1
# 返回准确率
return 1 - errorCnt / len(testDataList)

if name == ‘main’:
# 开始时间
start = time.time()

# 获取训练集
print('start read transSet')
trainDataList, trainLabelList = loadData('../Mnist/mnist_train.csv')

# 获取测试集
print('start read testSet')
testDataList, testLabelList = loadData('../Mnist/mnist_test.csv')

# 创建提升树
print('start init train')
tree = createBosstingTree(trainDataList[:10000], trainLabelList[:10000], 40)

# 测试
print('start to test')
accuracy = test(testDataList[:1000], testLabelList[:1000], tree)
print('the accuracy is:%d' % (accuracy * 100), '%')

# 结束时间
end = time.time()
print('time span:', end - start)

程序运行结果

Copy
start read transSet
start read testSet
start init train
iter:0:40, sigle error:0.0804, finall error:0.0804
iter:1:40, sigle error:0.1448, finall error:0.0804
iter:2:40, sigle error:0.1362, finall error:0.0585
iter:3:40, sigle error:0.1864, finall error:0.0667
iter:4:40, sigle error:0.2249, finall error:0.0474
iter:5:40, sigle error:0.2634, finall error:0.0437
iter:6:40, sigle error:0.2626, finall error:0.0377
iter:7:40, sigle error:0.2935, finall error:0.0361
iter:8:40, sigle error:0.3230, finall error:0.0333
iter:9:40, sigle error:0.3034, finall error:0.0361
iter:10:40, sigle error:0.3375, finall error:0.0325
iter:11:40, sigle error:0.3364, finall error:0.0340
iter:12:40, sigle error:0.3473, finall error:0.0309
iter:13:40, sigle error:0.3006, finall error:0.0294
iter:14:40, sigle error:0.3267, finall error:0.0275
iter:15:40, sigle error:0.3584, finall error:0.0288
iter:16:40, sigle error:0.3492, finall error:0.0257
iter:17:40, sigle error:0.3506, finall error:0.0256
iter:18:40, sigle error:0.3665, finall error:0.0240
iter:19:40, sigle error:0.3769, finall error:0.0251
iter:20:40, sigle error:0.3828, finall error:0.0213
iter:21:40, sigle error:0.3733, finall error:0.0229
iter:22:40, sigle error:0.3785, finall error:0.0218
iter:23:40, sigle error:0.3867, finall error:0.0219
iter:24:40, sigle error:0.3850, finall error:0.0208
iter:25:40, sigle error:0.3823, finall error:0.0201
iter:26:40, sigle error:0.3825, finall error:0.0204
iter:27:40, sigle error:0.3874, finall error:0.0188
iter:28:40, sigle error:0.3952, finall error:0.0186
iter:29:40, sigle error:0.4018, finall error:0.0193
iter:30:40, sigle error:0.3889, finall error:0.0177
iter:31:40, sigle error:0.3939, finall error:0.0183
iter:32:40, sigle error:0.3838, finall error:0.0182
iter:33:40, sigle error:0.4021, finall error:0.0171
iter:34:40, sigle error:0.4119, finall error:0.0164
iter:35:40, sigle error:0.4093, finall error:0.0164
iter:36:40, sigle error:0.4135, finall error:0.0167
iter:37:40, sigle error:0.4099, finall error:0.0171
iter:38:40, sigle error:0.3871, finall error:0.0163
iter:39:40, sigle error:0.4085, finall error:0.0154
start to test
the accuracy is:97 %
time span: 3777.730945825577
在这里插入图片描述
链接:https://pan.baidu.com/s/1WSNaLl7Qe2-Hz56CQJ6yDw
提取码:sf8a
若链接失效可以加获取,还有一群志同道合的朋友一起学习一起进步,人生苦短,我们学python

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值