百度飞浆学习——python中numpy库基础知识

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

基础数据结构ndarray数组

ndarray数组是Numpy中的基础数据结构式

为什么引入ndarray数组

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

  • ndarray数组中所有元素的数据类型是相同的,数据地址是连续的,批量操作数组元素时速度更快;list列表中元素的数据类型可以不同,需要通过寻址方式找到下一个元素
  • ndarray数组中实现了比较成熟的广播机制,矩阵运算时不需要写for循环
  • Numpy底层是用c语言编写的,内置了并行计算功能,运行速度高于纯Python代码

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

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

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

# 2 计算 a和b中对应位置元素的和,是否可以这么写?
a = [1, 2, 3, 4, 5]
b = [2, 3, 4, 5, 6]
c = a + b
# 检查输出发现,不是想要的结果
c
[1, 2, 3, 4, 5, 2, 3, 4, 5, 6]
# 使用for循环,完成两个list对应位置元素相加
c=[]
for i in range(5):
     c.append(a[i]+b[i])
c
[3, 5, 7, 9, 11]
# 使用numpy中的ndarray完成两个ndarray相加
import numpy as np
a = np.array([1, 2, 3, 4, 5])
b = np.array([2, 3, 4, 5, 6])
c = a + b 
c
array([ 3,  5,  7,  9, 11])

从上面的示例中可以看出,ndarray数组的矢量计算能力使得不需要写for循环,就可以非常方便的完成数学计算,在操作矢量或者矩阵时,可以像操作普通的数值变量一样编写程序,使得代码极其简洁。另外,ndarray数组还提供了广播机制,它会按一定规则自动对数组的维度进行扩展以完成计算,如下面例子所示,1维数组和2维数组进行相加操作,ndarray数组会自动扩展1维数组的维度,然后再对每个位置的元素分别相加。

# 自动广播机制,1维数组和2维数组相加

# 二维数组维度 2x5
# array([[ 1,  2,  3,  4,  5],
#         [ 6,  7,  8,  9, 10]])
d = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
# c是一维数组,维度5
# array([ 4,  6,  8, 10, 12])
c = np.array([ 4,  6,  8, 10, 12])
e = d + c
e
array([[ 5,  8, 11, 14, 17],
       [10, 13, 16, 19, 22]])

如何创建ndarray数组

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

  • 从list列表创建

  • 创建值全为1的ndarray数组

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

查看ndarray数组的属性

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

# 数组的数据类型 ndarray.dtype
# 数组的形状 ndarray.shape,1维数组(N, ),二维数组(M, N),三维数组(M, N, K)
# 数组的维度大小,ndarray.ndim, 其大小等于ndarray.shape所包含元素的个数
# 数组中包含的元素个数 ndarray.size,其大小等于各个维度的长度的乘积

a = np.ones([3, 3])
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

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

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

# 转化数据类型
b = a.astype(np.int64)
print('b, dtype: {}, shape: {}'.format(b.dtype, b.shape))

# 改变形状
c = a.reshape([1, 9])
print('c, dtype: {}, shape: {}'.format(c.dtype, c.shape))
b, dtype: int64, shape: (3, 3)
c, dtype: float64, shape: (1, 9)

ndarray数组的基本运算

darray数组可以像普通的数值型变量一样进行加减乘除操作,有两种形式的基本运算:
1. 标量和ndarray数组之间的运算

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

两个ndarray数组之间的运算

# 数组 减去 数组, 用对应位置的元素相减
arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
arr2 = np.array([[11., 12., 13.], [21., 22., 23.]])
arr1 - arr2
array([[-10., -10., -10.],
       [-17., -17., -17.]])

同理,数组加上数组, 用对应位置的元素相加

# 数组 乘以 数组,用对应位置的元素相乘
arr1 * arr2
array([[ 11.,  24.,  39.],
       [ 84., 110., 138.]])

同理,数组 除以 数组,用对应位置的元素相除

# 数组开根号,将每个位置的元素都开根号
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 参数进行,从原数组中切割出一个新数组。

#一维数组索引和切片
a=np.arrange(30)
a[10]
10
a=np.arrange(30)
b=a[4:7]
b
array([4, 5, 6])
# 数组切片是原始数组的视图。这意味着数据不会被复制,
# 视图上的任何修改都会直接反映到源数组上
a = np.arange(30)
arr_slice = a[4:7]
arr_slice[0] = 100
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]))
# 多维数组索引和切片
a = np.arange(30)
arr3d = a.reshape(5, 3, 2)
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]]])
# 只有一个索引指标时,会在第0维上索引,后面的维度保持不变
arr3d[0]
array([[0, 1],
       [2, 3],
       [4, 5]])
# 使用python中的for语法对数组切片

a = np.arange(24)
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])
a=a.reshape([6,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]])
# 使用for语句生成list
[k for k in range(0, 6, 2)]
[0, 2, 4]
# 结合上面列出的for语句的用法
# 使用for语句对数组进行切片
# 下面的代码会生成多个切片构成的list
# k in range(0, 6, 2) 决定了k的取值可以是0, 2, 4
# 产生的list的包含三个切片
# 第一个元素是a[0 : 0+2],
# 第二个元素是a[2 : 2+2],
# 第三个元素是a[4 : 4+2]
slices = [a[k:k+2] for k in range(0, 6, 2)]
slices
[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]])]

Numpy 应用举例——计算激活函数

使用ndarray数组可以很方便的构建数学函数,而且能利用其底层的矢量计算能力快速实现计算。神经网络中比较常用激活函数是Sigmoid和ReLU,其定义如下。
在这里插入图片描述
下面使用numpy和matplotlib计算函数值并画出图形:

# Relu 和sigmoid激活函数示意图
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib,patches as patches
#设置图片大小
plt.figure(figsize=(8,3)
# x是1维数组,数组大小是从-10. 到10.的实数,每隔0.1取一个点
x=np.arrange(-10,10,0.1)
#计算sigmoid函数
s=1.0/(1+np.exp(-x)
# 计算ReLU函数
y=np.clip(x,a_min=0,a_max=None)

##############################################################
# 设置两个子图窗口,将Sigmoid的函数图像画在左边
f=plt.subplot(121)
plt.plot(x,s,color='r')
plt.text(-5,0.9,r'$y=\sigma(x)$',fontsize=13)
# 设置坐标轴格式
currentAxis=plt.gca()
currentAxis.xaxis.set_label_text('x', fontsize=15)
currentAxis.yaxis.set_label_text('y', fontsize=15)
# 将ReLU的函数图像画在右边
f = plt.subplot(122)
# 画出函数曲线
plt.plot(x, y, color='g')
# 添加文字说明
plt.text(-3.0, 9, r'$y=ReLU(x)$', fontsize=13)
# 设置坐标轴格式
currentAxis=plt.gca()
currentAxis.xaxis.set_label_text('x', fontsize=15)
currentAxis.yaxis.set_label_text('y', fontsize=15)

在这里插入图片描述

Numpy应用举例——图像翻转和裁剪

图像是由像素点构成的矩阵,其数值可以用ndarray来表示。可以将上面章节中介绍的操作用在图像数据对应的ndarray上,并且通过图像直观的展示出它的效果。

# 导入需要的包
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

# 读入图片
image = Image.open('./work/images/000000001584.jpg')
image = np.array(image)
# 查看数据形状,其形状是[H, W, 3],
# 其中H代表高度, W是宽度,3代表RGB三个通道
image.shape
(612,,612,3)
# 原始图片
plt.imshow(image)

在这里插入图片描述

# 垂直方向翻转
# 这里使用数组切片的方式来完成,
# 相当于将图片最后一行挪到第一行,
# 倒数第二行挪到第二行,..., 
# 第一行挪到倒数第一行
# 对于行指标,使用::-1来表示切片,
# 负数步长表示以最后一个元素为起点,向左走寻找下一个点
# 对于列指标和RGB通道,仅使用:表示该维度不改变
image2 = image[::-1, :, :]
plt.imshow(image2)

在这里插入图片描述

# 水平方向翻转
image3 = image[:, ::-1, :]
plt.imshow(image3)

在这里插入图片描述

# 保存图片
im3 = Image.fromarray(image3)
im3.save('im3.jpg')
#高度方向裁剪
H,W=image.shape[0],image.shape[1]
H1=H//2
H2=H
image4 =image[H1:H2,:,:]
plt.imshow(image4)

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值