这部分是NumPy数组的快速概述,演示了 n 维 (n>=2) 数组是如何表示和操作的,介绍了如何将常用函数应用于 n 维数组(不使用 for 循环),以及n 维数组的轴和形状属性。
一、基本属性
NumPy的主要对象是同构多维数组。它是一个元素(通常是数字)表,所有元素(通常是数字)都具有相同的类型,由非负整数元组索引。在NumPy中,维度称为轴。
数组对象的基本属性:
属性 | 解释 |
---|---|
ndarray.ndim | 数组的轴数(维数) |
ndarray.shape | 数组的尺寸。返回一个整数元组,元组的长度是轴数,元组中的元素指示每个维度中数组的大小。 |
ndarray.size | 数组的元素总数。这等于shape元组中所有元素的乘积。 |
ndarray.dtype | 描述数组中元素类型的对象。可以使用标准Python类型创建或指定dtype。此外,NumPy还提供了自己的类型,如numpy.int32、numpy.int16 、numpy.float64 |
ndarray.itemsize | 数组中每个元素的大小(以字节为单位) |
ndarray.data | 包含数组实际元素的缓冲区。通常,我们不需要使用此属性,因为我们将使用索引工具访问数组中的元素。 |
a=np.arange(15).reshape(3,5)
print(a)
print(type(a))
print(a.ndim)
print(a.shape)
print(a.size)
print(a.dtype.name)
print(a.itemsize)
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]] # a
<class 'numpy.ndarray'> # type(a)
2 # a.ndim 维数
(3, 5) # a.shape
15 # a.size 3*5=15
int32 # a.dtype
4 # a.itemsize
二、创建数组
1. 从常规Python列表或元组出发创建数组
- 注意参数必须是单个序列,而不能直接输入序列中的各个值
- 可以将序列的序列转化为二维数组,将序列的序列的序列转化为三维数组
- 可以在创建时显式制定数组元素的类型
a=np.array([1,2,3,4,5],dtype=float) # 列表转换为一维数组
b=np.array([(1,2,3,4),(5,6,7,8)]) # 元组的列表转换为二维数组
c=np.array([[( 1, 2, 3, 4),( 5, 6, 7, 8)],
[( 9,10,11,12),(13,14,15,16)],
[(17,18,19,20),(21,22,23,24)]])
[1. 2. 3. 4. 5.] ------- a
[[1 2 3 4]
[5 6 7 8]] ------- b
[[[ 1 2 3 4]
[ 5 6 7 8]]
[[ 9 10 11 12]
[13 14 15 16]]
[[17 18 19 20]
[21 22 23 24]]] ------- c
2. 创建具有初始占位符内容的数组
通常,最初数组的元素是未知的,但其大小是已知的。因此,NumPy提供了几个函数来创建具有初始占位符内容的数组,这最大限度地减少了数组动态增长的必要性。
a=np.zeros((2,3)) # 创建一个充满0的数组,参数是表明数组形状的元组
b=np.ones((2,3)) # 创建一个充满1的数组,参数是表明数组形状的元组
c=np.empty((2,3,4)) # 创建一个数组,其初始内容是随机的
[[0. 0. 0.]
[0. 0. 0.]]
[[1. 1. 1.]
[1. 1. 1.]]
[[[1.06018346e-311 8.26448246e-315 8.26448183e-315 8.26448198e-315]
[1.06018346e-311 1.06018346e-311 8.26448752e-315 1.06018346e-311]
[8.26448325e-315 1.06018346e-311 8.26448183e-315 1.06018346e-311]]
[[8.26448752e-315 1.06018346e-311 8.26448198e-315 1.06018346e-311]
[8.26448183e-315 8.26448183e-315 1.06018346e-311 8.26448214e-315]
[1.06018346e-311 8.26448183e-315 1.06018346e-311 8.26449953e-315]]]
3. 创建数字序列
np.arange(x,y,z):创建一个
[
x
,
y
)
[x,y)
[x,y) 内以z为步长的数组
np.linspace(x,y,z):创建一个
[
x
,
y
]
[x,y]
[x,y] 内步长相同有z个值的数组(平均分成z-1份)
a=np.arange(10,30,5)
b=np.arange(0,2,0.3)
c=np.linspace(0,2,9)
x = np.linspace(0, 2 * math.pi, 10) #在0~2π之间取10个点
y = np.sin(x) #用以绘制y=sin(x)函数图
[10 15 20 25] # a -步长为5,包括10,不包括30
[0. 0.3 0.6 0.9 1.2 1.5 1.8] # b
[0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. ] # c
绘制出x-y关系图,可以看到当点取得够多,就可以绘制出非常平滑的图,因此np.linspace经常被用来生成序列绘制函数图像。
三、打印数组
打印数组时,NumPy 以类似于嵌套列表的方式显示它,但具有以下布局:
- 最后一个轴从左到右打印
- 倒数第二个从上到下打印
- 其余部分也从上到下打印,每个切片与下一个切片之间用空行隔开
然后将一维数组打印为行,将二维数组打印为矩阵,将三维数组打印为矩阵列表。
我尝试了一个四维数组:a=np.arange(120).reshape((2,3,4,5))
[[[[ 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]
[ 30 31 32 33 34]
[ 35 36 37 38 39]]
[[ 40 41 42 43 44]
[ 45 46 47 48 49]
[ 50 51 52 53 54]
[ 55 56 57 58 59]]]
[[[ 60 61 62 63 64]
[ 65 66 67 68 69]
[ 70 71 72 73 74]
[ 75 76 77 78 79]]
[[ 80 81 82 83 84]
[ 85 86 87 88 89]
[ 90 91 92 93 94]
[ 95 96 97 98 99]]
[[100 101 102 103 104]
[105 106 107 108 109]
[110 111 112 113 114]
[115 116 117 118 119]]]]
对于 n p . a r a n g e ( X ) . r e s h a p e ( ( x 1 , x 2 , . . . , x n − 1 , x n ) ) np.arange(X).reshape\big((x_1,x_2,...,x_{n-1},x_n)\big) np.arange(X).reshape((x1,x2,...,xn−1,xn)),满足:
- X = ∏ i = 1 n x i X=\prod\limits_{i=1}^nx_i X=i=1∏nxi
- python显示的结果看起来是一个个矩阵, x n − 1 x_{n-1} xn−1行 x n x_n xn 列
.
如果数组太大而无法打印,NumPy 会自动跳过数组的中心部分,只打印角,要禁用此行为并强制 NumPy 打印整个数组,可以使用 np.set_printoptions(threshold=sys.maxsize)
四、基本运算
1.数组上的算术运算符将逐个计算对应元素 ,并创建一个新数组进行结果填充
注意区别对应元素相乘与矩阵相乘,前者a*b 或np.multiply,后者用a@b或a.dot(b)
a=np.array([(10,20),(30,40)])
b=np.array([(1,2),(3,4)])
print(a-b)
print(a**2)
print(a<25)
print(a*b)
print(np.multiply(a,b))
print(a@b)
print(a.dot(b))
[[ 9 18]
[27 36]] # a-b
[[ 100 400]
[ 900 1600]] # a^2
[[ True True]
[False False]] # a>25
[[ 10 40]
[ 90 160]] # a*b
[[ 10 40]
[ 90 160]] # np.multiply(a,b)
[[ 70 100]
[150 220]] # a@b
[[ 70 100]
[150 220]] # a.dot(b)
2.某些操作(如 +=)会就地修改现有数组,而不是创建新数组
3.当处理不同类型的数组时,生成的数组的类型对应于更通用或更精确的数组类型(这种行为称为 upcasting)
4.许多一元运算(如计算数组中所有元素的总和)都是作为类的方法实现的,作用于整个数组,就好像它是一个数字列表一样,无论其形状如何。通过axis参数也可以沿数组的指定轴应用操作
a=np.array([(10,20),(30,40)])
print(a.sum()) # 求所有元素和 100
print(a.max()) # 求所有元素中的最大值 40
print(a.min()) # 求所有元素中的最小值 10
a=np.array([(10,20),(30,40)])
print(a.sum(axis=0)) # 每一列元素和 [40 60]
print(a.max(axis=0)) # 每一列最大值 [30 40]
print(a.min(axis=1)) # 每一行最小值 [10 30]
五、通用函数
这里列举了一些常用的函数,它们大部分都有着较为丰富的扩展功能以满足各种需求,比如很多计算可以针对整个数组,也可以针对某一个轴进行,且有的操作会改变原数组,而有的操作不改变,这里先不详述,只表达一种最简单的使用情况。
函数 | 解释 |
---|---|
np.exp(A) | 计算指数 |
np.sqrt(A) | 计算平方根 |
np.add(A,B) | 计算数组A,B对应元素相加,即A+B |
np.average(A) | 计算平均值,可以计算加权平均值 |
np.mean(A) | 计算平均值,无法计算加权平均 |
np.maximum(A,B) | 取对应位置较大的元素形成新的数组 |
np.minimum(A,B) | 取对应位置较小的元素形成新的数组 |
np.median(A) | 计算所有元素的中位数 |
np.prod(A) | 计算所有元素相乘的结果 |
np.sort(A) | 返回一个排序后的副本,A本身不变 |
np.std(A) | 计算标准差 |
np.var(A) | 计算方差 |
六、索引 切片和迭代
一维数组的索引、切片、迭代和标准Python序列(如列表)类似。而对于多维的数组:
- 每个轴都可以有一个索引,通过以逗号分隔的元组进行设置。
- 切片时,冒号表示切片范围,逗号隔开不同的轴,…(点号) 表示生成完整索引元组所需的任意数量的冒号
- 迭代多维数组是相对于第一个轴进行的。但是,如果要对数组中的每个元素执行操作,则可以使用属性flat,该属性是数组中所有元素的迭代器.
这里打算另外写一篇详细探讨