• 百度PaddlePaddle入门-5(Numpy,Random)


    Numpy是Numerical Python的简称,是Python中高性能科学计算和数据分析的基础包。Numpy提供了一个多维数组类型ndarray,它具有矢量算术运算和复杂广播的能力,可以实现快速的计算并且能节省存储空间。在使用Python调用飞桨API完成深度学习任务的过程中,通常会使用Numpy实现数据预处理和一些模型指标的计算,飞桨中的Tensor数据可以很方便的和ndarray数组进行相互转换。

    在这一节将介绍以下内容:

    • 基础数据结构ndarray数组

    • 随机数numpy.random

    • 线性代数numpy.linalg

    • Numpy保存和导入文件

    • 应用举例


    基础数据结构ndarray数组

    ndarray数组是Numpy中的基础数据结构式,这一小节将从以下几个方面展开进行介绍:

    • 为什么引入ndarray数组

    • 如何创建ndarray数组

    • ndarray数组的基本运算

    • ndarray数组的切片和索引

    • ndarray数组的统计运算

    为什么引入ndarray数组

    在Python中使用list列表可以非常灵活的处理多个元素的操作,但是其效率却比较低。ndarray数组相比于Python中的list列表具有以下特点:

    • ndarray数组中所有元素的数据类型是相同的,数据地址是连续的,批量操作数组元素时速度更快;list列表中元素的数据类型可以不同,需要通过寻址方式找到下一个元素

    • ndarray数组中实现了比较成熟的广播机制,矩阵运算时不需要写for循环

    • Numpy底层是用c语言编写的,内置了并行计算功能,运行速度高于纯Python代码

    下面的代码展示了使用ndarray数组和list列表完成相同的任务,ndarray数组的代码看上去要更加简洁而且易于理解。

    ndarray数组和list列表分别完成对每个元素增加1的计算

     1 # Python原生的list
     2 # 假设有两个list
     3 a = [1, 2, 3, 4, 5]
     4 b = [2, 3, 4, 5, 6]
     5 
     6 # 完成如下计算
     7 # 1 对a的每个元素 + 1
     8 # a = a + 1 不能这么写,会报错
     9 # a[:] = a[:] + 1 也不能这么写,也会报错
    10 for i in range(5):
    11     a[i] = a[i] + 1
    12 a
    [2, 3, 4, 5, 6]
    1 # 使用ndarray
    2 import numpy as np
    3 a = np.array([1, 2, 3, 4, 5])
    4 a = a + 1
    5 a
    array([2, 3, 4, 5, 6])

    ndarray数组和list列表分别完成相加计算

    1  2 计算 a和b中对应位置元素的和,是否可以这么写?
    2 a = [1, 2, 3, 4, 5]
    3 b = [2, 3, 4, 5, 6]
    4 c = a + b
    5 # 检查输出发现,不是想要的结果
    6 c
    [1, 2, 3, 4, 5, 2, 3, 4, 5, 6]
    1 # 使用for循环,完成两个list对应位置元素相加
    2 c = []
    3 for i in range(5):
    4     c.append(a[i] + b[i])
    5 c
    [3, 5, 7, 9, 11]
    1 # 使用numpy中的ndarray完成两个ndarray相加
    2 import numpy as np
    3 a = np.array([1, 2, 3, 4, 5])
    4 b = np.array([2, 3, 4, 5, 6])
    5 c = a + b 
    6 c
    array([ 3,  5,  7,  9, 11])
    从上面的示例中可以看出,ndarray数组的矢量计算能力使得不需要写for循环,就可以非常方便的完成数学计算,在操作矢量或者矩阵时,可以像操作普通的数值变量一样编写程序,使得代码极其简洁。另外,ndarray数组还提供了广播机制,它会按一定规则自动对数组的维度进行扩展以完成计算,如下面例子所示,1维数组和2维数组进行相加操作,ndarray数组会自动扩展1维数组的维度,然后再对每个位置的元素分别相加。
     1 # 自动广播机制,1维数组和2维数组相加
     2 
     3 # 二维数组维度 2x5
     4 # array([[ 1,  2,  3,  4,  5],
     5 #         [ 6,  7,  8,  9, 10]])
     6 d = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
     7 # c是一维数组,维度5
     8 # array([ 4,  6,  8, 10, 12])
     9 c = np.array([ 4,  6,  8, 10, 12])
    10 e = d + c
    11 e
    array([[ 5,  8, 11, 14, 17],
           [10, 13, 16, 19, 22]])

    如何创建ndarray数组

    有如下几种方式创建ndarray数组

    • 从list列表创建

    • 指定起止范围及间隔创建

    • 创建值全为0的ndarray数组

    • 创建值全为1的ndarray数组

    1 # 导入numpy
    2 import numpy as np
    3 
    4 # 从list创建array
    5 a = [1,2,3,4,5,6]
    6 b = np.array(a)
    7 b
    array([1, 2, 3, 4, 5, 6])
    1 # 通过np.arange创建
    2 # 通过指定start, stop (不包括stop),interval来产生一个1维的ndarray
    3 a = np.arange(0, 20, 2)
    4 a
    array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])
    1 # 创建全0的ndarray
    2 a = np.zeros([3,3])
    3 a
    array([[0., 0., 0.],
           [0., 0., 0.],
           [0., 0., 0.]])
    1 # 创建全1的ndarray
    2 a = np.ones([3,3])
    3 a
    array([[1., 1., 1.],
           [1., 1., 1.],
           [1., 1., 1.]])

    查看ndarray数组的属性

    ndarray的属性包括形状shape、数据类型dtype、元素个数size和维度ndim等,下面的程序展示如何查看这些属性

    1  数组的数据类型 ndarray.dtype
    2 # 数组的形状 ndarray.shape,1维数组(N, ),二维数组(M, N),三维数组(M, N, K)
    3 # 数组的维度大小,ndarray.ndim, 其大小等于ndarray.shape所包含元素的个数
    4 # 数组中包含的元素个数 ndarray.size,其大小等于各个维度的长度的乘积
    5 
    6 a = np.ones([3, 3])
    7 print('a, dtype: {}, shape: {}, size: {}, ndim: {}'.format(a.dtype, a.shape, a.size, a.ndim))
    a, dtype: float64, shape: (3, 3), size: 9, ndim: 2
    上面输出结果中,shape就是一个元组;size=各维长度大小的乘积;ndim不是很好理解=shape中包含元素的个数。同时ones()函数输出的默认类型就是float64.

    改变ndarray数组的数据类型和形状

    创建ndarray之后,可以对其数据类型进行更改,或者对形状进行调整,如下面的代码所示

    1 # 转化数据类型
    2 b = a.astype(np.int64)
    3 print('b, dtype: {}, shape: {}'.format(b.dtype, b.shape))
    4 
    5 # 改变形状
    6 c = a.reshape([1, 9])
    7 print('c, dtype: {}, shape: {}'.format(c.dtype, c.shape))
    b, dtype: int64, shape: (3, 3)
    c, dtype: float64, shape: (1, 9)

    ndarray数组的基本运算

    ndarray数组可以像普通的数值型变量一样进行加减乘除操作,这一小节将介绍两种形式的基本运算:

    • 标量和ndarray数组之间的运算

    • 两个ndarray数组之间的运算

    标量和ndarray数组之间的运算

    1 # 标量除以数组,用标量除以数组的每一个元素
    2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
    3 1. / arr
    array([[1.        , 0.5       , 0.33333333],
           [0.25      , 0.2       , 0.16666667]])
    1 # 标量乘以数组,用标量乘以数组的每一个元素
    2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
    3 2.0 * arr
    array([[ 2.,  4.,  6.],
           [ 8., 10., 12.]])
    1 # 标量加上数组,用标量加上数组的每一个元素
    2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
    3 2.0 + arr
    array([[3., 4., 5.],
           [6., 7., 8.]])
    1 # 标量减去数组,用标量减去数组的每一个元素
    2 arr = np.array([[1., 2., 3.], [4., 5., 6.]])
    3 2.0 - arr
    array([[ 1.,  0., -1.],
           [-2., -3., -4.]])

    两个ndarray数组之间的运算

    1 # 数组 减去 数组, 用对应位置的元素相减
    2 arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
    3 arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
    4 arr1 - arr2
    array([[-10., -10., -10.],
           [-17., -17., -17.]])
    1 # 数组 加上 数组, 用对应位置的元素相加
    2 arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
    3 arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
    4 arr1 + arr2
    array([[12., 14., 16.],
           [25., 27., 29.]])
    1 # 数组 乘以 数组,用对应位置的元素相乘
    2 arr1 * arr2
    array([[ 11.,  24.,  39.],
           [ 84., 110., 138.]])
    上面这个感觉有点难理解啊。
    1 # 数组 除以 数组,用对应位置的元素相除
    2 arr1 / arr2
    array([[0.09090909, 0.16666667, 0.23076923],
           [0.19047619, 0.22727273, 0.26086957]])
    1 # 数组开根号,将每个位置的元素都开根号
    2 arr ** 0.5
    array([[1.        , 1.41421356, 1.73205081],
           [2.        , 2.23606798, 2.44948974]])

    ndarray数组的索引和切片

    在程序中,通常需要访问或者修改ndarray数组某个位置的元素,也就是要用到ndarray数组的索引;有些情况下可能需要访问或者修改一些区域的元素,则需要使用数组的切片。索引和切片的使用方式与Python中的list类似,ndarray数组可以基于 -n ~ n-1 的下标进行索引,切片对象可以通过内置的 slice 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。

    1 # 1维数组索引和切片
    2 a = np.arange(30)
    3 a[10]
    10
    1 a = np.arange(30)
    2 b = a[4:7]
    3 b
    array([4, 5, 6])
    1 #将一个标量值赋值给一个切片时,该值会自动传播到整个选区(如下图所示)
    2 a = np.arange(30)
    3 a[4:7] = 10
    4 a
    array([ 0,  1,  2,  3, 10, 10, 10,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
           17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
    1 # 数组切片是原始数组的视图。这意味着数据不会被复制,
    2 # 视图上的任何修改都会直接反映到源数组上
    3 a = np.arange(30)
    4 arr_slice = a[4:7]
    5 arr_slice[0] = 100
    6 a, arr_slice
    (array([  0,   1,   2,   3, 100,   5,   6,   7,   8,   9,  10,  11,  12,
             13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,
             26,  27,  28,  29]), array([100,   5,   6]))
    1 # 通过copy给新数组创建不同的内存空间
    2 a = np.arange(30)
    3 arr_slice = a[4:7]
    4 arr_slice = np.copy(arr_slice)  #自己给自己拷贝
    5 arr_slice[0] = 100
    6 a, arr_slice
    (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
     array([100,   5,   6]))
    1 # 多维数组索引和切片
    2 a = np.arange(30)
    3 arr3d = a.reshape(5, 3, 2)
    4 arr3d
    array([[[ 0,  1],
            [ 2,  3],
            [ 4,  5]],
    
           [[ 6,  7],
            [ 8,  9],
            [10, 11]],
    
           [[12, 13],
            [14, 15],
            [16, 17]],
    
           [[18, 19],
            [20, 21],
            [22, 23]],
    
           [[24, 25],
            [26, 27],
            [28, 29]]])
    1 # 只有一个索引指标时,会在第0维上索引,后面的维度保持不变
    2 arr3d[0]
    array([[0, 1],
           [2, 3],
           [4, 5]])
    1 # 两个索引指标
    2 arr3d[0][1]
    array([2, 3])
    1 # 两个索引指标,与上面等价
    2 arr3d[0, 1]
    array([2, 3])
    1 # 使用python中的for语法对数组切片
    2 
    3 a = np.arange(24)
    4 a
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
           17, 18, 19, 20, 21, 22, 23])
    1 a = a.reshape([6, 4])
    2 a
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15],
           [16, 17, 18, 19],
           [20, 21, 22, 23]])
    1 # 使用for语句生成list
    2 [k for k in range(0, 10, 2)]
    [0, 2, 4, 6, 8]
     1 # 结合上面列出的for语句的用法
     2 # 使用for语句对数组进行切片
     3 # 下面的代码会生成多个切片构成的list
     4 # k in range(0, 6, 2) 决定了k的取值可以是0, 2, 4
     5 # 产生的list的包含三个切片
     6 # 第一个元素是a[0 : 0+2],也就是a[0:2]
     7 # 第二个元素是a[2 : 2+2],也就是a[2:4]
     8 # 第三个元素是a[4 : 4+2],也就是a[4:6]
     9 slices = [a[k:k+2] for k in range(0, 6, 2)]
    10 slices,a[0:2]
    ([array([[0, 1, 2, 3],
             [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
             [12, 13, 14, 15]]), array([[16, 17, 18, 19],
             [20, 21, 22, 23]])], array([[0, 1, 2, 3],
            [4, 5, 6, 7]]))
    1 slices[1]
    array([[ 8,  9, 10, 11],
           [12, 13, 14, 15]])

    ndarray数组的统计运算

    这一小节将介绍如何计算ndarray数组的各个统计量,包括以下几项:

    • mean 均值
    • std 标准差
    • var 方差
    • sum 求和
    • max 最大值
    • min 最小值
    1 # 计算均值,使用arr.mean() 或 np.mean(arr),二者是等价的
    2 arr = np.array([[1,2,3], [4,5,6], [7,8,9]])
    3 arr, arr.mean(), np.mean(arr)
    (array([[1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]]), 5.0, 5.0)
    1 # 求和
    2 arr.sum(), np.sum(arr)
    (45, 45)
    1 # 求最大值
    2 arr.max(), np.max(arr)
    (9, 9)
    1 # 求最小值
    2 arr.min(), np.min(arr)
    (1, 1)
    1 # 指定计算的维度
    2 # 沿着第1维求平均,也就是将[1, 2, 3]取平均等于2,[4, 5, 6]取平均等于5,[7, 8, 9]取平均等于8
    3 arr.mean(axis = 1)
    array([2., 5., 8.])
    1 # 沿着第0维求和,也就是将[1, 4, 7]求和等于12,[2, 5, 8]求和等于15,[3, 6, 9]求和等于18
    2 arr.sum(axis=0)
    array([12, 15, 18])
    1 # 沿着第0维求最大值,也就是将[1, 4, 7]求最大值等于7,[2, 5, 8]求最大值等于8,[3, 6, 9]求最大值等于9
    2 arr.max(axis=0) #axis=0,col; axis=1,row
    array([7, 8, 9])
    1 # 沿着第1维求最小值,也就是将[1, 2, 3]求最小值等于1,[4, 5, 6]求最小值等于4,[7, 8, 9]求最小值等于7
    2 arr.min(axis=1)
    array([1, 4, 7])
    1 # 计算标准差
    2 arr.std(),np.std(arr)
    (2.581988897471611, 2.581988897471611)
    1 # 计算方差
    2 arr.var()
    6.666666666666667
    1 # 找出最大元素的索引
    2 arr = np.array([[1,2,3], [4,15,6], [7,8,9]])
    3 arr.argmax(), arr.argmax(axis=0), arr.argmax(axis=1),arr
    (4, array([2, 1, 2]), array([2, 1, 2]), array([[ 1,  2,  3],
            [ 4, 15,  6],
            [ 7,  8,  9]]))
    1 # 找出最小元素的索引
    2 arr.argmin(), arr.argmin(axis=0), arr.argmin(axis=1)
    (0, array([0, 0, 0]), array([0, 0, 0]))

    随机数np.random

    • 创建随机ndarray数组

    • 设置随机数种子

    • 随机打乱顺序

    • 随机选取元素

    创建随机ndarray数组

    1 # 生成均匀分布随机数,随机数取值范围在[0, 1)之间
    2 a = np.random.rand(3, 3)
    3 a
    array([[0.6420599 , 0.73651207, 0.66565759],
           [0.14290725, 0.81142629, 0.50289975],
           [0.13405143, 0.45266459, 0.68173151]])
    1 # 生成均匀分布随机数,指定随机数取值范围和数组形状
    2 a = np.random.uniform(low = -1.0, high = 1.0, size=(2,2))
    3 a
    array([[-0.67923749, -0.17730746],
           [ 0.12102881, -0.04428187]])
    1 # 生成标准正态分布随机数
    2 a = np.random.randn(3, 3)
    3 a
    array([[ 0.25665606,  1.93389383, -1.70699442],
           [ 0.97149577, -0.92508515,  0.73949167],
           [ 2.43923963, -1.91191295, -0.74102035]])
    1 # 生成正态分布随机数,指定均值loc和方差scale
    2 a = np.random.normal(loc = 1.0, scale = 1.0, size = (3,3))
    3 a
    array([[0.07006288, 1.45427367, 0.5653806 ],
           [1.33709714, 1.26909652, 2.58879916],
           [0.88281434, 0.93290283, 0.09127028]])

    设置随机数种子

    1 # 可以多次运行,观察程序输出结果是否一致
    2 # 如果不设置随机数种子,观察多次运行输出结果是否一致
    3 np.random.seed(10)  #设置随机数种子,每次都产生同样的随机数
    4 a = np.random.rand(3, 3)
    5 a
    array([[0.77132064, 0.02075195, 0.63364823],
           [0.74880388, 0.49850701, 0.22479665],
           [0.19806286, 0.76053071, 0.16911084]])

    随机打乱ndarray数组顺序

    1 # 生成一维数组
    2 a = np.arange(0, 30)
    3 # 打乱一维数组顺序
    4 print('before random shuffle: ', a)
    5 np.random.shuffle(a)
    6 print('after random shuffle: ', a)
    ('before random shuffle: ', array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
           17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]))
    ('after random shuffle: ', array([13, 26, 21,  3, 25, 28,  6, 20,  2, 10, 27, 19,  4,  5, 12,  8,  0,
            1, 29, 23, 14, 17, 11,  7, 22, 16, 18, 15,  9, 24]))
    1 # 生成一维数组
    2 a = np.arange(0, 30)
    3 # 将一维数组转化成2维数组
    4 a = a.reshape(10, 3)
    5 # 打乱一维数组顺序
    6 print('before random shuffle: 
    {}'.format(a))
    7 np.random.shuffle(a)
    8 print('after random shuffle: 
    {}'.format(a))
     
    before random shuffle: 
    [[ 0  1  2]
     [ 3  4  5]
     [ 6  7  8]
     [ 9 10 11]
     [12 13 14]
     [15 16 17]
     [18 19 20]
     [21 22 23]
     [24 25 26]
     [27 28 29]]
    after random shuffle: 
    [[ 3  4  5]
     [24 25 26]
     [21 22 23]
     [12 13 14]
     [ 0  1  2]
     [ 9 10 11]
     [ 6  7  8]
     [15 16 17]
     [27 28 29]
     [18 19 20]]
    
    随机打乱1维数组顺序时,发现所有元素位置都改变了;随机打乱二维数组顺序时,发现只有行的顺序被打乱了,列的顺序保持不变。

    随机选取元素

    1 # 随机选取一选部分元素
    2 a = np.arange(30)
    3 b = np.random.choice(a, size=50)    #size如果大于30,则有重复的数字
    4 b
    array([ 3,  3, 27, 18, 22, 13, 26, 11, 16, 21, 29, 13, 11, 17, 19, 22,  5,
           11, 21,  1, 11, 24,  0,  5,  9,  8,  5, 11, 11, 26,  7,  8, 21,  8,
           28, 13, 27, 25, 25, 14, 17, 21, 13,  9,  1,  4, 23, 28,  7, 27])

  • 相关阅读:
    7-30-组队赛
    POJ 3125 Printer Queue
    7-28-比赛
    POJ 3922 A simple stone game
    POJ 1845
    第一次组队训练
    I-number
    Radar Installation
    Robots on a grid(DP+bfs())
    Dividing a Chocolate(zoj 2705)
  • 原文地址:https://www.cnblogs.com/yuzaihuan/p/12266353.html
Copyright © 2020-2023  润新知