educoder 练习答案 TensorFlow技术与平台应用

本文详述了TensorFlow的起源、特点、基本框架和实现流程,包括变量创建、保存与恢复、占位符使用以及矩阵运算。通过一系列实验,深入浅出地介绍了TensorFlow的使用,包括张量运算进阶、构建神经网络和队列操作。此外,还探讨了TensorFlow中的会话管理和数据广播机制,为初学者提供了全面的指导。
部署运行你感兴趣的模型镜像

1、TensorFlow初体验

一、起源

  1. 机器学习作为如今全球最为热门的计算机技术之一,可以让人们根据大量的数据来对未来的情况进行预测和判定。如今,全球科技巨头无不在在机器学习领域投入了大量的人力物力。Facebook,苹果,微软,百度,阿里巴巴,腾讯等行业巨擘无不参与其中。作为行业的领头羊 Google 公司自然也在其中。TensorFlow是 Google 多年以来内部开发建设的机器学习系统,并于2015 年面向全球进行了开源。
    TensorFlow

  2. TensorFlow 是谷歌基于 DistBelief 进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着 N 维数组,Flow(流)意味着基于数据流图的计算,TensorFlow 为张量从流图的一端流动到另一端计算过程。TensorFlow 是将复杂的数据结构传输至人工智能神经网中进行分析和处理过程的系统,可被用于语音识别、图像识别和文本处理等多项深度学习应用领域。

  3. TensorFlow 可以在 CPU 和 GPU 指令系统上运行,在操作系统方面,TensorFlow 支持 64 位的 Linux、MacOS、Windows 和移动平台Andriod 和 iOS。

  4. 截止到 2017 年九月 TensorFlow 支持 C, C++, Python 编程语言。目前,TensorFlow 的 Python 库更加易用,它提供了大量的辅助函数来简化构建图的工作,这些函数尚未被 C 和 C++ 库支持。但三种语言的会话库 (session libraries) 是一致的。本实训是基于 Python 语言开展的。

二、特性

使用 TensorFlow,我们必须明白 TensorFlow 的5点特性:

  1. 使用图 (graph) 来表示计算任务;
  2. 在被称之为会话 (session) 的上下文 (context) 中执行图;
  3. 使用 tensor 表示数据;
  4. 通过变量 (variable) 维护状态;
  5. 使用 feed 和 fetch 可以为任意的操作(arbitrary operation) 赋值或者从其中获取数据。

三、基本框架

  1. TensorFlow 是一个编程系统, 使用图来表示计算任务。 图中的节点被称之为 op (operation 的缩写)。一个 op 获得 0 个或多个 Tensor, 然后执行计算,结果是产生 0 个或多个 Tensor。 每个 Tensor 是一个类型化的多维数组。 例如, 你可以将一小组图像集表示为一个四维浮点数数组, 这四个维度分别是 [batch, height, width, channels]。
  2. 一个 TensorFlow 图描述了计算的过程。 为了进行计算, 图必须在会话里被启动。会话将图的 op 分发到诸如 CPU 或 GPU 之类的设备上,同时提供执行 op 的方法。这些方法执行后,将产生的 tensor 返回。 在 Python 语言中, 返回的 tensor 是 numpy ndarray 对象; 在 C 和 C++ 语言中,返回的 tensor 是 tensorflow::Tensor 实例。
    一般而言,Tensor的维度或者阶数要看张量的最左边有多少个左中括号,有n个,则这个张量就是n维张量,或者n阶张量。
    TensorFlow的运算一般分为两个阶段:1.定义计算图中的所有计算,2.执行计算(会话Session

四、实现流程

  1. TensorFlow 程序通常被分成两个阶段:构建阶段和执行阶段。 在构建阶段,op 的执行步骤被描述成一个图。在执行阶段,使用会话机制执行图中的 op;
  2. 例如,通常在构建阶段创建一个图来表示和训练神经网络,然后在执行阶段反复执行图中的训练 op。
    执行会话(Session)
    会话用来执行定义好的计算。会话可以调用和管理TF的所有资源。会话用完后需要关闭释放资源。
    会话的模式有两种:


第一种、显式调用会话生成函数和关闭会话函数。

#创建一个会话
sess = tf.Session()
#运行会话得到计算结果
sess.run(result)
#关闭会话,释放资源
sess.close()

第二种:运用上下文管理器来使用会话
with tf.Session() as session:
    session.run(result)
  

五、 实验

第1关变量创建和初始化

任务描述
新建一个名为 weights 的 Tensor 变量,里面的变量名为 big_weights,并进行初始化。

相关知识
当训练模型时,用变量来存储和更新参数。变量包含张量 (Tensor)存放于内存的缓存区。建模时,它们需要被明确地初始化,模型训练后,它们必须被存储到磁盘。这些变量的值,可在之后的模型训练和分析时被加载。

本关卡介绍 TensorFlow 类中的 tf.Variable 类。

创建
当创建一个变量时,将一个张量作为初始值,传入构造函数 Variable()。TensorFlow 提供了一系列操作符来初始化张量,初始值是常量或是随机值。
我们需要指定操作符张量的 shape。变量的 shape 通常是固定的,但 TensorFlow 提供了高级的机制,用来重新调整其行列数。

# Create two variables.
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")

调用 tf.Variable() 添加一些操作(Op, operation)到 graph:
一个 Variable 操作存放变量的值;
一个初始化 op 将变量设置为初始值,这事实上是一个 tf.assign 操作;
初始值的操作,例如示例中对 biases 变量的 zeros 操作也被加入了 graph。
tf.Variable 的返回值是 Python 的 tf.Variable 类的一个实例。

初始化
变量的初始化必须在模型的其它操作运行之前,先明确地完成。最简单的方法就是添加一个给所有变量初始化的操作,并在使用模型之前,首先运行那个操作;
使用 tf.global_variables_initializer() 添加一个操作,对变量做初始化。记得在完全构建好模型并加载之后,再运行那个操作。如下是代码展示:

# Create two variables.
weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="weights")
biases = tf.Variable(tf.zeros([200]), name="biases")
...
# Add an op to initialize the variables.
init_op = tf.global_variables_initializer()
# Later, when launching the model
with tf.Session() as sess:
  # Run the init operation.
     sess.run(init_op)
  ...
  # Use the model

用另一个变量初始化
我们有时候会需要用另一个变量的初始化值,给当前变量初始化。由于 tf.global_variables_initializer() 是并行地初始化所有变量,所以在有这种需求的情况下,我们需要尤其小心;
用其它变量的值初始化一个新的变量时,使用其它变量的 initialized_value() 属性。我们可以直接把已初始化的值,作为新变量的初始值,或者把它当做 tensor 计算得到一个值,赋予新变量。如下是代码展示:

# Create a variable with a random value.
**weights** = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="weights")
# Create another variable with the same value as 'weights'.
w2 = tf.Variable(**weights**.initialized_value(), name="w2")
# Create another variable with twice the value of 'weights'
w_twice = tf.Variable(**weights**.initialized_value() * 0.2, name="w_twice")

(1)编程要求
在右侧编辑器 Begin-End 区间补充代码,新建一个名为 weights 的 Tensor 变量,里面的变量名为 big_weights,并进行初始化。不要增删改本关的原有代码。

# -*- coding: utf-8 -*-
import tensorflow as tf

def variables_create():
    '''
    返回值:
    weights: 一个Tensor变量
    '''
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="big_weights")
    # ********** End **********#
    # 返回weights
    return weights

第2关变量保存

任务描述
学习如何保存模型的变量。

相关知识
保存和加载
最简单的保存和恢复模型的方法是,使用 tf.train.Saver 对象。 tf.train.Saver 对象可以有效地保存( save )和恢复( restore )变量。 Saver 对象提供了方法,来运行节点( ops ),并定义检查点文件的读写路径。

检查点文件
变量存储在二进制文件里,里面内容主要包含从变量名到 tensor 值的映射关系。当我们创建一个 Saver 对象时,我们可以选择性地,为检查点文件中的变量挑选变量名。默认情况下,变量名为每个变量 Variable.name 属性的值。

保存变量
TensorFlow 用 tf.train.Saver() 创建一个 Saver,从而用来管理模型中的所有变量。代码示例如下:

# Create some variables.
v1 = tf.Variable(..., name="v1")
v2 = tf.Variable(..., name="v2")
...
# Add an op to initialize the variables.
init_op = tf.initialize_all_variables()
# Add ops to save and restore all the variables.
saver = tf.train.Saver()
# Later, launch the model, initialize the variables, do some work, save the
# variables to disk.
with tf.Session() as sess:
      sess.run(init_op)
  # Do some work with the model.
  ..
  # Save the variables to disk.
 save_path = saver.save(sess, "/tmp/model.ckpt")
 print "Model saved in file: ", save_path

(2)编程要求
在右侧编辑器 Begin-End 区间补充代码,新建 tf.train.Saver() 对象和 tf.Session() 对象,并进行初始化,将 tf.Session() 对象保存,保存路径为save_dir/store.ckpt。不要增删改本关的原有代码。
####测试说明

# -*- coding: utf-8 -*-

import tensorflow as tf
import time


def variables_save():
    '''
    参数:
    weights: Tensor变量
    biase:   Tensor变量
    const123:Tensor变量    
    '''
    weights=tf.Variable(tf.random_normal([784,200]),name="weights")
    biase=tf.Variable(tf.zeros([1]),name='biases')
    const123=tf.Variable(([[3]]),name="jjdaren")
    init_op=tf.global_variables_initializer()
    sess=tf.Session()
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    saver=tf.train.Saver()
    sess.run(init_op)
    save_path=saver.save(sess,'save_dir/store.ckpt')
    # ********** End **********#

    sess.close()

第3关变量恢复

任务描述
学习如何恢复模型。

相关知识
保存和加载

最简单的保存和恢复模型的方法是,使用 tf.train.Saver 对象。 tf.train.Saver 对象可以有效地保存( save )和恢复( restore )变量。 Saver 对象提供了方法,来运行节点( ops ),并定义了检查点文件的读写路径。

检查点文件
变量存储在二进制文件里,里面内容主要包含从变量名到 tensor 值的映射关系。当我们创建一个 Saver 对象时,我们可以选择性地,为检查点文件中的变量挑选变量名。默认情况下,变量名为每个变量 Variable.name 属性的值。

恢复变量
用同一个 Saver 对象来恢复变量。注意,当我们从文件中恢复变量时,不需要事先对它们做初始化。


    # Create some variables.
v1 = tf.Variable(..., name="v1")
 v2 = tf.Variable(..., name="v2")
    ...
 # Add ops to save and restore all the variables.
saver = tf.train.Saver()

# Later, launch the model, use the saver to restore variables from disk, and
# do some work with the model.
with tf.Session() as sess:
  # Restore variables from disk.
      saver.restore(sess, "/tmp/model.ckpt")
 print "Model restored."
  # Do some work with the model
  ...

选择存储和恢复哪些变量
如果我们不给 tf.train.Saver() 传入任何参数,那么 Saver 将处理图 (graph) 中的所有变量。其中每一个变量,都以变量创建时传入的名称被保存。在检查点文件中,明确定义变量的名称是很有用的。
有时候仅保存和恢复模型的一部分变量很有用。再举个例子,我们也许训练得到了一个 5 层神经网络,现在想训练一个 6 层的新模型,可以将之前 5 层模型的参数,导入到新模型的前 5 层中。我们可以通过给 tf.train.Saver() 构造函数,传入 Python 字典,很容易地定义需要保存的变量及对应名称:键对应使用的名称,值对应被管理的变量。

(3)编程要求
在右侧编辑器 Begin-End 区间补充代码,新建 tf.train.Saver() 对象,恢复模型,模型路径为src/step3/save_dir1/store.ckpt。不要增删改本关的原有代码。

# -*- coding: utf-8 -*-

import tensorflow as tf
import time

def variable_restore():
    '''
    参数:
    const123:Tensor变量
    
    返回值:
    final_result: 一个Tensor类型变量
    '''
    const123 = tf.Variable(([[2]]), name="jjdaren")
    sess=tf.Session()
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    saver=tf.train.Saver()
    saver.restore(sess,'src/step3/save_dir1/store.ckpt')

    # ********** End **********#
    final_result=sess.run(const123)
    sess.close()
    #返回 final_result
    return final_result

第4关占位符使用–简单乘法实现

任务描述
学习如何使用占位符。

相关知识
占位符
在 Tensorflow 中,有时候我们并不清楚具体的输入数值,但我们在图中可以先占据一个位置。这就是所谓的占位符。

input1 = tf.placeholder("float", shape=[1, 2])
input2 = tf.placeholder("float", shape=[2, 1])

这里的 input1 和 input2 并不是特定的值,相反,他们都只是一个占位符,可以在 TensorFlow 运行某一计算时,根据该占位符输入具体的值。input1 和 input2 都是一个 2 维的浮点数张量。

feed_dic

我们该如何给占位符传入具体的参数呢? 答案很简单:启动图后,使用 feed_dict 参数,将数据传入 sess.run() 函数。

sess.run(product,feed_dict={input1:[[1,3],input2:[[1],[2]]})

矩阵乘法实现
在 Tensorflow 中,矩阵相乘较为简单,如下所示:

tf.matmul(input1,input2)

在一个会话中启动图
构造阶段完成后,我们才能启动图。 启动图的第一步是,创建一个 Session 对象,如果无任何创建参数,会话构造器将启动默认图。

启动默认图.

sess = tf.Session()

#调用 sess 的 'run()' 方法来执行矩阵乘法 op, 传入 'product' 作为该方法的参数. 
#上面提到, 'product' 代表了矩阵乘法 op 的输出, 传入它是向方法表明, 我们希望取回
#矩阵乘法 op 的输出.
#整个执行过程是自动化的, 会话负责传递 op 所需的全部输入. op 通常是并发执行的.
#函数调用 'run(product)' 触发了图中三个 op (两个常量 op 和一个矩阵乘法 op) 的执行.
# 返回值 'result' 是一个 numpy `ndarray` 对象.
product=tf.matmul(input1,input2)
result=sess.run(product,feed_dict={input1:[[1,3]],input2:[[1],[2]]})
print result
# ==> [[ 12.]]
# 任务完成, 关闭会话.
sess.close()

Session 对象在使用完后,需要关闭以释放资源。除了显式调用 close 外, 也可以使用 “with” 代码块,来自动完成关闭动作。

with tf.Session() as sess:
     result = sess.run([product])
     print result

(4)编程要求
在右侧编辑器 Begin-End 区间补充代码,利用占位符,启动 tensorflow 图,实现 input1*input2,并将结果保存到变量 result 中。

# -*- coding: utf-8 -*-

import tensorflow as tf
import time

def placer_holders():
    '''
    参数:
    input1:占位符
    input2:占位符
    input1_value:矩阵
    input2_value:矩阵
    返回值:
    result: 一个Tensor类型变量
    '''
    input1=tf.placeholder(dtype="float32",shape=[1,2])
    input2=tf.placeholder(dtype="float32",shape=[2,1])
    input1_value=[[2,4]]
    input2_value=[[1],[2]]
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    product=tf.matmul(input1_value,input2_value)
    with tf.Session() as sess:
        result=sess.run(product)

    # ********** End **********#
    #返回result
    return  result

2、Tensorflow入门–运算

(1)Tensorflow基本运算

相关知识点

5                               # 维度为0的Tensor,即标量
[1, 2, 3, 4]                    # 维度为1的Tensor,即一维数组
[[1, 2, 3, 4], [5, 6, 7, 8]]    # 维度为2的Tensor, 即二维矩阵
[[[1, 2, 3, 4]],[[5, 6, 7, 8]]] # 维度为3的Tensor,即3维空间矩阵
定义所有计算
import tensorflow as tf             #1
a = tf.constant(5, name="input_a")  #2
b = tf.constant(3, name="input_b")  #3
c = tf.multiply(a,b, name="mul_c")  #4
d = tf.add(a,b, name="add_d")       #5
e = tf.add(c,d, name="add_e")       #6

执行会话

执行会话(Session)
会话用来执行定义好的计算。会话可以调用和管理TF的所有资源。会话用完后需要关闭释放资源。

会话的模式有两种:

第一种、显式调用会话生成函数和关闭会话函数。

#创建一个会话
sess = tf.Session()
#运行会话得到计算结果
sess.run(result)
#关闭会话,释放资源
sess.close()
第二种:运用上下文管理器来使用会话

with tf.Session() as session:
    session.run(result)

答案

# -*- coding: utf-8 -*-
import tensorflow as tf
import os

os.environ["TF_CPP_MIN_LOG_LEVEL"]='3'

def simple_func(a,b,c,d):
    '''
    返回值:
    result: 一个标量值
    '''
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    a1=tf.constant(a)
    b1=tf.constant(b)
    ab=tf.add(a1,b1).eval()
    c1=tf.constant(c)
    d1=tf.constant(d)
    cd=tf.add(c1,d1).eval()
    result=tf.multiply(ab,cd).eval()
    return result
'''
    init_op = tf.global_variables_initializer()# 必须初始化所有变量

    sess = tf.Session()
    # 使用会话得到之前计算的结果。
    sess.run(ab)
    sess.run(cd)
    sess.run(result)
    # 关闭会话使得本次运行中使用到的资源可以被释放。
    sess.close()
''' 
    # ********** End **********#

    # 返回result

a = int(input())
b = int(input())
c = int(input())
d = int(input())

init_op = tf.global_variables_initializer()#并行地初始化所有变量


with tf.Session() as sess:
    sess.run(init_op)
    print(simple_func(a,b,c,d))

(2) Tensorflow常见矩阵操作

知识点
TensorFlow常见矩阵运算
Tensorflow支持常见的矩阵运算,包括矩阵乘,点积乘,矩阵转置,矩阵求逆等。

函数 功能描述`


tf.diag(diagonal, name=None)	  返回一个给定对角值的对角tensor
tf.diag_part(input, name=None)	 功能与tf.diag函数相反,返回对角阵的对角元素
tf.t\frace(x, name=None)	          	求一个2维tensor足迹,即对角值diagonal之和
tf.transpose(a, perm=None, name=’transpose’)	矩阵转置,行列互换
tf.matmul(a, b, transpose_a=False, transpose_b=False, a_is_sparse=False, b_is_sparse=False,name=None)				矩阵乘法
tf.matrix_determinant(input, name=None)	求矩阵的行列式
tf.matrix_inverse(input, adjoint=None, name=None)	求逆矩阵

答案

# -*- coding: utf-8 -*-
import tensorflow as tf
import os

os.environ["TF_CPP_MIN_LOG_LEVEL"]='3'

def count_trace(a):
    '''
    返回值:
    result: 一个标量值
    a为int 2
    '''
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    sess=tf.Session()
    v1=tf.fill([3,3],a)
    sess.run(v1)
    '''
    print(sess.run(v1))
    [[2 2 2]
    [2 2 2]
    [2 2 2]]
    '''

    a2=tf.trace(v1)
    sess.run(a2)
    '''
    print(sess.run(a2))
    6
    '''

    v2=tf.fill([3,3],a2)
    sess.run(v2)
    '''
    print(sess.run(v2))
    [[6 6 6]
    [6 6 6]
    [6 6 6]]
    '''

    res=v1+v2
    sess.run(res)
    '''
    print(sess.run(res))
    [[8 8 8]
    [8 8 8]
    [8 8 8]]
    '''
    result1=tf.trace(res)
    result=sess.run(result1)
    '''
    print(sess.run(result))
    24
    '''
    sess.close()
    # ********** End **********#
    # 返回result
    return result

init_op = tf.global_variables_initializer()
a = int(input())

with tf.Session() as sess:
    sess.run(init_op)
    print(count_trace(a))

(3)Tensorflow数据广播机制

广播机制

一般而言,我们进行矩阵相加等计算时,会有数据格式要求,即两矩阵形状一致。但在实际处理中,我们可能会碰到形状不一致的情况,而TensorFlow的广播机制就是为了处理这个问题。广播是指让具有不同形状的张量在进行算术运算的兼容形状的过程。

# -*- coding: utf-8 -*-
import tensorflow as tf
import os

os.environ["TF_CPP_MIN_LOG_LEVEL"]='3'

def broad_cast(t):
    tensor_a = tf.constant([[1, 3], [4, 5]])
    '''
    返回值:
    result: 一个标量值
    '''
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    a = tf.constant([t,2*t])#看左边的中括号有几个,就是几维度。tensor_a是二维
    #一维向量,二维矩阵,三维空间矩阵
    '''
    a=[1 2]
    返回值:
    result: 一个标量值
    '''
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
   
    b1=tf.expand_dims(a,0)#使用0的广播尺寸。每个向量元素成为一行,并且向量对于矩阵中的每一列都进行复制。
    b2=tf.expand_dims(a,1)#使用1的广播尺寸。每个向量元素变成一列,并且向量对于矩阵中的每一行都进行复制。
    
    c1=tensor_a+b1
    c2=tensor_a+b2
    c=c1+c2
    result=tf.trace(c)

    init_op = tf.global_variables_initializer()
    with tf.Session() as sess:
        result=sess.run(result)
    # ********** End **********#
    # 返回result
    return result

init_op = tf.global_variables_initializer()

a = int(input())
with tf.Session() as sess:
    sess.run(init_op)
    print(broad_cast(a))

3、TensorFlow入门–张量运算进阶

第1关:在指定位置修改维度 - expand_dims方法与squeeze方法

知识点

a=tf.zeros([2,3,4])  #a是形状为[2,3,4]的全0数组
tf.expand_dims(a, 0) #结果是形状为[1,2,3,4]的全0数组
tf.expand_dims(a, 1) #结果是形状为[2,1,3,4]的全0数组
tf.expand_dims(a, 2) #结果是形状为[2,3,1,4]的全0数组
# -*- coding: utf-8 -*-
import tensorflow as tf

# 根据action中参数的值修改tensor的形状
# tensor是一个TensorFlow中的张量
# action是一个TensorFlow中的一维张量 (向量), 表示要对 tensor 进行操作的序列
# action的中的值 (记为x) 含义如下:
# 当x大于等于0时, 表示需要在 tensor 的第 x 维度增加一个维度.
# 当x小于0时, 表示需要去掉 tensor 的第 -x 维度 (输入数据保证合法).
# 返回修改形状后的张量.
def change(tensor,action):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    with tf.Session() as sess:
        '''
        print(sess.run(tensor)) 
        [[1. 1. 1.]
        [1. 1. 1.]]
        print(sess.run(action))
        [1]
        '''
        
        for x in action.eval():
            if x>=0:
                tensor=tf.expand_dims(tensor,x)
            else:
                tensor=tf.squeeze(tensor,-x)
        
        return sess.run(tensor)
    
    # ********** End **********#
    


第2关:合成张量 - stack方法和concat方法

知识点

t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2], 0)  # 结果为[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12],是个形状为[4,3]的张量。
tf.concat([t1, t2], 1)  # 结果为[[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12]],是个形状为[2,6]的张量。
x = tf.constant([1, 4])
y = tf.constant([2, 5])
z = tf.constant([3, 6])
tf.stack([x, y, z]0)  # 结果为 [[1, 4], [2, 5], [3, 6]] 
tf.stack([x, y, z], 1)  # 结果为 [[1, 2, 3], [4, 5, 6]]
# -*- coding: utf-8 -*-
import tensorflow as tf

# 根据参数生成相应的张量
# 首先需要生成num个形状为shape的张量, 之后使用stack方法让这num个张量沿dim维合并. 返回合并后的结果
# 参数类型说明:
# num为正整数
# dim为整数
# shape为numpy数组
def packing(num, dim, shape):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#

    L=[]
    for i in range(0, num):
        L.append(tf.zeros(shape))#生成张量
    return tf.stack(L, dim)

    # ********** End **********#
    


第3关:判断张量是否相等- equal方法

知识点 euqal方法

判断张量是否相等
其实这里的说法略微显得有些不太严谨,因为接下来我们要讲的方法其实并不是用于判断张量是否相等的,而是用于判断张量中每个元素是否相等的。

我们首先介绍equal方法,在介绍了equal方法之后,其他的方法大家只需要看他们的名字就知道该如何使用了。

euqal方法的原型如下:

tf.math.equal(
    x,
    y,
    name=None
)
# -*- coding: utf-8 -*-
import tensorflow as tf

# 返回张量x与张量y中的相同的元素个数
def judge(x, y):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    
    a=tf.equal(x,y)
    '''
    with tf.Session() as sess:
        print(sess.run(a))
    [[ True  True False False]
    [ True False  True  True]
    [ True  True False  True]
    [False False  True  True]]
    '''
    a_reshape=tf.reshape(a,[1,-1])
    '''
    with tf.Session() as sess:
        print(sess.run(a_reshape))
        [[ True  True False False  True False  True  True  True  True False  True False False  True  True]]
    '''
    a_value=a_reshape.eval()
    
    count=0
    for x in a_value.flat:#数组的flat属性返回的是数组的迭代器,通过这个迭代器,可以一层for循环就搞定多维数组的访问
        if x:
            count=count+1
    return count
    # ********** End **********#

4、TensorFlow入门–构建神经网络

第1关:神经元与激活函数

# -*- coding: utf-8 -*-
import tensorflow as tf

# 模拟一个 M-P 神经元的工作原理
# input_value 是输入值, 类型为一维的tf.constant
# weight 是这个神经元的权重, 类型为一维的tf.constant
# threshold 是这个神经元的阈值, 类型为零维的tf.constant
# 返回值是一个浮点数
def neuron(input_value, weight, threshold):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    
    mul=input_value*weight
    y=tf.reduce_sum(mul)-threshold
    return tf.sigmoid(y).eval()#tf.sigmoid()要与eval()同用
    
    
    # ********** End **********#
    

第2关:神经元与激活函数 - tanh方法

# -*- coding: utf-8 -*-
import tensorflow as tf

# 模拟一个 M-P 神经元
class neuron(object):

    # 构造函数
    # weight为本神经元的权重,类型为一维的tf.constant
    # threshold 是这个神经元的阈值, 类型为零维的tf.constant
    def __init__(self, weight, threshold):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
        self.weight=weight
        self.threshold=threshold
    # ********** End **********#

    # 计算函数
    # input_value 是输入值, 类型为一维的tf.constant
    # 返回值是一个浮点数
    def computes(self, input_value):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#

        return tf.tanh(tf.reduce_sum(self.weight*input_value)-self.threshold).eval()
    # ********** End **********#
    

第3关:构建简单的单隐层前馈神经网络

# -*- coding: utf-8 -*-
import tensorflow as tf

# 模拟一个 M-P 神经元
class neuron(object):

    # 构造函数
    # weight为本神经元的权重,类型为一维的tf.constant
    # threshold 是这个神经元的阈值, 类型为零维的tf.constant
    def __init__(self, weight, threshold):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
        self.weight=weight
        self.threshold=threshold
    # ********** End **********#

    # 计算函数
    # input_value 是输入值, 类型为一维的tf.constant
    # 返回值是一个浮点数
    def computes(self, input_value):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
        return tf.nn.relu(tf.reduce_sum(self.weight*input_value)-self.threshold).eval()
    # ********** End **********#

# 模拟神经网络中的一层

class Dense(object):
    
    # 构造函数
    # weights 为本层中每个神经元的权重,元素类型为一维的tf.constant,weights的类型是python的列表
    # thresholds 为本层中每个神经元的权重,元素类型为零维的tf.constant,thresholds的类型是python的列表
    def __init__(self, weights, thresholds):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
        size=len(weights)
        self.neurons=[]
        for i in range(size):
            self.neurons.append(neuron(weights[i], thresholds[i]))
    # ********** End **********#

    # 计算函数
    # input_value 是输入值, 类型为一维的tf.constant
    # 返回值应为一个 1 维, 长度为n的Tensor, n是本层中神经元的数量
    def computes(self, input_value):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
        L=[]
        size=len(self.neurons)
        for i in range(size):
            L.append(self.neurons[i].computes(input_value))
        return tf.constant(L)

    # ********** End **********#

# 模拟一个简单的神经网络
# input_value是这个神经网络的输入,类型为一维的tf.constant
# wegihtsOfMiddle 是这个神经网络中间层每个神经元的权重, 元素类型为一维的tf.constant,wegihtsOfMiddle的类型是python的列表
# thresholdsOfMiddle 是这个神经网络中间层每个神经元的阈值, 元素类型为零维的tf.constant,thresholdsOfMiddle的类型是python的列表
# wegihtsOfOut 是这个神经网络输出层每个神经元的权重, 元素类型为一维的tf.constant,wegihtsOfOut 的类型是python的列表
# thresholdsOfOut 是这个神经网络输出层每个神经元的阈值, 元素类型为零维的tf.constant,thresholdsOfOut 的类型是python的列表
# 返回值是一个一维浮点数组 (注意不是Tensor),数组的长度为输出层神经元的数量

def NetWork(input_value, wegihtsOfMiddle, thresholdsOfMiddle, weightsOfOut, thresholdsOfOut):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
   
    middle=Dense(wegihtsOfMiddle, thresholdsOfMiddle)
    out=Dense(weightsOfOut, thresholdsOfOut)
    return out.computes(middle.computes(input_value)).eval()


    # ********** End **********#

5、TensorFlow入门–队列与TensorBoard操作

第1关:出队操作 - dequeue 方法

# -*- coding: utf-8 -*-
import tensorflow as tf

# 返回queue中所有张量之和
# queue是一个tensforflow.FIFOQueue
def queueSum(queue):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    #加eval()取值

    if queue.size().eval()==0:
        return 0
    ret=queue.dequeue().eval()
    while queue.size().eval()>0:#队列自减
        ret=ret+queue.dequeue().eval()
    return ret
    


    # ********** End **********#

第2关:入队 - enqueue方法

# -*- coding: utf-8 -*-
import tensorflow as tf

# 依次取出queue中各个元素, 将其与其本身相加后放回queue中
# queue是一个tensforflow.FIFOQueue
# sess是一个tensorflow.Session(), 用来执行操作
def addEach(sess, queue):
    # 请在此添加代码 完成本关任务
    # ********** Begin *********#
    for i in range(queue.size().eval()):
        x = queue.dequeue()
        y = x+x
        en_q=queue.enqueue([y])
        sess.run(en_q)
#写作queue=queue.enqueue([y])报错
        

    


    # ********** End **********#
    

6、Tensorflow入门–图与会话

(1)第1关Hello,Tensorflow

#********* Begin *********#
import tensorflow as tf
#使用tf.constant()函数在图中创建一个常量Tensor
c=tf.constant("Hello World")
# 创建一个Session
sess=tf.Session()
# 让c这个Tensor动起来,并打印c这个Tensor动起来之后的值
print(sess.run(c))
# 关闭Session
#sess.close()

#********* End *********#

(2)第2关计算图与会话

相关知识
为了完成本关任务,你需要掌握:

计算图(Graph)
会话(Session)
计算图Graph
TensorFlow是一个通过计算图的形式来表述计算的编程系统。
基于TensorFlow这个编程系统中的每一个计算都是计算图上的一个节点,而节点与节点之间的连线则代表计算之间的依赖关系。如我们需要定义一个y=wx+b的计算:
在这里插入图片描述
上图中,w,x,b为我们输入的tensor,Mul,Add表示节点之间的依赖关系。这整个就是一个计算图,我们可以理解为,计算图就是用来定义一个模型或者计算的。我们节点可以为:

常量节点tf.constant:它的value值可以为一个数值也可以为一个列表。如:

a = tf.constant(1)
b = tf.constant([1,2,3])

变量节点tf.Variable:它可以用来存储图执行过程中需要更新的量,在神经网络中用来储存权重值,创建方式如下:

v1=tf.Variable(tf.random_normal(shape=[4,3],mean=0,stddev=1),name='v1')

表示生成一个四行三列的tensor其中的值符合均值为0标准差为1的正态分布。节点名字为v1。当然还有更多其它的创建方式:

v2=tf.Variable(tf.constant(2),name='v2')
v3=tf.Variable(tf.ones([4,3]),name='v3')


不过值得主义的是,定义了变量节点后想要运行它需要先进行初始化:

sess.run(tf.global_variables_initializer())

占位节点tf.placeholder:placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。等建立session,在会话中,运行模型的时候通过feed_dict()函数向占位符喂入数据。创建方式如下:

input1 = tf.placeholder(tf.float32)
#创建会话,喂入数据
with tf.Session() as sess:
    print(sess.run(output, feed_dict = {input1:[5.]}))

这个时候,假如我们想要计算2×3+5则可以进行如下操作:

w = tf.constant(2.)
x = tf.constant(3.)
b = tf.constant(5.)
y = tf.add(tf.multiply(w,x),b,name='y')
print(y)
>>>
Tensor("y:0", shape=(), dtype=float32)

输出结果并不是我们所意料的,这是因为,计算图只是定义了这个计算,它并没有运行起来,而想要运行起来则需要生成一个会话。

会话Session
我们已经知道计算图是用来定义一个模型或者计算的,而会话则是让这个模型或则计算运行起来,得到结果。如上一个例子,我们想要得到结果则需要进行如下操作:

sess = tf.Session()
print(sess.run(y))
>>>
11.0
进行计算后,我们可以关闭会话释放资源:

sess.close()
当然,还有另外一种创建会话的方法:

with tf.Session() as sess:
    print(sess.run(y))
>>>
11.0
这种方式不需要调用Session.close()函数来关闭会话,上下文结束时资源会自动释放。

总的来说,计算图就是定义tensor之间的依赖关系,而会话则是让这些数据flow起来。

编程要求
根据提示,在右侧编辑器补充代码,实现matmul方法。其中:

a(list):你需要将它转为相应的数据类型
b(list):你需要将它转为相应的数据类型
result(ndarray):矩阵相乘后的结果

# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np

def matmul(a,b):
    '''
    a(list):矩阵a
    b(list):矩阵b
    result(ndarray):矩阵相乘结果
    '''
    #********* Begin *********#
    #常量节点tf.constant可为列表和常数
    #常量节点tf.ones可为矩阵
    #变量节点tf.Variable:它可以用来存储图执行过程中需要更新的量;在神经网络中用来储存权重值,
    v1=tf.constant(a)
    v2=tf.constant(b)

    ndarray=tf.matmul(v1,v2)


    '''
    tf.Variable 和 tf.placeholder的区别,两者都可以盛放变量,
    但在启动会话前,tf.Variable必须先被赋值和初始化,
    而tf.placeholder是需要在启动会话的时候传入值的;
    从直观上讲,tf.placeholder更加接近函数的形参。

    这是我们可以执行numpy矩阵乘法的三种方法。
    首先是使用multiple()函数, 该函数执行矩阵的逐元素乘法。
    其次是使用matmul()函数, 该函数执行两个数组的矩阵乘积。
    最后是dot()函数的使用, 该函数执行两个数组的点积。
    '''
    with tf.Session() as sess:
        result=sess.run(ndarray)
   

    #********* End *********#
    return result
    

(3) 第3关Tensorflow实现线性回归

股票数据介绍
股票原始数据如下:

在这里插入图片描述

我们的目的是利用股市收盘价、最高价与最低价的变化百分比、收盘价与开盘价的变换百分比、成交量预测未来的股市收盘价。

其中开盘价对应的数据为Adj.Open
最高价对应的数据为Adj.High
最低价对应的数据为Adj. Low
成交量对应的数据为Adj. Volume
而另外两个特征,数据表格中并没有,所以需要我们自己创建,代码如下:


import pandas as pd
df = pd.read_csv('./step3/googlestock2.csv')
# 只用到df中下面的几个字段
df = df[['Adj. Open', 'Adj. High', 'Adj. Low', 'Adj. Close', 'Adj. Volume']]
# 构造两个新的列
# HL_PCT为股票最高价与最低价的变化百分比
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Close']) / df['Adj. Close'] * 100.0
# HL_PCT为股票收盘价与开盘价的变化百分比
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0
# 下面为真正用到的特征字段
df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
# 因为scikit-learn并不会处理空数据,需要把为空的数据都设置为一个比较难出现的值,这里取-9999,
df.fillna(-99999, inplace=True)
我们是要预测未来的股票收盘价格,这里定义预测天数为数据量的百分之1,然后构造出数据特征与标签:

# 定义预测列变量,它存放研究对象的标签名
forecast_col = 'Adj. Close'
# 定义预测天数,这里设置为所有数据量长度的1%
forecast_out = int(math.ceil(0.1*len(df)))
X = np.array(df.drop(['label'], 1))
#对数据进行标准化
X = preprocessing.scale(X)
#现在的收盘价为部分特征,未来的收盘价为标签
X = X[:-forecast_out]
# 通过让与Adj. Close列的数据往前移动1%行来表示
df['label'] = df[forecast_col].shift(-forecast_out)
# 抛弃label列中为空的那些行
df.dropna(inplace=True)
y = np.array(df['label'])

这时我们已经创建好数据,一共3081个样本,我们将前2481个样本用来训练,后面600个样本用来测试:

train_data,test_data = X[:-600],X[-600:]
train_label,test_label = y[:-600],y[-600:]

线性回归**

简单线性回归
在生活中,我们常常能碰到这么一种情况,一个变量会跟着另一个变量的变化而变化,如圆的周长与半径的关系,当圆的半径确定了,那么周长也就确定了。还有一种情况就是,两个变量之间看似存在某种关系,但又没那么确定,如青少年的身高与体重,他们存在一种近似的线性关系:身高/cm = 体重/kg +105

但是,并不是每个青少年都符合这个公式,只能说每个青少年的身高体重都存在这么一种近似的线性关系。这就是其实就是简单的线性回归,那么,到底什么是线性回归呢?假如我们将青少年的身高和体重值作为坐标,不同人的身高体重就会在平面上构成不同的坐标点,然后用一条直线,尽可能的去拟合这些点,这就是简单的线性回归。

简单的线性回归模型如下:

y=wx+b

其中x表示特征值(如:体重值),w表示权重,b表示偏置,y表示标签(如:身高值)。

多元线性回归
简单线性回归中,一个变量跟另一个变量的变化而变化,但是生活中,还有很多变量,可能由多个变量的变化决定着它的变化,比如房价,影响它的因素可能有:房屋面积、地理位置等等。如果我们要给它们建立出近似的线性关系,这就是多元线性回归,多元线性回归模型如下:

y=b+w1​x1+w2x2+…+wnxn
其中xi表示第i个特征值,wi表示第i个特征对应的权重,b表示偏置,y表示标签。

模型训练流程
由数据集可以知道,每一个样本有4个特征与标签,而我们要做的事就是通过这4个特征来预测标签值,我们可以构建一个多元线性回归模型,来对股票收盘价格进行预测。模型如下:
y=b+w1​x1+w2x2+…+wnxn
其中xi表示第i个特征值,wi 表示第i个特征对应的权重,b表示偏置,y表示目标房价。

而我们的目的就是找出能够正确预测的多元线性回归模型,即找出正确的参数θ。那么如何寻找呢?通常在监督学习里面都会使用这么一个套路,构造一个损失函数,用来衡量真实值与预测值之间的差异,然后将问题转化为最优化损失函数。既然损失函数是用来衡量真实值与预测值之间的差异那么很多人自然而然的想到了用所有真实值与预测值的差的绝对值来表示损失函数。不过带绝对值的函数不容易求导,所以采用MSE(均方误差)作为损失函数,公式如下:

loss= m1i=1∑m (yi −pi )2

其中p表示预测值,y表示真实值,m为样本总个数,i表示第i个样本。最后,我们再使用梯度下降来求得我们所需要的参数。

线性回归模型训练流程图如下:

关于梯度下降详细内容请点击查看

模型搭建

我们想要使用tensorflow实现线性回归,首先需要创建两个tf.placeholder用来喂入数据特征与标签:

data = tf.placeholder(tf.float32, [None, 4])
real_label = tf.placeholder(tf.float32, [None, 1])
[None, 4]表示数据有4个特征,喂入数据的样本个数待定。

然后再定义我们需要跟新的权重与偏置参数,通过上一节的内容我们直到需要用tf.Variable来定义:

weight = tf.Variable(tf.random_normal([4, 1]), dtype=tf.float32)
bias = tf.Variable(tf.ones([1]), dtype=tf.float32)

定义线性回归模型y=wx+b:

y_label = tf.add(tf.matmul(data, weight), bias)

然后构造损失函数,使用梯度下降的方法来进行训练:

#构造损失函数
loss = tf.reduce_mean(tf.square(real_label - y_label))
train = tf.train.AdamOptimizer(lr).minimize(loss)
#初始化
sess.run(tf.global_variables_initializer())
#进行训练
for i in range(n_iters):
    sess.run(train,feed_dict={data: train_data, real_label: train_label})

最后就可以对测试集数据进行预测:

test_predict = sess.run(y_label,feed_dict={data: test_data})

编程要求
根据提示,在右侧编辑器补充代码,实现线性回归方法。

# -*- coding: utf-8 -*-
import math
import numpy as np
import pandas as pd
from sklearn.preprocessing import scale
import tensorflow as tf
def preprocess_data(df):
    '''
    df(DataFrame):原始数据
    X(ndarray):处理后数据特征
    y(ndarray):处理后数据标签
    '''
    #*********Bengin*********#
    # 定义预测列变量,它存放研究对象的标签名
    forecast_col = 'Adj. Close' 
    # 定义预测天数,这里设置为所有数据量长度的1%
    forecast_out = int(math.ceil(0.1*len(df)))
    # 只用到df中下面的几个字段['Adj. Open', 'Adj. High', 'Adj. Low', 'Adj. Close', 'Adj. Volume']
    df = df[['Adj. Open', 'Adj. High', 'Adj. Low', 'Adj. Close', 'Adj. Volume']]    
    # 构造两个新的列
    # HL_PCT为股票最高价与最低价的变化百分比
    df['HL_PCT'] = (df['Adj. High'] - df['Adj. Close']) / df['Adj. Close'] * 100.0
    # HL_PCT为股票收盘价与开盘价的变化百分比
    df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0
    # 下面为真正用到的特征字段['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']
    df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
    # 因为scikit-learn并不会处理空数据,需要把为空的数据都设置为一个比较难出现的值,这里取-9999,
    df.fillna(-99999, inplace=True)
    # 用label代表该字段,是预测结果
    df['label'] = df[forecast_col].shift(-forecast_out)
    #构造X
    X = np.array(df.drop(['label'], 1))   
    X = scale(X)
    X = X[:-forecast_out]
    # 抛弃label列中为空的那些行
    df.dropna(inplace=True)
    y = np.array(df['label'])
    #将标签reshape成(-1,1)
    y = y.reshape(-1,1)
    #*********End*********#
    return X,y
def tf_predict(sess,train_data,train_label,test_data,lr,n_iters):
    '''
    sess:tf.Session创建的会话
    train_data(ndarray):训练数据
    train_label(ndarray):训练标签
    test_data(ndarray):测试数据
    lr(float):学习率
    n_iters(int):训练轮数
    test_predict(ndarray):测试集预测标签
    '''
    #*********Bengin*********#
    #创建两个tf.placeholder用来喂入数据特征与标签
    data = tf.placeholder(tf.float32, [None, 4])
    real_label = tf.placeholder(tf.float32, [None, 1])


    weight = tf.Variable(tf.random_normal([4, 1]), dtype=tf.float32)
    bias = tf.Variable(tf.ones([1]), dtype=tf.float32)

    y_label = tf.add(tf.matmul(data, weight), bias)
    loss = tf.reduce_mean(tf.square(real_label - y_label))
    train = tf.train.AdamOptimizer(lr).minimize(loss)
    sess.run(tf.global_variables_initializer())
    
    for i in range(n_iters):
        sess.run(train,feed_dict={data: train_data, real_label: train_label})    
    test_predict = sess.run(y_label,feed_dict={data: test_data})
    sess.close()
    #*********End*********#
    return test_predict

7、决策树

第2关:信息熵与信息增益

import numpy as np# 计算信息熵
def calcInfoEntropy(feature, label):
    '''
    计算信息熵
    :param feature:数据集中的特征,类型为ndarray
    :param label:数据集中的标签,类型为ndarray
    :return:信息熵,类型float
    '''

    #*********** Begin ***********#
    label_set = set(label)
    #print("the type of label_set is: ",type(label_set))
    '''
    print( label_set)
    {0, 1}
    {0}
    {0, 1}
    '''
    
    result=0
    #每个标签出现的概率,得出对应的p;[[0,3/5],[1,2/5],[0,3/5]...]
    for l in label_set:#遍历集合中的每一个元素
        count = 0
        for j in range(len(label)):#print(len(label))=5
            if label[j] == l:
                count += 1
        p = count/len(label)
        result+=-p*np.log2(p)#H(X)

    return result

    #*********** End *************#


# 计算条件熵
def calcHDA(feature, label, index, value):
    '''
    计算信息熵
    :param feature:数据集中的特征,类型为ndarray
    :param label:数据集中的标签,类型为ndarray
    :param index:需要使用的特征列索引,类型为int
    :param value:index所表示的特征列中需要考察的特征值,类型为int
    :return:信息熵,类型float
    '''

    #*********** Begin ***********#
    count = 0
    sub_feature = []#list
    sub_label = []
    #print(len(feature)):5
    #print(feature):[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]] 两列分别代表性别和活跃度
    for i in range(len(feature)):#i=0/1/2/3/4
        #print(feature[i][index]) 0 1 1 0 1

        if feature[i][index] == value:#若index=1,value=
            count += 1
            sub_feature.append(feature[i])#提取出符合特征的feature
            '''
            print(feature[i])
            [1, 0]
            [1, 2]
            [1, 1]
            '''
            sub_label.append(label[i])#提取出符合特征的feature的对应标签
            '''
            print(label[i])
            1
            0
            1
            '''

    pHA = count/len(feature)
    e = calcInfoEntropy(sub_feature,sub_label)
    return pHA*e    

    #*********** End *************#


def calcInfoGain(feature, label, index):
    '''
    计算信息增益
    :param feature:测试用例中字典里的feature
    :param label:测试用例中字典里的label
    :param index:测试用例中字典里的index,即feature部分特征列的索引
    :return:信息增益,类型float
    '''

    #*********** Begin ***********#
    base_e = calcInfoEntropy(feature,label)
    #print("base_e= ",base_e):base_e=  0.5287712379549449
    f = np.array(feature)
    '''
    print(f)
    [[0 1]
    [1 0]
    [1 2]
    [0 0]
    [1 1]]
    '''
    f_set = set(f[:, index])#提取标签
    #print(f_set) :{0, 1}
    sum_HDA = 0
    for a in f_set:
        sum_HDA += calcHDA(feature, label, index, a)
    return base_e-sum_HDA
    #*********** End *************#

第3关:使用ID3算法构造决策树

import numpy as np

class DecisionTree(object):
    def __init__(self):
        #决策树模型
        self.tree = {}

    def calcInfoGain(self, feature, label, index):
        '''
        计算信息增益
        :param feature:测试用例中字典里的feature,类型为ndarray
        :param label:测试用例中字典里的label,类型为ndarray
        :param index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。
        :return:信息增益,类型float
        '''

        # 计算熵
        def calcInfoEntropy(label):
            '''
            计算信息熵
            :param label:数据集中的标签,类型为ndarray
            :return:信息熵,类型float
            '''

            label_set = set(label)
            result = 0
            for l in label_set:
                count = 0
                for j in range(len(label)):
                    if label[j] == l:
                        count += 1
                # 计算标签在数据集中出现的概率
                p = count / len(label)
                # 计算熵
                result -= p * np.log2(p)
            return result

        # 计算条件熵
        def calcHDA(feature, label, index, value):
            '''
            计算信息熵
            :param feature:数据集中的特征,类型为ndarray
            :param label:数据集中的标签,类型为ndarray
            :param index:需要使用的特征列索引,类型为int
            :param value:index所表示的特征列中需要考察的特征值,类型为int
            :return:信息熵,类型float
            '''
            count = 0
            # sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签
            sub_feature = []
            sub_label = []
            for i in range(len(feature)):
                if feature[i][index] == value:
                    count += 1
                    sub_feature.append(feature[i])
                    sub_label.append(label[i])
            pHA = count / len(feature)
            e = calcInfoEntropy(sub_label)
            return pHA * e

        base_e = calcInfoEntropy(label)
        f = np.array(feature)
        # 得到指定特征列的值的集合
        f_set = set(f[:, index])
        sum_HDA = 0
        # 计算条件熵
        for value in f_set:
            sum_HDA += calcHDA(feature, label, index, value)
        # 计算信息增益
        return base_e - sum_HDA

    # 获得信息增益最高的特征
    def getBestFeature(self, feature, label):
        max_infogain = 0
        best_feature = 0
        for i in range(len(feature[0])):
            infogain = self.calcInfoGain(feature, label, i)
            if infogain > max_infogain:
                max_infogain = infogain
                best_feature = i
        return best_feature

    def createTree(self, feature, label):
        # 样本里都是同一个label没必要继续分叉了
        if len(set(label)) == 1:
            return label[0]
        # 样本中只有一个特征或者所有样本的特征都一样的话就看哪个label的票数高
        if len(feature[0]) == 1 or len(np.unique(feature, axis=0)) == 1:
            vote = {}
            for l in label:
                if l in vote.keys():
                    vote[l] += 1
                else:
                    vote[l] = 1
            max_count = 0
            vote_label = None
            for k, v in vote.items():
                if v > max_count:
                    max_count = v
                    vote_label = k
            return vote_label

        # 根据信息增益拿到特征的索引
        best_feature = self.getBestFeature(feature, label)
        tree = {best_feature: {}}
        f = np.array(feature)
        # 拿到bestfeature的所有特征值
        f_set = set(f[:, best_feature])
        # 构建对应特征值的子样本集sub_feature, sub_label
        for v in f_set:
            sub_feature = []
            sub_label = []
            for i in range(len(feature)):
                if feature[i][best_feature] == v:
                    sub_feature.append(feature[i])
                    sub_label.append(label[i])
            # 递归构建决策树
            tree[best_feature][v] = self.createTree(sub_feature, sub_label)
        return tree

    def fit(self, feature, label):
        '''
        :param feature: 训练集数据,类型为ndarray
        :param label:训练集标签,类型为ndarray
        :return: None
        '''

        #************* Begin ************#
        self.tree = self.createTree(feature, label)
        #************* End **************#

    def predict(self, feature):
        '''
        :param feature:测试集数据,类型为ndarray
        :return:预测结果,如np.array([0, 1, 2, 2, 1, 0])
        '''

        #************* Begin ************#
        result = []

        def classify(tree, feature):
            if not isinstance(tree, dict):
                return tree
            t_index, t_value = list(tree.items())[0]
            f_value = feature[t_index]
            if isinstance(t_value, dict):
                classLabel = classify(tree[t_index][f_value], feature)
                return classLabel
            else:
                return t_value

        for f in feature:
            result.append(classify(self.tree, f))

        return np.array(result)
        #************* End **************#

第5关:sklearn中的决策树

from sklearn.tree import DecisionTreeClassifier

def iris_predict(train_sample, train_label, test_sample):
    '''
    实现功能:1.训练模型 2.预测
    :param train_sample: 包含多条训练样本的样本集,类型为ndarray
    :param train_label: 包含多条训练样本标签的标签集,类型为ndarray
    :param test_sample: 包含多条测试样本的测试集,类型为ndarry
    :return: test_sample对应的预测标签
    '''
    # ************* Begin ************#

    dt = DecisionTreeClassifier(max_depth=3)#不加max_depth=3,结果正确率只有0.93
    dt.fit(train_sample, train_label)
    result=dt.predict(test_sample)
    return result
    
    # ************* End **************#

您可能感兴趣的与本文相关的镜像

TensorFlow-v2.15

TensorFlow-v2.15

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值