Python之NumPy

一、NumPy是什么?

  • NumPy是Python的外部库,经常用于数组和矩阵的计算。
  • NumPy虽然是Python的外部库,但NumPy中主要的处理都是用C语言或者C++来编写的,所以同时具有优良的性能(C、C++)和便利的语法(Python)。

二、安装NumPy

在命令行使用下面的命令即可:

pip install numpy

三、引入NumPy库

引入NumPy库:

import numpy as np
  • import numpy是引入NumPy库。
  • 然后as np是把这个库的名称简写为np,这样在代码中只需要用np即可调用库中的类和函数。这个不是必需的,但通常都会这么写,在后面代码的编写中会比较方便。

四、NumPy数组

1. 生成NumPy数组(numpy.ndarray)

a. 使用array()函数

  • 使用NumPy库中的array()函数可将列表(list)类型或元组(tuple)类型转为NumPy数组(numpy.ndarray)类型。
  • 使用type()函数可以查看一个对象的类型。

例如:

a = np.array([0, 1, 2, 3])
print(type([0, 1, 2, 3])) # >>><class 'list'>
print(type(a)) # >>><class 'numpy.ndarray'>
print(a) # >>>[0 1 2 3]

b = np.array((4, 5, 6, 7))
print(type((4, 5, 6, 7))) # <class 'tuple'>
print(type(b)) # <class 'numpy.ndarray'>
print(b) # >>>[4 5 6 7]

b. 使用arange()函数

  • 使用NumPy库中的arange()函数可以生成一个固定差值的NumPy数组。
  • 使用arange()有三种情况:
    ①一个参数:arange(<终点>)
    ②两个参数:arange(<起点>, <终点>)
    ③三个参数:arange(<起点>, <终点>, <固定差值>)
    这三种情况中,如果没有固定差值参数,那么默认为1;如果没有起点参数,默认为0;数组不包含终点

例如:

a = np.arange(5)
b = np.arange(4, 9)
c = np.arange(3, 8, 2)
print(a) # >>>[0 1 2 3 4]
print(b) # >>>[4 5 6 7 8]
print(c) # >>>[3 5 7]

2. N维NumPy数组

  • NumPy不仅可以生成像上面例子中的一维数组(排成一排的数组),还能生成多维的数组。

a. 二维数组(矩阵)

  • 在数学上一维数组称为“向量”,而二维数组称为“矩阵”。
    例如下面的代码生成了一个3×2的二维数组:
a = np.array([[1, 2],
			  [3, 4],
			  [5, 6]])
print(a)
'''
>>>[[1 2]
    [3 4]
    [5 6]]
'''

b. 多维数组(张量)

  • 同理还能生成三维乃至更多维的数组,通常将三维或三维以上的数组称为“张量”或者“多维数组”。

3. 访问NumPy数组元素

  • 如果数组的下标是自然数,从0开始,从左到右不断累加1增大。
  • 如果下标是负数,表示从右到左的序号。
  • 一维数组的访问方式:<数组名>[<下标>]

例如:

a = np.array([4, 8, 6, 9])
print(a[0]) # >>>4
print(a[3]) # >>>9
print(a[-1]) # >>>9

一维数组a中有4个元素,4、8、6、9的下标分别为0、1、2、3,所以a[0]为4,a[3]为9,下标为-1,表示从右到左第一个元素,所以是9。

  • 如果是二维数组,那么访问元素的方式为:<数组名>[<0维下标>][<1维下标>],或者是:<数组名>[<0维下标>, <1维下标>]。

例如:

a = np.array([[1, 2],
			  [3, 4],
			  [5, 6]])
print(a[1][0]) # >>>3
print(a[1, 0]) # >>>3

数组a的0维下标为1的部分是数组[3, 4],然后在数组[3, 4]内的下标就是数组a的1维下标,所以数组a[1][0]表示的是[3, 4]下标为0的数,所以是3。

  • 同理,N维数组元素的访问方式为:<数组名>[<0维下标>][<1维下标>]…[<N-1维下标>]或者:<数组名>[<0维下标>, <1维下标>, … ,<N-1维下标>]

4. NumPy数组切片

a. 一维数组切片

  • 一维数组切片形如a[i: j: k]
  • i 为开始下标,j 为结束下标,k 为步长。
  • a[i: j: k]表示从a中取下标为 i 的元素,以每隔步长 k 的距离取元素,一直到下标为 j 的元素(不包括下标为 j 的元素)。
  • 没有 i 时,i 默认为0;没有 j 时,j 默认为数组最后一个元素下标+1,即数组长度;没有 k 时,k 旁边的 : 也需要缺省掉,k 默认为1。
    例如:
a = np.array([0, 1, 2, 3, 4, 5, 6]) #长度为7的数组,下标从0到6

#没有步长k,步长k默认为1
print(a[2: 5]) # >>>[2 3 4]
print(a[: 4]) # >>>[0 1 2 3]
print(a[0: 4]) # >>>[0 1 2 3]
print(a[3: ]) # >>>[3 4 5 6]
print(a[3: 7]) # >>>[3 4 5 6]
print(a[: ]) # >>>[0 1 2 3 4 5 6]

#有步长k
print(a[1: 6: 2]) # >>>[1 3 5]
print(a[1: 5: 2]) # >>>[1 3]
print(a[: 7: 3]) # >>>[0 3 6]
print(a[0:: 3]) # >>>[0 3 6]
print(a[:: 3]) # >>>[0 3 6]

b. 二维数组切片及多维数组切片

  • 二维数组的切片和一维数组类似,结构形如a[i: j: k, l: m: n]
  • i 为0维开始下标,j 为0维结束下标,k 为0维步长;l 为1维开始下标,m 为1维结束下标,n 为1维步长。
  • a[i: j: k]表示从a的0维中取下标为 i 的元素,以每隔步长 k 的距离取元素,一直到下标为 j 的元素(不包括下标为 j 的元素);然后从a的1维中取下标为 l 的元素,以每隔步长 n 的距离取元素,一直到下标为 m 的元素(不包括下标为 m 的元素)。
  • 没有 i 或 l 时,i 或 l 默认为0;没有 j 或 m 时,j 或 m 默认为数组最后一个元素下标+1,即数组长度;没有 k 或 n 时,k 或 n 旁边的 : 也需要缺省掉,k 或 n 默认为1。

例如:

a = np.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]])
print(a[0, 1:4]) # >>>[1 2 3]
print(a[1: 4, 0]) # >>>[ 5 10 15]
print(a[::2, ::2]) 
'''
>>>[[ 0  2  4]
	[10 12 14]
	[20 22 24]]
'''
print(a[:, 1]) # >>>[ 1  6 11 16 21]

上面的代码不够直观,结合下图更容易理解:
在这里插入图片描述

  • 从二维数组切片特征可推知多维数组切片特征。

5. NumPy数组的属性

a. 维度(ndim)

  • NumPy数组的属性ndim可以反映数组的维度。

例如:

a = np.array([0, 1])
b = np.array([[0, 1], [2, 3], [4, 5]])
c = np.array([[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]])
print(a.ndim) # >>>1
print(b.ndim) # >>>2
print(c.ndim) # >>>3

b. 形状(shape)

  • NumPy数组的属性shape可以反映数组的形状。
  • 这个shape属性是一个元组(tuple)类型的值,所以一维数组的shape会用小括号里一个数字加一个逗号的形式表示。

例如:

a = np.array([0, 1])
b = np.array([[0, 1], [2, 3], [4, 5]])
c = np.array([[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]])
print(a.shape) # >>>(2,)
print(b.shape) # >>>(3, 2)
print(c.shape) # >>>(2, 2, 3)

在上面这个例子中,数组b的shape为(3, 2),表示b的0维(维度的索引从0开始)是3,1维是2。可以看到b最外的一个括号内用两个逗号隔开了三个小数组,所以b的第0维是3,然后每个小数组内分别有两个数,所以b的第1维是2。

c. 元素的数据类型(dtype)

  • NumPy数组的属性dtype可以反映数组中元素的类型。

例如:

a = np.array([0, 1])
b = np.array([0.0, 1.0])
c = np.array([2, 3.0])
print(a.dtype) # >>>int32
print(b.dtype) # >>>float64
print(c.dtype) # >>>float64
print(type(c[0])) # >>><class 'numpy.float64'>
print(type(c[1])) # >>><class 'numpy.float64'>
print(c[0]) # >>>2.0

在上述例子中,int32表示用32位二进制数表示的整数(int)类型,float64表示用64位二进制数表示的浮点数(float)类型。

  • NumPy数组的元素类型要保持一致。

像上面的数组c,向array()函数传入的列表中有整数2和浮点数3.0,但生成的NumPy数组中整数2变成了浮点数2.0。

d. 元素总数(size)

  • NumPy数组的属性size可以反映数组中所有元素个数。

例如:

a = np.array([0, 1])
b = np.array([[0, 1], [2, 3], [4, 5]])
c = np.array([[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]])
print(a.size) # >>>2
print(b.size) # >>>6
print(c.size) # >>>12

e. 元素所占字节数(itemsize)

  • NumPy数组的属性itemsize可以反映数组中一个元素所占的字节数。

例如:

a = np.array([0, 1])
print(a.dtype) # >>>int32
print(a.itemsize) # >>>4

b = np.array([0.0, 1.0])
print(b.dtype) # >>>float64
print(b.itemsize) # >>>8

上述例子中,因为数组a中的元素类型为int32,32位是 32 / 8 = 4 个字节,所以a的itemsize是4;而数组b中的元素类型为float64,64位是 64 / 8 = 8 个字节,所以b的itemsize是8。

f. NumPy数组所占字节数(nbytes)

  • NumPy数组的属性nbytes可以反映这个数组所占的字节数。但这个属性的值没有算上数组的开销,而是只是所有元素所占的总字节数,即 ntytes = itemsize * size 。

例如:

a = np.array([0, 1])
b = np.array([[0, 1], [2, 3], [4, 5]])
c = np.array([0.0, 1.0])
print(a.nbytes) # >>>8
print(b.nbytes) # >>>24
print(c.nbytes) # >>>16

上面这个例子中,数组a中元素为inf32,占4个字节,一共有两个元素,所以总字节数为 4 * 2 = 8 ;数组b的总字节数为 4 * 6 = 24 ;而数组c中元素为float64,占8个字节,一共有两个元素,所以总字节数为 8 * 2 = 16 。

五、使用NumPy数组

1. 基本运算符

  • NumPy数组的加减乘除分别使用符号:+、-、*、/。
  • 两个数组的结构相同才能进行加减乘除运算,对应元素分别进行运算。
  • 数字和NumPy数组运算会使数字分别与每一个元素进行计算。

例如:

a = np.array([2, 5, 8])
b = np.array([1, 2, 3])

print(a + b) # >>>[ 3  7 11]
print(a - b) # >>>[1 3 5]
print(a * b) # >>>[ 2 10 24]
print(a / b) # >>>[2.         2.5        2.66666667]

print(a / 2) # >>>[1.  2.5 4. ]

可以注意到,即使两NumPy数组的元素类型都是整型,使用除法会使结果变成浮点型。

  • 取整除法使用//符号进行运算。

例如:

a = np.array([2, 5, 8])
b = np.array([1, 2, 3])
print(a // b) # >>>[2 2 2]
  • 次方使用**符号计算。

例如:

a = np.array([2, 5, 8])
b = np.array([1, 2, 3])
print(a ** b) # >>>[  2  25 512]

2. 特殊运算符

除了加减乘除,NumPy还提供了一些很方便的运算符。

  • <数组名>.sum():可以计算数组中所有元素的累加值。
  • <数组名>.max():可以得到数组中最大的值。
  • <数组名>.min():可以得到数组中最小的值。
  • <数组名>.mean():可以计算数组中所有元素的平均值。
  • <数组名>.argmax():可以得到数组中最大值的下标,如果有多个符合条件,则会得到下标最小的那个。
  • <数组名>.argmin():可以得到数组中最小值的下标,如果有多个符合条件,则会得到下标最小的那个。

例如:

a = np.array([5, 2, 6, 8, 4, 2])
print(a.sum()) # >>>27
print(a.max()) # >>>8
print(a.min()) # >>>2
print(a.mean()) # >>>4.5
print(a.argmax()) # >>>3
print(a.argmin()) # >>>1

3. 点积

  • 使用np.dot(a, b)可以计算数组a和数组b的点积。
  • 使用点积的两个数组必须满足:前一个数组的最大维度的大小要等于后一个数组的0维的大小。
  • 两个一维数组使用点积,相当于两个数组对应元素相乘后的累加值。
  • 两个二维数组使用点积,相当于矩阵乘法。
  • 两个一维数组使用点积,交换两数组的位置,值仍然不变;但二维及二维以上数组使用点积,如果交换了两个数组的位置,值不一定相等。

例如:

a = np.array([1, 4, 3])
b = np.array([3, 2, 1])
print(np.dot(a, b)) # >>>14
print(np.dot(b, a)) # >>>14
print(np.sum(a * b)) # >>>14

c = np.array([[ 1,  2,  3],
			  [ 4,  5,  6],
			  [ 7,  8,  9],
			  [10, 11, 12]])
d = np.array([[1, 2],
			  [3, 4],
			  [5, 6]])
print(c.shape) # >>>(4, 3)
print(d.shape) # >>>(3, 2)
print(np.dot(c, d))
'''
[[ 22  28]
 [ 49  64]
 [ 76 100]
 [103 136]]
'''
#print(np.dot(d, c)) #ValueError: shapes (3,2) and (4,3) not aligned: 2 (dim 1) != 4 (dim 0)

在上面的例子中,c的形状是(4, 3),d的形状是(3, 2)。c在前,d在后。c的最高维1维大小为3,d的0维大小也为3,所以c和d才能进行点积计算。但如果倒过来,d的最高维1维是2,c的0维是4,两者不相等,所以进行点积运算会报错。

4. 索引进阶

  • 一次获取多个下标对应的元素方法:将下标列表放入[]。

例如:

a = np.arange(8) # a = [0 1 2 3 4 5 6 7]
print(a[[1, 4, -1]]) # >>>[1 4 7]
  • 从数组中找到符合条件的元素的方法:将条件放入[]。
  • 使用np.where()也可以达到筛选元素的效果,但返回的是符合条件的元素构成数组的元组,需要直接得到符合条件的元素数组,要多加一个[0]。

例如:

a = np.arange(8) # a = [0 1 2 3 4 5 6 7]
print(a[a < 3]) # >>>[0 1 2]
print(np.where(a < 3)) # >>>(array([0, 1, 2], dtype=int64),)
print(np.where(a < 3)[0]) # >>>[0 1 2]

参考:http://www.numpy.org.cn/article/basics/an_introduction_to_scientific_python_numpy.html#%E6%95%B0%E7%BB%84%E5%9F%BA%E7%A1%80

如有错误,欢迎指出!如有问题,欢迎讨论!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值