Numpy


  Numpy是 Python 语言的一个扩展程序库,其中提供了许多向量和矩阵操作,底层用C语言编写,其对数组的操作速度不受python解释器的限制,处理速度快,效率远高于纯python代码。查看当前使用numpy的版本:

import numpy as np
print(np.version())	#1.26.4

一、数据维度的概念

  维度是数据的组织形式。

1.1常见的多维数据

1.一维数据
  一维数据由对等关系的有序或无需数据构成,采用线性方式组织。常见的一维数据组织形式如列表(数据元素可不同,有序)、数组(数据元素相同、有序)、集合(数据元素可不同,无序)。一维数组使用一个下标即可确定一个元素。
在这里插入图片描述
2.二维数据
  二维数据是一维数据的组合形式,常见的表格就是二维数据格式。二维数组使用两个下标确定一个元素,其中第一个下标表示一维数组,第二个下标表示数据在该一维数组中的位置
在这里插入图片描述
在numpy当中,使用一维数组的集合来表示二维数组:

print(np.array([[1,  2],  [3,  4]]) )

在这里插入图片描述
3.三维数据
  三维数据是二维数据的组合形式(在新维度上扩展形成),表现为一个数据立方体。三维数组使用三个下标确定一个元素,其中第一个下标确定二维数组、第二个下标确定二维数组中的一维数组、第三个下标确定元素的位置。
在这里插入图片描述
在numpy当中,使用二维数组的集合来表示三维数组:

print(np.array([[[1,  2],  [3,  4]],[[5,  6],  [7,  8]]]) )

在这里插入图片描述

1.2numpy的维度、形状、轴

1.2.1维度

  在机器学习、线性代数当中常见的m维行向量、n维列向量、mxn阶矩阵的概念如下:

  • m维行向量:一个行向量中有m列数据。
  • n维列向量:一个列向量中有n行数据。
  • mxn阶矩阵:可看作是m个n维列向量,或是n个m维行向量组成。

但在numpy当中,维度(dimension)指的是坐标系的维度,如一维指只有x轴、二维指xoy坐标系、三维指xoyz坐标系,由于不同坐标系所含轴数不同,所以numpy中维度也可指数组轴(axis)的数目,并且可以使用.ndim获取数组的轴数(维度数):

# 创建零维数组(标量)
arr0=np.array(1)
# 创建一维数组
arr1=np.array([1,2,3,4])
# 创建二维数组
arr2=np.array([[1,2,3],[4,5,6]])
# 创建三维数组
arr3=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
print(f'零维数组的轴数为{arr0.ndim},一维数组的轴数为{arr1.ndim},二维数组的轴数为{arr2.ndim},三维数组的轴数为{arr3.ndim}')

在这里插入图片描述
事实上,也可通过数组包含方括号的个数来判断数组的维度,如[[[...]]]是三维,而[[[[[[......]]]]]]是六维。

注意,[1]与1是不同的概念,前者表示只含有一个元素的一维数组,其轴为1,而后者表示标量,轴为零。

1.2.2形状

  数组形状描述了这个数组的样式,即有多少行、多少列以及在更高维度中如何组织数据。numpy中的数组提供了属性shape来返回一个用于表示数组形状的元组,如:

arr=np.array([[[1,2],[3,4]],[[5,6],[7,8]],[[9,10],[11,12]]])
print(f'数组的形状是{arr.shape}')

在这里插入图片描述
即三维数组中包含了3个二维数组,每个二维数组都包含2个一维数组,每个一维数组都包含了两个元素。事实上,从属性返回的元组也可看出数组的维度:

  • ():表示零维。
  • (5,):表示一维。注意区分元组中(5)和(5,)。
  • (2,3):表示二维。
  • (2,3,4):表示三维。

1.2.3轴

  前文提到,numpy中的轴(axis)与坐标系轴的概念类似且有着自己的方向。事实上,numpy使用axis 序号作为轴的名称,从0开始计数,数组维度与axis的取值关系如下:
在这里插入图片描述
注意,axis=0每次表示的都是新增轴。
1.一维数组的轴
在这里插入图片描述
  一维数组只包含axis=0轴,代表数组的列变换:

arr=np.array([1,2,3])
print(arr)
print(arr.shape)

在这里插入图片描述
其中,axis=0对应shape属性中的3,表示该轴方向上共有三组元素可供操作。

2.二维数组的轴

在这里插入图片描述
  在二维数组中,使用axis=0(0轴)表示新增的横轴(横并不是axis的指向),代表行变换,用axis=1表示竖轴,代表列变换。并且,每个轴都对应shape属性中的一个元素,如:
在这里插入图片描述
其中,axis=0对应3,表示共有三行(三个一维数组)元素,axis=1对应4,表示共有四列(每个一维数组有四个)元素。

3.三维数组的轴

在这里插入图片描述

arr=np.arange(1,19).reshape(3,2,3)
print(arr)

在这里插入图片描述

  • axis=0:表示新增轴,此处可理解为深度,对应arr.shape[0],表示包含两个三维数组。
  • axis=1:表示横轴,对应arr.shape[1],表示每个二维数组包含两个一维数组。
  • axis=2:表示数轴,对应arr.shape[2],表示每个一维数组含有3个元素。

1.3reshape()函数

  np.reshape()函数是numpy 中用于改变数组形状的函数,注意,传入数组大小的乘积(一般使用元组表示)必须等于数组中元素的个数。例:

array  = np.array([1,2,3,4,5,6,7,8,9,10,11,12])
array.reshape(2,2,3)

在这里插入图片描述
即,数组共有12个元素,而2*2*3=12.

1.4numpy中行、列向量的表示

  在numpy中创建42的数组a与21的矩阵b,并对二者使用点乘操作np.dot()

# 创建4*2数组
a = np.array([[1,1,1,1],[1,1,1,1]]).T
# 创建一维数组b
b = np.array([2,3]) 
# 点乘操作a·b
print('a·b=',np.dot(a,b))

# 将b数组转置
b = b.T
# 点乘操作a·b
print('a·b=',np.dot(a,b))

在这里插入图片描述

  • 若b表示2维行向量:42矩阵与12矩阵相乘应报错,但没有。
  • 若b表示2维列向量:42矩阵与21矩阵相乘应报错,但没有。

即,一维数组b既可表示行向量,也可表示列向量。并有以下结论

  • numpy中的一维数组可同时表示行、列向量,这取决于和它进行点乘的矩阵是什么。
  • 在习惯上为避免不确定是行还是列向量,可使用二维数组表示行列向量。如:
a = np.array([[2,3]]) #行向量
b = np.array([[2],[3]]) #列向量
print(a.shape)
print(b.shape)

在这里插入图片描述

1.5数组的迭代

  NumPy包含一个迭代器对象numpy.nditer,可以用于在数组上进行迭代。

a = np.array([[1,2,3],[4,5,6]])
for x in np.nditer(a):
    print(x)

在这里插入图片描述

1.6添加/删除元素

在这里插入图片描述

1.6.1append()

  此函数用于在输入数组的末尾添加值:

numpy.append(arr, values, axis)
  • arr:输入数组。
  • values:要向arr添加的值,比如和arr形状相同(除了要添加的轴)。
  • axis:沿着它完成操作的轴。如果没有提供,两个参数都会被展开。
 import numpy as np 
a = np.array([[1,2,3],[4,5,6]]) 
 
print('原始数组:')
print(a)
print('\n')  
 
print('向数组添加元素:')
print(np.append(a, [7,8,9])) 
print('\n')
 
print('沿轴 0 添加元素:')
print(np.append(a, [[7,8,9]],axis = 0))
print('\n')
 
print('沿轴 1 添加元素:')
print(np.append(a, [[5,5,5],[7,8,9]],axis = 1))

在这里插入图片描述

1.6.2insert()

  此函数用于向数组中插入元素:

 numpy.insert(arr, obj, values, axis)
  • arr:输入数组。
  • obj:在其之前插入值的索引。
  • values:要插入的值。
  • axis:沿着它插入的轴,如果未提供,则输入数组会被展开。
a = np.array([[1,2],[3,4],[5,6]]) 
 
print('第一个数组:')
print(a)
 
print('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print(np.insert(a,3,[11,12]))
print('\n')
print('传递了 Axis 参数。 会广播值数组来配输入数组。')
 
print('沿轴 0 插入:')
print(np.insert(a,1,[11],axis = 0))
print('\n')
 
print('沿轴 1 插入:') 
print(np.insert(a,1,11,axis = 1))

在这里插入图片描述

1.6.3delete()

  此函数返回从输入数组中删除指定子数组的新数组。 与insert()函数的情况一样,如果未提供轴参数,则输入数组将展开。 该函数接受以下参数:

Numpy.delete(arr, obj, axis)
import numpy as np 
a = np.arange(12).reshape(3,4) 
 
print('第一个数组:')
print(a)
print('\n')
 
print('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print(np.delete(a,5))
print('\n')
 
print('删除第二列:')  
print(np.delete(a,1,axis = 1))
print('\n')
 
print('包含从数组中删除的替代值的切片:')
a = np.array([1,2,3,4,5,6,7,8,9,10])
print(np.delete(a, np.s_[::2]))

在这里插入图片描述

二、Ndarray对象

2.1简介

  NumPy 中定义的最重要的对象是称为 ndarray 的 N 维数组类型。 它描述相同类型的元素集合,可以使用基于零的索引访问集合中的元素。由于数据类型确定,ndarray中的每个元素在内存中使用相同大小的块。事实上,ndarray由实际的数据、描述这些数据的元数据(数据维度、数据类型等信息)两部分构成,打印输出时,使用[]表示。

2.1.1常用属性

在这里插入图片描述

arr=np.array([[1,2,3],[4,5,6]])
print(f'arr.ndim={arr.ndim}\narr.shape={arr.shape}\naarr.size={arr.size}\narr.dtype={arr.dtype}')

在这里插入图片描述

2.1.2.ndarray对象的数据类型

类型类型代码说明
int8/16/32/64i1/i2/i4/i8 (数字表示字节数)有符号8/16/32/64位整数
uint8/16/32/64u1/u2/u4/u8 (数字表示字节数)无有符号8/16/32/64位整数
float16/32/64/128f2/f4/f8/f16(数字表示字节数)半精度浮点数、标准的单精度浮点数(与C语言float兼容)、标准的双精度浮点数(与C语言的double、Python的float对象兼容)、扩展精度浮点数
complex64/128/256c8/c16/c32分别用两个32位,64位,128位浮点数表示的复数(含实部与虚部)
bool?存储True和False值的布尔类型
objectOpython对象类型
StringS固定长度的字符串类型(每个字符一个字节)。例如:要创建一个长度为10的字符串,应使用S10
unicode_U固定长度的Unicode类型(字节数由平台决定)跟字符串的定义方式一样
np.array(range(10),dtype='f') 

在这里插入图片描述

2.2创建ndarray对象

2.2.1array()

  array()是最基本的ndarray对象创建函数,接收一切序列型的对象,比如:列表、元组、可迭代对象等,也包括它自己。

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

在这里插入图片描述
当不指定dtype时,numpy将根据实际情况创建:

# 1.当不指定dtype时,NumPy将根据数据情况关联一个dtype类型
array = np.array([[1,2,3],[4,5,6]])
print(array.dtype) # int32

# 2.指定dtype进行创建
np.array([1,2+2.5j,3.1-5j],dtype=complex) # [1. +0.j  2. +2.5j 3.1-5.j ]

# 3.使用序列创建
arr1=np.array([0,1,2,3]) # 使用列表创建
arr2=np.array((0,1,2,3)) # 使用元组创建
arr3=np.array([[1,2],[3,4],(0.1,0.2)]) # 列表+元组创建

2.2.2arange()

  arange()可用于创建指定数据范围的ndarray对象。

numpy.arange(start, stop, step, dtype)

在这里插入图片描述

np.arange(5, dtype=float) # [0. 1. 2. 3. 4.]

2.2.3empty()

  empty()返回一个新的未初始化的数组,这意味着新数组的内容是未定义的,它包含了数组创建时存在于内存中的任意数据。
在这里插入图片描述

np.empty((3,3,2))

在这里插入图片描述

2.2.5ones()、zeros()、full()

  ones()zeros()用于返回用1、0填充的ndarray对象:

numpy.ones(shape, dtype = None, order = 'C')
numpy.zeros(shape, dtype = None, order = 'C')

在这里插入图片描述

np.zeros(5)  # 默认类型为float64

在这里插入图片描述
  full()用于返回一个使用指定值填充的ndarray对象:

np.full(shape, fill_value, dtype=None, order='C')

在这里插入图片描述

np.full((2, 2), np.inf)

在这里插入图片描述

2.2.6eye()

  eye()用于返回一个使用指定值填充的对角方阵。

np.eye(N, M=None, k=0, dtype=float, order='C')

在这里插入图片描述

a = np.eye(5, k=-2)
b = np.eye(5, k=2)
c = np.eye(5)
print(a) # 右移两格
print(b) # 左移两格
print(c) # 对角方阵

在这里插入图片描述

2.2.7repeat()

  将输入值的整体或某部分,在原来的基础上,进行指定次数的复制,从而创建新的输出值。

np.repeat(a, repeats, axis=None)

在这里插入图片描述

x=np.array([[1,2],[3,4]])
# 沿axis=0方向分别复制一次、两次
np.repeat(x,[1,2],axis=0)

在这里插入图片描述

2.2.8linspace()

  linspace()用于创建指定范围的等差数组,

numpy.linspace(start, stop, num, endpoint, retstep, dtype)

在这里插入图片描述

# 生成10~20含有5个数的等差数列
np.linspace(10,20,5)

在这里插入图片描述

2.2.9logspace()

numpy.logscale(start, stop, num, endpoint, base, dtype)

在这里插入图片描述

#生成100~1000含有50个数的等比数列
np.logspace(2,3,50)

在这里插入图片描述

2.2.10asarray()

  asarray()用于将输入的python序列转化为ndarray对象,类似于array():

numpy.asarray(a, dtype = None, order = None)

在这里插入图片描述

list1 = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
np.asarray(list1)

在这里插入图片描述

三、Ndarray维度变换

  numpy提供以下函数对ndarray数组进行维度变换变换:
在这里插入图片描述

3.1reshape()

reshape(a, newshape, order='C')
#1.reshape,返回新数组,不会改变原数组
arr=np.array([[1,2,3],[4,5,6]])
b=arr.reshape(3,2)
print('arr=',arr)
print('b=',b)

在这里插入图片描述

3.2resize()

resize(a, new_shape)
#2.resize,直接在原数组上进行修改,无返回值
arr=np.array([[1,2,3],[4,5,6]])
arr.resize(3,2)
print(arr)

在这里插入图片描述

3.3swapaxes()

swapaxes(a, axis1, axis2)
  • a:要进行轴交换的数组。
  • axis1:要交换的第一个轴的索引。
  • axis2:要交换的第二个轴的索引。

  因为ndarray.swapaxes()需要2个轴作为入参,所以,一维数组不可调用swapaxes()。在使用ndarray.swapaxes()后,访问元素所用的索引发生了调换:
在这里插入图片描述

3.4flatten()

  对数组进行降维,返回一维数组,原数组保持不变,属于深拷贝(新数组被分配了新的地址,所以改变自身的值,原值不受影响):

a = np.arange(12).reshape(2, 3, 2)
b=a.flatten()
b[0]=20
print(a)
print(b)

由于是深拷贝,当b的值进行修改时,a数组中对应的值并未改变。
在这里插入图片描述

3.5ravel()

  对数组进行降维,返回一维数组,原数组发生改变,属于浅拷贝(返回新对象的指针仍指向原数组):

a = np.arange(12).reshape(2, 3, 2)
b=a.ravel()
b[0]=20
print(a)
print(b)

由于是浅拷贝,当b的值进行修改时,a数组中对应的值发生改变。
在这里插入图片描述

四、类型变换、拼接、分割

4.1astype()

  astype()函数可用于array中数值类型的转换。

arr = np.arange((10))
print(arr, arr.dtype, sep="\n")
arr = arr.astype("float32")
print(arr, arr.dtype, sep="\n")

在这里插入图片描述

4.2tolist()

  numpy中提供了dnarray向list类型转换的函数,若直接使用list(),则无法完全进行转换:

arr=np.array([[1,2,3],[4,5,6]])
list(arr)

在这里插入图片描述

arr=np.array([[1,2,3],[4,5,6]])
arr.tolist()

在这里插入图片描述

4.3T()

  numpy对二维数组提供了转置操作:

arr=np.array([[1,2,3],[4,5,6]])
arr.T

在这里插入图片描述

4.4vstack():垂直堆叠

numpy.vstack(tup)

  vstack()函数用于在垂直方向上堆叠数组,即将多个数组按行方向堆叠,其中,tup是包含了要堆叠数组的元组,这些数组必须有相同的列数。

#一维数组
a = np.array([1,2,3])
b = np.array([4,5,6])
print(np.vstack((a,b)) )
#二维数组
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
print(np.vstack((a,b)))
#三维数组
a = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
b = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
print(np.vstack((a,b)))

在这里插入图片描述

4.5hstack():水平堆叠

  hstack()表示进行水平堆叠,实质是按axis=1将每个垂直的列都堆叠在一起,则要求行数相等:

#一维数组
a = np.array([1,2,3])
b = np.array([4,5,6])
print(np.hstack((a,b)) )
#二维数组
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
print(np.hstack((a,b)))
#三维数组
a = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
b = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
print(np.hstack((a,b)))

在这里插入图片描述

4.7stack():自定义堆叠

np.stack(arrays, axis=0, out=None)
a = np.arange(0,2)
b = np.arange(2,4)
c = np.arange(4,6)
'''
[0, 1]
[2, 3]
[4, 5] ->
沿着axis=0堆叠:
[[0, 1],
[2, 3],
[4, 5],]
'''


a = np.arange(0,2)
b = np.arange(2,4)
c = np.arange(4,6)
'''
[0, 1]
[2, 3]
[4, 5] ->
沿着axis=1拼接:
[[0,2,4],
[1,3,5]]
'''
np.stack((a,b,c), axis=1)

4.8concatenate():自定义拼接

numpy.concatenate((a1, a2, ...), axis=0, out=None)

  concatenate()函数用于沿指定轴将多个数组合并成一个新的数组。

  • (a1, a2, ...):要合并的数组序列,以元组形式传入。
  • axis:指定合并的轴,即沿着哪个维度进行合并。默认值为 0,表示沿着第一个维度进行合并。
  • out:指定输出数组的可选参数。

1.合并一维数组

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
np.concatenate((a,b))

在这里插入图片描述
2.合并二维数组

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print(np.concatenate((a,b)))
print(np.concatenate((a,b),axis=1))

在这里插入图片描述

4.9split()

  split()函数用于将一个数组拆分为多个子数组,返回的是多个数组。

split(ary, indices_or_sections, axis=0)
  • ary:待分割的原始数组。
  • indices_or_sections:int或者一维数组,表示一个索引,也就是切的位置所在。
    • int:用这个数平均分割原数组。
    • 一维数组:以数组中的数字为索引切开。
  • axis:选定切的维度。
x = np.array([1,2,3,4,5,6,7,8,9])
# 平均切分为3个数组
print(np.split(x, 3))

A = np.arange(36).reshape((2, 2, 9)) 
#表示按axis=2,即(2,2,9)中的9处切分,切分为[0:2]、[3:5]、[6:8]3个数组
[A1, A2, A3] = np.split(A, [3, 6], axis=2)
print(A1, A2, A3,sep='\n')

在这里插入图片描述

五、索引与切片

  nadarry数组的操作包括数组的索引和切片。

  • ①索引:获取数组中特定位置元素的过程。
  • ②切片:获取数组元素子集的过程。

5.1切片

一维数组的切片

a = np.array([9,8,7,6,5])
print(a[2])	# 7
print(a[1:4:2]) #起始编号:终止编号(不含):步长
# [8 6]

二维数组的切片

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

三维数组的切片

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

  切片还可以包括省略号(…),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的数组。

a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]])
print(a)
"""
[[1 2 3]
 [3 4 5]
 [4 5 6]]
"""
# 这会返回第二列元素的数组:
print(a[..., 1])
"""
[2 4 5]
"""
# 现在我们从第二行切片所有元素:
print(a[1, ...])
"""
[3 4 5]
"""
# 现在我们从第二列向后切片所有元素:
print(a[..., 1:])
"""
[[2 3]
 [4 5]
 [5 6]]
"""

5.2索引

a = np.arange(24).reshape((2, 3, 4))
print(a)
print(a[1, 2, 3])  #每个维度一个索引值,逗号分割
print(a[-1, 2, -2])
"""
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
"""
"""
23
22
"""

布尔索引:使用布尔数组作为索引。arr[condition],condition为一个条件/多个条件组成的布尔数组。

x = np.array([3, 2, 3, 1, 3, 0])
# 布尔型数组的长度必须跟被索引的轴长度一致
y = np.array([True, False, True, False, True, False])
print(x[y])  # [3,3,3]
print(x[y == False])  # [2,1,0]
print(x >= 3)  # [ True False  True False  True  False]
print(x[~(x >= 3)])  # [2,1,0]
print((x == 2) | (x == 1))  # [False  True False  True False False]
print(x[(x == 2) | (x == 1)])  # [2 1]
x[(x == 2) | (x == 1)] = 0
print(x)  # [3 0 3 0 3 0]

六、广播

6.1简介

  对数组的算术运算通常在两个具有完全相同形状的阵列之间进行,如:

a = np.array([1,2,3,4]) 
b = np.array([10,20,30,40]) 
a*b

在这里插入图片描述
此时两个数组相应的元素之间进行计算。而若两个数组的维数不相同,由于numpy具有广播的性质,使得计算仍可继续进行。例如:

a = np.array([1, 2, 3])
print(a*2)

在这里插入图片描述
严格意义上,数组a大小为(1,3),而2属于标量,二者并不能直接进行计算。而numpy的广播机制对标量2进行了扩容,使得计算可正常进行:
在这里插入图片描述
再比如以下计算仍可正常进行:

a = np.array([[0, 0, 0],
              [10, 10, 10],
              [20, 20, 20],
              [30, 30, 30]])
b = np.array([1, 2, 3])
print(a+b)

在这里插入图片描述

6.2广播规则

  当对两个 array 进行操作时,numpy 会从最大的axis(shape属性最右侧的值)开始向左进行比较,只有:

  • 1.两维度相等。
  • 2.两维度其中一个为1。

此时,两维度才会被认为是兼容的,否则抛出异常显示无法计算。例如一个形状为256 x 256 x 3的三维数组与大小为(3,)的一维数组进行计算:

三维数组形状:256 x 256 x 3
一维数组形状:            3	, 会被拉伸为1 x 1 x 3
结果的形状:  256 x 256 x 3

当比较的任一维度大小是 1 时,使用另一个数组对应维度的大小。同理:

A      (4d array):  8 x 1 x 6 x 1
B      (3d array):      7 x 1 x 5
result (4d array):  8 x 7 x 6 x 5

而以下例子中,倒数第二个维度不满足上述条件,故无法计算:

A      (2d array):      2 x 1
B      (3d array):  8 x 4 x 3 # 倒数第二个维度不兼容

  以图为例:

>>> a = np.array([[ 0.0,  0.0,  0.0],
...               [10.0, 10.0, 10.0],
...               [20.0, 20.0, 20.0],
...               [30.0, 30.0, 30.0]])
>>> b = np.array([1.0, 2.0, 3.0])
>>> a + b
array([[  1.,   2.,   3.],
        [11.,  12.,  13.],
        [21.,  22.,  23.],
        [31.,  32.,  33.]])
>>> b = np.array([1.0, 2.0, 3.0, 4.0])
>>> a + b
Traceback (most recent call last):
ValueError: operands could not be broadcast together with shapes (4,3) (4,)

在这里插入图片描述

七、其他操作

7.1axis作为函数参数时的技巧

  axis常常作为函数参数进行使用,但在实际使用过程当中自行判断操作的元素非常麻烦,此处参考文章:文章链接。此方法包含两步思路:

  • axis=value找到对应[]中的最大单位块
  • 对最大单位块进行操作。
    • 当单位块是数值时直接计算。
    • 当单位块是数组时,将对应下标元素进行计算。

7.1.1思路解析

寻找最大单位快:某层[]里包裹的最大结构块。

  • [1,2,3]:数值1,2,3,axis取值为0.
  • [[1,2],[3,4]:[1,2],[3,4],axis取值为0、1.
  • [[[1,2],[3,4]],[[5,6],[7,8]]]:[[1,2],[3,4]]、[[5,6],[7,8]],axis取值为0、1、2.

对单位块进行操作:最大单位块是数值时直接计算即可,而当其是数组时,如[[[1,2],[3,4]],[[5,6],[7,8]]],axis=0对应三维数组最外层,即其中包含[[1, 2],[3, 4]]、 [[5, 6],[7, 8]]两个最大单位块。而axis=1对应第二层,其中包含两组元素,每组包含两个单位最大块,即[1,2]和[3,4]、[5,6]和[7,8]。同理,axis=2对应的最大块都是数值,直接计算即可。

7.1.2实例1:sum函数

一维数组
  一维数组维度为1,只有axis=0时的情形:

arr = np.array([1, 2, 3])
arr.sum(axis = 0)	# 6
  • axis=0对应最外层[],单位最大块为数值1,2,3。
  • 直接对数值求和计算。

二维数组
  二维数组维度为2,有axis=0axis=1时的情形:
axis=0

arr = np.array([[1, 2], [3, 4]])
arr.sum(axis = 0)	# array([4, 6])
  • axis=0对应最外层[],包含[1,2]和[3,4]两个最大单位块。
  • 单位块是数组,则二者对应下标元素进行计算,即[1,2]中1对应下标0,2对应下标1,同样[3,4]中3对应下标0,4对应下标1,则有[1+3,2+4]=[4,6]。

axis=1

rr = np.array([[1, 2], [3, 4]])
arr.sum(axis = 1)	# array([3, 7])
  • axis=1对应第二层[],在第一个[]中包含1,2(数值形式的最大单位块),第二个[]中包含3,4.
  • 单位块是数值,直接进行计算,即[1+2,3+4]=[3,7]。

三维数组
  二维数组维度为3,有axis=0axis=1axis=2时的情形:
axis=0

arr = np.array([[[1, 2],[3, 4]], [[5, 6],[7, 8]]])
arr.sum(axis=0)	# array([[ 6,  8],[10, 12]])
  • axis=0对应最外层[],包含最大单位块为[[1, 2],[3, 4]]与[[5, 6],[7, 8]]。
  • 由于单位块是数组,则将对应下标元素进行计算,即[[1, 2],[3, 4]] + [[5, 6],[7, 8]] = [[1+5,2+6],[3+7,4+8]] = [[6,8], [10,12]]。

axis=1

arr = np.array([[[1, 2],[3, 4]], [[5, 6],[7, 8]]])
arr.sum(axis=1)	# array([[ 4,  6],[12, 14]])
  • axis=1对应第二层[],注意,去掉第一层[]时获得两个最大单位块[[1, 2],[3, 4]]和[[5, 6],[7, 8]](即两个数组),则去掉第二层[]时同样获得两组(每组两个)最大单位块,第一组中为[1, 2]和[3, 4]],第二组中为[5, 6]和[7, 8]。
  • 由于对应最大单位块是数组,故将两组单位块对应元素进行计算,即[[1+3,2+4],[5+7, 6+8]] = [[4,6],[12,14]]。

axis=2

arr = np.array([[[1, 2],[3, 4]], [[5, 6],[7, 8]]])
arr.sum(axis=2)	# array([[ 3,  7],[11, 15]])
  • axis=2对应第三层[],去掉第二层[]时获得两组最大单位块,第一组中为[1, 2]和[3, 4],第二组中为[5, 6]和[7, 8],即四个数组。故去掉[]获得数值形式的最大单位块,第一组为1和2,第二组为3和4,第三组为5和6,第四组为7和8,注意1,2,3,4同属第一层中的一组,5,6,7,8属另一组(注意,即使不存在[],也不可随意合并分组)。
  • 由于最大单位块是数值,故将同属一个单位块的数据进行运算,即[[1+2,3+4],[5+6,7+8]] = [[3,7],[11,15]]。

axis=-1:表示在当前数组最后一维度操作,三维数组中axis=0/1/2,那么axis=-1即等价于axis=2,所以其结果与axis=2相同。

7.1.3实例2:argmax函数

  argmax函数用于获取数组中元素最大值的下标。
一维数组

arr = np.array([3, 4, 6, 9, 1, 2])
print(np.argmax(arr, axis=0))	# 3

二维数组
axis=0

arr = np.array([[3, 6, 6, 2], [4, 7, 11, 2], [5, 9, 1, 3]])
print(np.argmax(arr, axis=0))	# [2 2 1 2]
  • axis=0对应最外层[],去掉[]后得到三个最大单位块[3, 6, 6, 2],[4, 7, 11, 2],[5, 9, 1, 3]。
  • 单位块是数组,则对应下标元素进行计算,即argmax([3,4,5])、argmax([6,7,9])、argmax([6,11,1])、argmax([2,2,3]),得到4个最大值索引值:2、2、1、2,得到索引值数组:[2 2 1 2]。

axis=1

arr = np.array([[3, 6, 6, 2], [4, 7, 11, 2], [5, 9, 1, 3]])
print(np.argmax(arr, axis=1))	# [1 2 1]       
  • axis=0对应[]去掉后得到[3, 6, 6, 2],[4, 7, 11, 2],[5, 9, 1, 3],将axis=1对应[]去掉后得到三组元素3, 6, 6, 24, 7, 11, 25, 9, 1, 3
  • 由于单位块是数值形式,故直接进行计算,即argmax([3,6,6,2])、argmax([4,7,11,2])、argmax([5,9,1,3]),得到3个最大值索引值:1、2、1,得到索引数组:[1 2 1]。

三维数组
axis=0

arr = np.array([[[1, 5, 5, 2], [9, -6, 2, 8], [-3, 7, -9, 1]], [[-1, 7, -5, 2], [9, 6, 2, 8], [3, 7, 9, 1]], [[21, 6, -5, 2], [9, 36, 2, 8], [2, 7, 66, 1]]])
print(np.argmax(arr, axis=0))
'''
[[2 1 0 0]
 [0 2 0 0]
 [1 0 2 0]]
 '''
  • axis对应最外层[],去掉后得到:[[1, 5, 5, 2], [9, -6, 2, 8], [-3, 7, -9, 1]][[-1, 7, -5, 2], [9, 6, 2, 8], [3, 7, 9, 1]][[21, 6, -5, 2], [9, 36, 2, 8], [2, 7, 66, 1]]三个最大单位块。
  • 由于最大单位块是数组,故将三者对应下标的元素进行计算:

在这里插入图片描述
即:argmax([1,-1,21)、argmax([5,7,6])、argmax([5,-5,-5])、argmax([2,2,2])、argmax([9,9,9])、argmax([-6,6,36])…以此类推,得到索引值数组:
在这里插入图片描述
axis=1

>>> arr
array([[[ 1,  5,  5,  2],
        [ 9, -6,  2,  8],
        [-3,  7, -9,  1]],

       [[-1,  7, -5,  2],
        [ 9,  6,  2,  8],
        [ 3,  7,  9,  1]],

       [[21,  6, -5,  2],
        [ 9, 36,  2,  8],
        [ 2,  7, 66,  1]]])
>>> print(np.argmax(arr, axis=1))
[[1 2 0 1]
 [1 0 2 1]
 [0 1 2 1]]
  • 脱去两层[]后得到三组最大单位块,第一组中为[ 1, 5, 5, 2],[ 9, -6, 2, 8],[-3, 7, -9, 1],第二组中为[-1, 7, -5, 2],[ 9, 6, 2, 8],[ 3, 7, 9, 1],第三组中为[21, 6, -5, 2],[ 9, 36, 2, 8],[ 2, 7, 66, 1]
  • 将三组单位块中数组对应下标元素进行计算,如对于第一组的[ 1, 5, 5, 2],[ 9, -6, 2, 8],[-3, 7, -9, 1]有:

在这里插入图片描述
以此类推计算argmax([1,9,-3)、argmax([5,-6,7])、argmax([5,2,-9])、argmax(2,8,1),得到索引数组:
在这里插入图片描述
axis=2

>>> arr
array([[[ 1,  5,  5,  2],
        [ 9, -6,  2,  8],
        [-3,  7, -9,  1]],

       [[-1,  7, -5,  2],
        [ 9,  6,  2,  8],
        [ 3,  7,  9,  1]],

       [[21,  6, -5,  2],
        [ 9, 36,  2,  8],
        [ 2,  7, 66,  1]]])
>>> print(np.argmax(arr, axis=2))
[[1 0 1]
 [1 0 2]
 [0 1 2]]
  • 第二层[]对应[ 1, 5, 5, 2],[ 9, -6, 2, 8],[-3, 7, -9, 1][-1, 7, -5, 2],[ 9, 6, 2, 8],[ 3, 7, 9, 1][21, 6, -5, 2],[ 9, 36, 2, 8],[ 2, 7, 66, 1]三组单位最大块,将[]去掉后得到三组数值1,5,5,29,-6,2,8-3,7,-9,1-1,7,-5,29,6,2,83,7,9,121,6,-5,29,36,2,82,7,66,1。(注意,即使不存在[],也不可随意合并分组
  • 直接在数值中进行计算argmax([1,5,5,2])、argmax([9,-6,2,8])、argmax([-3,7,-9,1])…

在这里插入图片描述
axis=-1,表示在当前数组最后一维度操作,三维数组中axis=0/1/2,那么axis=-1即等价于axis=2,所以其结果与axis=2相同。

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值