Python的NumPy库(一)基础用法

NumPy库并不是Python的标准库,但其在机器学习、大数据等很多领域有非常广泛的应用,NumPy本身就有比较多的内容,全部的学习可能涉及许多的内容,但我们在这里仅学习常见的使用,这些内容对于我们日常使用NumPy是足够的。

NumPy简介

NumPy是Python中科学计算的基础包,它代表 "Numeric Python"。Numeric,即 NumPy 的前身,是由 Jim Hugunin 开发的。 也开发了另一个包 Numarray ,它拥有一些额外的功能。 2005年,Travis Oliphant 通过将 Numarray 的功能集成到 Numeric 包中来创建 NumPy 包。

NumPy的核心是多维数组(ndarray),以及用于数组快速操作的各种API,有包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。

NumPy数组 和 原生Python Array(数组)之间有几个重要的区别:

  • NumPy 数组在创建时具有固定的大小,与Python的原生数组对象(可以动态增长)不同。更改ndarray的大小将创建一个新数组并删除原来的数组。
  • NumPy 数组中的元素都需要具有相同的数据类型,因此在内存中的大小相同。 例外情况:Python的原生数组里包含了NumPy的对象的时候,这种情况下就允许不同大小元素的数组。
  • NumPy 数组有助于对大量数据进行高级数学和其他类型的操作。通常,这些操作的执行效率更高,比使用Python原生数组的代码更少。
  • 越来越多的基于Python的科学和数学软件包使用NumPy数组; 虽然这些工具通常都支持Python的原生数组作为参数,但它们在处理之前会还是会将输入的数组转换为NumPy的数组,而且也通常输出为NumPy数组。换句话说,为了高效地使用当今科学/数学基于Python的工具(大部分的科学计算工具),你只知道如何使用Python的原生数组类型是不够的 - 还需要知道如何使用 NumPy 数组。

NumPy数组主要是用来解决数学问题,包括功能(矩阵计算)和性能两个方面,并且性能更为关键。

NumPy数组主要是用来解决数学问题的,所以需要学习者具备一定的数学知识,比如矩阵、线性代数等等,本文假定学习者已经掌握了这些数学基础知识。

NumPy多维数组定义

NumPy多维数组有多种定义方法,我们主要学习常见的几种。

对象构造方法

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

返回NumPy数组。

参数说明:

  • object:初始化的数组值,可以是Python数组,也可以是序列类型的对象,如果是一个嵌套的序列对象,就会生成一个多维数组
  • dtype: 数组元素的数据类型。
  • copy :对象是否被复制。
  • order :排序方式,C(按行)、F(按列)或A(任意,默认)。
  • subok: 默认情况下,返回的数组被强制为基类数组。 如果为true,则返回子类。
  • ndmin :指定返回数组的最小维数。

数组对象的属性

NumPy 数组的维数称为秩(rank),秩就是轴(axis)的数量,可以相像为坐标轴,一维数组就是一维坐标轴,二维数组就是二维坐标轴,依次类推。

axis=0,表示第1条轴,一般我们称之为横轴,实际是沿着横轴对每一列进行操作。

axis=1,表示第2条轴,一般我们称之为纵轴,实际是沿着纵轴对每一行进行操作。

属性 说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的形状,就是各维度的元素数的列表,例如举证就是(n,m),维度数相同但形状并不一定相同,例如矩阵都是二位的,但(3,3)的矩阵和(4,3)的矩阵形状是不同的
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。

注意:初学者很容易将维度和形状搞混淆,维度是坐标轴的概念,一维就是一条直线,二维就是十字交叉的坐标轴,三维就是立方体一样的三轴坐标形状是比维度之下的长度的描述,描述的是各维度的长度,如一维的形状就是描述一条线段的长度(5个元素长度就是5,100个元素长度就是100),二维的形状就是描述长方形的两条边的长度,长是横轴,宽是纵轴,用二元元组描述横轴和纵轴,三维的形状就是描述长方体的三条边的长度,长、宽、高的三元组。同样是二维数组,会因为形状不同而不同,如长宽是(3,2)的数组和长宽为(2,3)是完全不同的两个数组。

几个维度在numpy是通过嵌套几层中括号来表示的,形状是通过中括号里的元素个数来表示的(中括号里的每一个中括号也是一个元素)。

python 复制代码
a = np.array([[1,2,3,4], [10,20+5j,30+1j,40+2j]])
print(a)
print(a.ndim) #2
print(a.shape) #(2, 4)
print(a.dtype) #int64
print(a.itemsize) #8
print(a.flags)
# C_CONTIGUOUS: True
# F_CONTIGUOUS: False
# OWNDATA: True
# WRITEABLE: True
# ALIGNED: True
# WRITEBACKIFCOPY: False
print(a.real)
#[[ 1.  2.  3.  4.]
# [10. 20. 30. 40.]]
print(a.imag)
#[[0. 0. 0. 0.]
# [0. 5. 1. 2.]]
print(a.data)
#<memory at 0x108540040>

基于序列类型创建数组

可以基于序列类型生成数组,元素的类型并不限定为数值型,最终元素的类型会被转换为dtype:

python 复制代码
import numpy as np

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

b = np.array(['a','b','c', 'd'])
print(b) #['a' 'b' 'c' 'd']

c = np.array(['abc', 'def'])
print(c) #['abc' 'def']

如果元素的类型不一致会ValueError的异常:

python 复制代码
a = np.array([1,2,3,4, [1,2]])
print(a)
#ValueError: setting an array element with a sequence. 

但注意:python会根据输入的数据类型的兼容性,进行自我适应,调整最终的dtype对象:

python 复制代码
import numpy as np

a = np.array([1,2,3,4,2])
print(a) #[1 2 3 4 2]
print(a.dtype) #int64
a = np.array([1,2,3,4,2.0])
print(a) #[1. 2. 3. 4. 2.]
print(a.dtype) #float64
a = np.array([1,2,3,4,'ab'])
print(a.dtype) #<U21
print(a) #['1' '2' '3' '4' 'ab']

元素也可以支持字典:

python 复制代码
s = np.array([{1:'1'}, {2:'2', 3:'3'}])
print(s) #[{1: '1'} {2: '2', 3: '3'}]
print(s.dtype) #object

元素也支持自定义对象

python 复制代码
class MyClass:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        return f'(MyClass {self.a=}, {self.b=})'

    def foo(self):
        pass

c = np.array([MyClass(1, 2), MyClass('s', 'c')])
print(c) #[(MyClass self.a=1, self.b=2) (MyClass self.a='s', self.b='c')]
print(c.dtype) #object

字典和自定义类都被识别为object类型,所以它们也可以被放在一起:

python 复制代码
c = np.array([MyClass(1, 2), MyClass('s', 'c'), MyClass2(), {2:'2', 3:'3'}])
print(c) #[(MyClass self.a=1, self.b=2) (MyClass self.a='s', self.b='c') <__main__.MyClass2 object at 0x1094ae050> {2: '2', 3: '3'}]
print(c.dtype) #object

如果要生成多维数组,需要列表对象是嵌套对象:

python 复制代码
import numpy as np

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

如果直接使用元组作为元素,NumPy会把它识别为多维数组:

python 复制代码
a = np.array([(1,2,3,4), (10,20,30,40)])
print(a)
'''
[[ 1  2  3  4]
 [10 20 30 40]]
'''

也可以通过指定ndmin来指定最小维数

python 复制代码
b = np.array(('a', 'b', 'c'), ndmin=2)
print(b)
#[['a' 'b' 'c']]

通过dtype指定数组元素的类型:

python 复制代码
c = np.array((20,30,40,50), ndmin=2, dtype=complex)
print(c)
#[[20.+0.j 30.+0.j 40.+0.j 50.+0.j]]

dtype支持的数值类型

numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 Python 内置的类型。下表列举了常用 NumPy 基本类型:

类型 代码 说明
bool_ b 布尔型数据类型(True 或者 False)
int_ 默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8、uint8 i1、u1 有符号位和无符号位的8bit整数,相当于一个字节
int16、uint16 i2、u2 有符号位和无符号位的16bit整数,2字节整数
int32、uint32 i4、u4 有符号位和无符号位的32bit整数,4字节整数
int64、uint64 i8、u8 有符号位和无符号位的64bit整数,8字节整数
float_ float64 类型的简写
float16 f2 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32 f4 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 f8 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_ complex128 类型的简写,即 128 位复数
complex64 c8 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 c16 复数,表示双 64 位浮点数(实数部分和虚数部分)
bytes S C格式的字符串
Unicode U Unicode格式的字符串

数据类型对象(numpy.dtype 类的实例)用来描述与数组对应的内存区域是如何使用,它描述了数据的以下几个方面::

  • 数据的类型(整数,浮点数或者 Python 对象)
  • 数据的大小(例如, 整数使用多少个字节存储)
  • 数据的字节顺序(小端法或大端法),通过对数据类型预先设定 < 或 > 来决定的。 < 意味着小端法(最小值存储在最小的地址,即低位组放在最前面)。> 意味着大端法(最重要的字节存储在最小的地址,即高位组放在最前面)。
  • 在结构化类型的情况下,字段的名称、每个字段的数据类型和每个字段所取的内存块的部分
  • 如果数据类型是子数组,那么它的形状和数据类型是什么。
复制代码
numpy.dtype(object, align, copy)

返回NumPy的数据类型

参数说明:

  • object - 要转换为的数据类型对象
  • align - 如果为 true,填充字段使其类似 C 的结构体。
  • copy - 复制 dtype 对象 ,如果为 false,则是对内置数据类型对象的引用
python 复制代码
dt = np.dtype(np.int32)
print(dt)
#int32

dt = np.dtype('i4')
print(dt)
#int32

dt = np.dtype('<i4')
print(dt)
#int32

将数据类型应用于 ndarray 对象:

python 复制代码
dt = np.dtype([('age',np.int8)])
a = np.array([(10,),(20,),(30,)], dtype = dt)
print(a)
#[(10,) (20,) (30,)]

下面的示例定义一个结构化数据类型 student,包含字符串字段 name,整数字段 age,及浮点字段 marks,并将这个 dtype 应用到 ndarray 对象。

python 复制代码
STUDENT = np.dtype([('name','S20'), ('age', 'i1'), ('marks', 'f4')])
print(STUDENT)
#[('name', 'S20'), ('age', 'i1'), ('marks', '<f4')]
a = np.array([('John', 12, 91.5),('Rose', 13, 99)], dtype = STUDENT)
print(a)
#[(b'John', 12, 91.5) (b'Rose', 13, 99. )]
print(a.dtype)
#[('name', 'S20'), ('age', 'i1'), ('marks', '<f4')]

从上面的例子可以看出,dtype定义的结构并没有被识别为object,而是一种带描述的结构体。

软拷贝数组

复制代码
numpy.asarray(a, dtype = None, order = None)

numpy.asarray 类似 numpy.array,基于存在的对象a(必须是数组,或序列等)创建一个新的数组对象。

array()和asarray()方法都能将序列对象转换为NumPy数组,二者:

  • 当他们的参数是列表型数据(list)时,二者没有区别;
  • 当他们的参数是数组类型(array)时,np.array()会返回参数数组的一个副本(copy,两者值一样但指向不同的内存),np.asarray()会返回参数数组的一个视图(两者指向同一块内存).
  • np.array()的副本会新开辟一块内存,对于大数组来说,会存在大量的复制操作,速度更慢且需要耗费大量内存;
  • np.asarray()的视图相当于新增加了一个指向当前内存的引用,不存在复制操作,速度更快且节约内存。注意通过其中的一个引用修改数据,其他引用的数据也会跟着变,因为他们指向同一块内存区域。
python 复制代码
a1 = np.asarray([[1, 2, 3], [4, 5, 6]])
print(f'{a1=}')
b1 = np.asarray(a1)
print(f'{b1=}')
b2 = np.array(a1)
print(f'{b2=}')
a1[1][1] = 10
print('-------')
print(f'{a1=}')
print(f'{b1=}')
print(f'{b2=}')

'''
a1=array([[1, 2, 3],
       [4, 5, 6]])
b1=array([[1, 2, 3],
       [4, 5, 6]])
b2=array([[1, 2, 3],
       [4, 5, 6]])
-------
a1=array([[ 1,  2,  3],
       [ 4, 10,  6]])
b1=array([[ 1,  2,  3],
       [ 4, 10,  6]])
b2=array([[1, 2, 3],
       [4, 5, 6]])
'''

创建空数组

复制代码
numpy.empty(shape, dtype = float, order = 'C')

创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组。

参数说明:

  • shape:数组的形状元组,例如矩阵表示为(n,m),就是n 行 m 列;
  • dtype:元素的类型,默认是浮点数;
  • order:数组在内存中的存储顺序,'C' 是C 的行数组,或者 'F'是 FORTRAN 的列数组。
python 复制代码
x = np.empty((3,2), dtype=int)
print(x)
'''
[[   0 2043]
 [   1    0]
 [   0    0]]
'''

注意 − 数组元素为随机值,因为它们未初始化。

创建0填充数组

复制代码
numpy.zeros(shape, dtype = float, order = 'C')

创建指定维度的数组,数组元素以 0 来填充

参数说明:

  • shape:数组的形状;
  • dtype:元素的类型,默认是浮点数;
  • order:数组在内存中的存储顺序,'C' 是C 的行数组,或者 'F'是 FORTRAN 的列数组。
python 复制代码
x = np.zeros((3,2), dtype=int)
print(x)
y = np.zeros((2,3), dtype=[('NAME', 'S20'), ('AGE', 'i2')])
print(y)

'''
[[0 0]
 [0 0]
 [0 0]]
[[(b'', 0) (b'', 0) (b'', 0)]
 [(b'', 0) (b'', 0) (b'', 0)]]
'''

创建1填充数组

复制代码
numpy.ones(shape, dtype = None, order = 'C')

创建指定维度的形状,数组元素以 1 来填充,与0填充一样,只是换成用1来填充。

创建n填充数组

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

创建指定维度的形状,数组元素以 fill_value来填充,与0填充一样,只是换成用1来填充。

python 复制代码
x = np.full((3,2), 'OK')
print(x)
'''
[['OK' 'OK']
 ['OK' 'OK']
 ['OK' 'OK']]
'''

仿制0填充数组

复制代码
numpy.zeros_like(a, dtype=None, order='K', subok=True, shape=None)

用于创建一个与给定数组具有相同形状的数组,数组元素以 0 来填充。

参数说明:

  • a:要仿制的数组
  • dtype:元素的类型,默认是浮点数;
  • order:数组在内存中的存储顺序,可选值为 'C'(按行优先)或 'F'(按列优先),默认为 'K'(保留输入数组的存储顺序);
  • subok:是否允许返回子类,如果为 True,则返回一个子类对象,否则返回一个与 a 数组具有相同数据类型和存储顺序的数组;
  • shape:创建的数组的形状,如果不指定,则默认为 a 数组的形状。
python 复制代码
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
za = np.zeros_like(a)
print(za)
'''
[[0 0 0]
 [0 0 0]
 [0 0 0]]
'''

仿制1填充数组

复制代码
numpy.ones_like(a, dtype=None, order='K', subok=True, shape=None)

创建一个与给定数组具有相同形状的数组,与仿制0填充数据一样,只是数组元素以 1 来填充。

仿制n填充数组

numpy.full_like(a, fill_value,dtype=None, order='K', subok=True, shape=None)

创建一个与给定数组具有相同形状的数组,与仿制0填充数据一样,只是数组元素以 fill_value 来填充。

从流创建数组

复制代码
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)

接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。

注意:buffer 是字符串的时候,Python3 默认 str 是 Unicode 类型,所以要转成 bytestring 在原 str 前加上 b。

参数说明:

  • buffer:任意流对象
  • dtype:数组的元素类型
  • count:读取的数据数量,默认为-1,读取所有数据。
  • offset:流的偏移量,默认为0
python 复制代码
bs = b'This is a test case!'
a = np.frombuffer(bs, dtype='S2')
print(a)
#[b'Th' b'is' b' i' b's ' b'a ' b'te' b'st' b' c' b'as' b'e!']

从迭代器创建数组

复制代码
numpy.fromiter(iterable, dtype, count=-1)

可迭代对象中建立 ndarray 对象,返回一维数组。

参数说明:

  • iterable:待提供数据的迭代器
  • dtype:数组的元素类型
  • count:读取的数据数量,默认为-1,读取所有数据。
python 复制代码
it = iter(range(5))
x = np.fromiter(it, dtype=int)
print(x) #[0 1 2 3 4]

创建范围数组

类似于Python的range:

复制代码
numpy.arange(start, stop, step, dtype)

参数说明:

  • start:起始值,创建的数组包含这个数(闭区间)
  • stop:终止值,创建的数组将不包含这个数(开区间)
  • step:步长,默认是1
  • dtype:数组的元素类型,如果没有提供,则会使用输入数据的类型。
python 复制代码
import numpy as np
 
x = np.arange(5)  
print (x) #[0  1  2  3  4]

构建等差数列数组

复制代码
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

创建一个一维数组,数组的元素是一个等差数列。

参数说明:

  • start:起始值,创建的数组包含这个数(闭区间)
  • end:终止值,如果endpointtrue,该值包含于数列中
  • num:要生成的等步长的样本数量,默认为50
  • endpoint:该值为 true 时,数列中包含stop值,反之不包含,默认是True。
  • retstep:如果为 True 时,生成的数组中会显示间距,反之不显示。
  • dtype:数组的元素类型

numpy.linspace是numpy.arange的增强版本。

python 复制代码
a = np.linspace(10, 15, num=6, dtype=float)
print(a) #[10. 11. 12. 13. 14. 15.]
a = np.linspace(10, 20, num=6, dtype=float)
print(a) #[10. 12. 14. 16. 18. 20.]
a = np.linspace(10, 20, num=6, endpoint=False, dtype=float)
print(a) #[10.         11.66666667 13.33333333 15.         16.66666667 18.33333333]
#10, 10+1+2/3, 10+(1+2/3)*2, 10+(1+2/3)*3, 10+(1+2/3)*4, 10+(1+2/3)*5, 10+(1+2/3)*6=20 
a = np.linspace(10, 19, num=6, endpoint=False, dtype=float)
print(a) #[10.  11.5 13.  14.5 16.  17.5]

如果endpoin=Fasle,实际是把num计算为num+1,然后取前面的num位。

构建等比数列数组

复制代码
numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)

创建一个于等比数列数组。

参数说明:

  • start:起始值,创建的数组包含这个数(闭区间)
  • end:终止值,如果endpointtrue,该值包含于数列中
  • num:要生成的等步长的样本数量,默认为50
  • endpoint:该值为 true 时,数列中包含stop值,反之不包含,默认是True。
  • base:对数 log 的底数。
  • dtype:数组的元素类型
python 复制代码
a = np.logspace(1, 3, num=3)
print(a)
#[  10.  100. 1000.]

注意:默认是以10为底数的,可以理解为start是,end为

创建对称矩阵

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

创建一个对称矩阵,矩阵的对角线上的值为1,其他值为0。

python 复制代码
x = np.eye(5)
print(x)
'''
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]
'''

参数说明:

  • N为矩阵的列数
  • M为矩阵的行数,默认等于N
  • k表示对角线1的偏移量
python 复制代码
x = np.eye(3, k=1)
print(x)
'''
[[0. 1. 0.]
 [0. 0. 1.]
 [0. 0. 0.]]
'''

x = np.eye(3, k=-1)
print(x)
'''
[[0. 0. 0.]
 [1. 0. 0.]
 [0. 1. 0.]]
'''

索引和切片

下标

NumPy数组可以直接通过下标进行访问,下标从0开始,每个下标代表一行数据,下标的下标代表一个元素,也可以直接用逗号分割各维度:

python 复制代码
a = np.array([[1,2,3], [10,20,30]])
print(a[1]) #[10 20 30]
print(a[1][1]) #20
print(a[1,1]) #20

切片

NumPy数组也支持切片,通过冒号分隔切片参数 start:stop:step 来进行切片操作。

注意:对切片赋值是直接对数组赋值,会改变数据的值。

一维数组切片

对于一维数组,用法与Python列表一样:

python 复制代码
a = np.arange(10)
b = a[2:7:2]   # 从索引 2 开始到索引 7 停止,间隔为 2
print(b) #[2 4 6]
print(a[2]) #2
print(a[2:]) #[2 3 4 5 6 7 8 9]
print(a[:2]) #[0 1]
print(a[2:7]) #[2 3 4 5 6]
print(a[::1]) #[0 1 2 3 4 5 6 7 8 9]
print(a[-2:]) #[8 9]

也支持负整数下标,最后一个数的负整数下标为-1,但因为矩阵比较复杂,而负整数为更进一步的增加表达的复杂度,除非是一维数组,一般不建议使用负整数下标.

冒号 : 的解释:如果只放置一个参数,如 [2] ,将返回与该索引相对应的单个元素。如果为 [2:] ,表示从该索引开始以后的所有项都将被提取,如果未[:2],则提取到第2个值(不含2,开区间)。如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项。

如果前面的start和end都不指定,只指定step也是可以的,将根据步长取全部的数据。

多维数组切片

多维数组的切片,对于每一个维度,都是遵循一维的切片规则,不同的维度之间通过逗号分割。

python 复制代码
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])
print(a)
'''
[[    1     2     3     4]
 [   10    20    30    40]
 [   10   100  1000 10000]]
'''

print(a[1:])
'''
[[   10    20    30    40]
 [   10   100  1000 10000]]
'''

print(a[:,1:])
'''
[[    2     3     4]
 [   20    30    40]
 [  100  1000 10000]]
'''

如果只想得到某一列,可以通过切片得到,如只想得到第3列:

python 复制代码
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])
print(a[:,2:3])
'''
[[   3]
 [  30]
 [1000]]
'''

如果直接使用第2列的下标,但得到的不是列数据,而是转置为行的数据:

python 复制代码
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])

print(a[:,2])
'''
[   3   30 1000]
'''

如果维度很高,也可以通过...代替前面或后面的维数:

python 复制代码
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])
print(a[...,1]) #第2列元素
# [  2  20 100]
print(a[1,...]) #第2行元素
#[10 20 30 40]
print (a[...,1:])  # 第2列及剩下的所有元素
'''
[[    2     3     4]
 [   20    30    40]
 [  100  1000 10000]]
'''

切片赋值

也可以直接对切片进行赋值,切片是原数组的试图,对切片的赋值,会修改原数组的值。

python 复制代码
a = np.array([[11,12,13], [21,22,23],[31,32,33]])
print(a)
'''
[[11 12 13]
 [21 22 23]
 [31 32 33]]
'''

print(a[0:2,1]) #[12 22]
a[0,1] = 100
a[0:2,1] = (101,102) #将会修改数组a的元素
print(a[0:2,1]) #[101 102]
print(a)
'''
[[ 11 101  13]
 [ 21 102  23]
 [ 31  32  33]]
'''

b = a[0:2,2]
b[0] = 201 #也同样会修改a的元素
print(a)
'''
[[ 11 101 201]
 [ 21 102  23]
 [ 31  32  33]]
'''

b = (301,302) #这个不能修改a的元素,直接把b的引用指向了一个新的元组
print(a)
'''
[[ 11 101 201]
 [ 21 102  23]
 [ 31  32  33]]
'''

b = a[0:2,2]
b[:] = (301,302) #如果要修改b的全部元素,要这么样写才行,同样会修改a的元素
print(a)
'''
[[ 11 101 301]
 [ 21 102 302]
 [ 31  32  33]]
'''

整数数组索引

对于多维数组,也可以通过一个整数数组来访问。

以下实例获取数组中 (0,0),(1,1)(2,0) 位置处的元素:

python 复制代码
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])
print(a)
'''
[[    1     2     3     4]
 [   10    20    30    40]
 [   10   100  1000 10000]]
'''

print(a[[0,1,2], [0,1,0]])
'''
[ 1 20 10]
'''

布尔索引(条件过滤)

可以通过布尔索引做条件过滤。直接在中括号中写过滤条件:

python 复制代码
x = np.array([[11, 12, 13],[21, 22, 23],[31, 32, 33],[41, 42, 43]])
print(x[x>21]) #[22 23 31 32 33 41 42 43]
print(x[x%2==0]) #[12 22 32 42]
python 复制代码
a = np.array([np.nan,  1,2,np.nan,3,4,5])  
print (a[~np.isnan(a)])

#[ 1.   2.   3.   4.   5.]

花式索引

花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。

对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素,如果目标是二维数组,那么就是对应下标的行。

花式索引跟切片不一样,它总是将数据复制到新数组中。

python 复制代码
x = np.array([[11,12,13,14,15],[21,22,23,24,25],[31,32,33,34,35],[41,42,43,44,45], [51,52,53,54,55], [61,62,63,64,65]])
print(x)
print(x[1]) #第2行
print(x[1,2]) #23
print(x[[1,2]]) #第2、3行
print(x[[1,2,3,4],[1,3,2,4]]) #表示获取x(1,1)、(2,3)、(3,2)、(4,4)四个元素,x[]里的第一个中括号是第0维,第2个中括号是第1维。

'''
[[11 12 13 14 15]
 [21 22 23 24 25]
 [31 32 33 34 35]
 [41 42 43 44 45]
 [51 52 53 54 55]
 [61 62 63 64 65]]
[21 22 23 24 25]
23
[[21 22 23 24 25]
 [31 32 33 34 35]]
[22 34 43 55]
'''

从上面的例子可以看出,可以使用x[n]来获得第n+1行的数据,可以通过一个列表作为下标x[[n,m,..]]来获得多行的数据,这就是花式索引。

并且可以用行号重新组织数组,如下:

python 复制代码
x = np.array([[11,12,13,14,15],[21,22,23,24,25],[31,32,33,34,35],[41,42,43,44,45], [51,52,53,54,55], [61,62,63,64,65]])
print(x)
print(x[[-1,-2,-3,-4]])

'''
[[11 12 13 14 15]
 [21 22 23 24 25]
 [31 32 33 34 35]
 [41 42 43 44 45]
 [51 52 53 54 55]
 [61 62 63 64 65]]
[[61 62 63 64 65]
 [51 52 53 54 55]
 [41 42 43 44 45]
 [31 32 33 34 35]]
'''

广播(数组运算)

广播(Broadcast)是 numpy 对不同维度(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。

如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求形状相同(维数相同,且各维度的长度也要相同)。

python 复制代码
a = np.array([[1,2,3,4], [7,8,9,10]])
b = np.array([[10,20,30,40], [70,80,90,100]])
c1 = a * b
print(c1)
'''
[[  10   40   90  160]
 [ 490  640  810 1000]]
'''

c2 = a + b
print(c2) 
'''
[[ 11  22  33  44]
 [ 77  88  99 110]]
'''

c3 = b - a
print(c3) 
'''
[[ 9 18 27 36]
 [63 72 81 90]]
'''

c4 = b / a
print(c4)
'''
[[10. 10. 10. 10.]
 [10. 10. 10. 10.]]
'''

广播不是矩阵运算,是数组各元素按位置与对应另外一个数组的数学运算,将得到与数组一样的维度的数组。

当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制:

如果两个数组a,b的维数相同,但b的某一个维度或几个维度的长度为1,则会自动将该维度的数据复制进行伸展到与a的形状一致,再进行按元素位置对应的运算。极端情况,b只有一个元素,它可以横向、纵向的任意扩展(复制自己)

例子一:b是一个单一的数,单一的数可以向任何维度复制自己

python 复制代码
a = np.array([[11,12,13,14], [21,22,23,24], [31,32,33,34]])
b = 1
c = a + b
print(c)
'''
[[12 13 14 15]
 [22 23 24 25]
 [32 33 34 35]]
'''

例子二:b是一维数据

python 复制代码
a = np.array([[11,12,13,14], [21,22,23,24], [31,32,33,34]])
b = np.array([2,2,2,2])
c = a + b
print(c)
'''
[[13 14 15 16]
 [23 24 25 26]
 [33 34 35 36]]
'''

b = np.array([[3],[3],[3]])
c = a + b
print(c)
'''
[[14 15 16 17]
 [24 25 26 27]
 [34 35 36 37]]
'''

无论是纵向还是横向,都会整行(或整列)复制自己。

但是,要求这一维数据的长度必须与a至少一个维度的长度相同,否则会出现

ValueError: operands could not be broadcast together with shapes

的错误。

python 复制代码
a = np.array([[11,12,13,14], [21,22,23,24], [31,32,33,34]])
b = np.array([2,2,2])
c = a + b #ValueError: operands could not be broadcast together with shapes (3,4) (3,) 
print(c)

例子三:三维度的例子

立方体与点的和:a上所有的值都会加上b,形成一个与a形状相同的立方体

python 复制代码
a = np.array([[[11,12,13,14],
               [21,22,23,24],
               [31,32,33,34]],
              [[111,112,113,114],
               [121,122,123,124],
               [131,132,133,134]],
              [[211,212,213,214],
               [221,222,223,224],
               [231,232,233,234]]])
b = np.array(2)
c = a + b
print(c)

'''
[[[ 13  14  15  16]
  [ 23  24  25  26]
  [ 33  34  35  36]]

 [[113 114 115 116]
  [123 124 125 126]
  [133 134 135 136]]

 [[213 214 215 216]
  [223 224 225 226]
  [233 234 235 236]]]

'''

立方体与线段的和:线段会向横和纵两个方向扩展,a的每一组元素对应b的元素的位置进行加和,得到和a一样的形状的数组。

python 复制代码
a = np.array([[[11,12,13,14],
               [21,22,23,24],
               [31,32,33,34]],
              [[111,112,113,114],
               [121,122,123,124],
               [131,132,133,134]],
              [[211,212,213,214],
               [221,222,223,224],
               [231,232,233,234]]])
# b = np.array(2)
# c = a + b
# print(c)

b = np.array([100,101,102,103])
c = a + b
print(c)

'''
[[[111 113 115 117]
  [121 123 125 127]
  [131 133 135 137]]

 [[211 213 215 217]
  [221 223 225 227]
  [231 233 235 237]]

 [[311 313 315 317]
  [321 323 325 327]
  [331 333 335 337]]]
'''

立方体和面的和:按面去加和。

python 复制代码
a = np.array([[[11,12,13,14],
               [21,22,23,24],
               [31,32,33,34]],
              [[111,112,113,114],
               [121,122,123,124],
               [131,132,133,134]],
              [[211,212,213,214],
               [221,222,223,224],
               [231,232,233,234]]])

b = np.array([[100,100,100,100],[200,200,200,200],[300,300,300,300]])
c = a + b
print(c)

'''
[[[111 112 113 114]
  [221 222 223 224]
  [331 332 333 334]]

 [[211 212 213 214]
  [321 322 323 324]
  [431 432 433 434]]

 [[311 312 313 314]
  [421 422 423 424]
  [531 532 533 534]]]
'''

数组的常用方法

NumPy提供了大量操作数组的方法,这里列举几种常用的方法,有些有复杂机制的方法后面还会详细说明。

修改数组形状

方法 描述
reshape 不改变数据的条件下修改形状
flat 数组元素迭代器
flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组
ravel 返回展开数组
resize 返回指定形状的新数组

重新造形

复制代码
numpy.reshape(newshape, order='C')

该方法在不改变数据的条件下修改形状。

参数说明:

  • newshape:新的形状,可以是一个整数或者整数序列,也可以是展开的多个整数
  • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序。
python 复制代码
import numpy as np

a = np.arange(8)
print('原始数组:')
print(a)
print('\n')

b = a.reshape(4, 2)
print('修改后的数组:')
print(b)

'''
原始数组:
[0 1 2 3 4 5 6 7]


修改后的数组:
[[0 1]
 [2 3]
 [4 5]
 [6 7]]
'''

修改数组大小

复制代码
numpy.resize(arr, shape)

返回指定大小的新数组,如果新数组大小大于原始大小,则包含原始数组中的元素的副本。

参数说明:

  • arr:要修改大小的数组
  • shape:返回数组的新形状
python 复制代码
import numpy as np
 
a = np.array([[1,2,3],[4,5,6]])
 
print ('第一个数组:')
print (a)
print ('\n')
 
print ('第一个数组的形状:')
print (a.shape)
print ('\n')
b = np.resize(a, (3,2))
 
print ('第二个数组:')
print (b)
print ('\n')
 
print ('第二个数组的形状:')
print (b.shape)
print ('\n')
# 要注意 a 的第一行在 b 中重复出现,因为尺寸变大了
 
print ('修改第二个数组的大小:')
b = np.resize(a,(3,3))
print (b)

'''
第一个数组:
[[1 2 3]
 [4 5 6]]


第一个数组的形状:
(2, 3)


第二个数组:
[[1 2]
 [3 4]
 [5 6]]


第二个数组的形状:
(3, 2)


修改第二个数组的大小:
[[1 2 3]
 [4 5 6]
 [1 2 3]]
'''

访问全部元素迭代器

numpy.ndarray.flat

一个数组元素迭代器,可以访问全部的数组元素。

python 复制代码
import numpy as np
 
a = np.arange(9).reshape(3,3) 
print ('原始数组:')
for row in a:
    print (row)
 
#对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器:
print ('迭代后的数组:')
for element in a.flat:
    print (element)

'''
原始数组:
[0 1 2]
[3 4 5]
[6 7 8]
迭代后的数组:
0
1
2
3
4
5
6
7
8
'''

展开数组(复制)

复制代码
ndarray.flatten(order='C')

返回一份数组拷贝并且将多维数组展开,对拷贝所做的修改不会影响原始数组。

参数说明:

  • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。
python 复制代码
import numpy as np
 
a = np.arange(8).reshape(2,4)
 
print ('原数组:')
print (a)
print ('\n')
# 默认按行
 
print ('展开的数组:')
print (a.flatten())
print ('\n')
 
print ('以 F 风格顺序展开的数组:')
print (a.flatten(order = 'F'))

'''
原数组:
[[0 1 2 3]
 [4 5 6 7]]


展开的数组:
[0 1 2 3 4 5 6 7]


以 F 风格顺序展开的数组:
[0 4 1 5 2 6 3 7]
'''

展开数组(视图)

复制代码
numpy.ravel(order='C')

返回原数组的展开数组,返回的是数组视图,修改会影响原始数组。

参数说明:

  • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。
python 复制代码
import numpy as np

a = np.arange(8).reshape(2, 4)
print('原数组a:\n', a)
b = a.flatten()
print('flatten展开的数组b:\n', b)
c = a.ravel()
print ('ravel展开的数组c:\n', c)

b[1] = 10
print('修改b[1]后数组b:\n', b)
print('修改b[1]后数组a:\n', a) #a并没有变化
c[1] = 10
print('修改c[1]后数组b:\n', c)
print('修改c[1]后数组a:\n', a) #a的元素值改变了

'''
原数组a:
 [[0 1 2 3]
 [4 5 6 7]]
flatten展开的数组b:
 [0 1 2 3 4 5 6 7]
ravel展开的数组c:
 [0 1 2 3 4 5 6 7]
修改b[1]后数组b:
 [ 0 10  2  3  4  5  6  7]
修改b[1]后数组a:
 [[0 1 2 3]
 [4 5 6 7]]
修改c[1]后数组b:
 [ 0 10  2  3  4  5  6  7]
修改c[1]后数组a:
 [[ 0 10  2  3]
 [ 4  5  6  7]]
'''

数组变换

函数 描述
transpose 转置:对换数组的维度
ndarray.T self.transpose() 相同
rollaxis 向后滚动指定的轴
swapaxes 对换数组的两个轴

转置T

复制代码
numpy.transpose(axes)

返回转置的数组。

参数说明:

  • axes:整数列表,对应维度,通常所有维度都会对换。
python 复制代码
a = np.arange(12).reshape(4, 3)
print('原数组a:\n', a)
'''
原数组a:
 [[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

print('a转置后:\n', a.transpose())
'''
a转置后:
 [[ 0  3  6  9]
 [ 1  4  7 10]
 [ 2  5  8 11]]
'''

可以指定转置的轴,0相当于x轴,1相当于y轴,...,以此类推。上面的例子是二维的,如果指定为tanspose(0,1)相当于没有转置,返回的就是与原来一样的数组,如果是tanspose(1,0)返回的就是转置数组。

python 复制代码
a = np.arange(12).reshape(4, 3)
print('原数组a:\n', a)
'''
原数组a:
 [[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

print('transpose(0,1):\n', a.transpose(0,1))
'''
transpose(0,1):
 [[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
'''

print('transpose(1,0):\n', a.transpose(1,0))
'''
transpose(1,0):
 [[ 0  3  6  9]
 [ 1  4  7 10]
 [ 2  5  8 11]]
'''

对于高维数组,可以任意的排列各轴:

python 复制代码
a = np.arange(36).reshape(4, 3, 3)
print('原数组a:\n', a)
print('transpose(0,2,1):\n', a.transpose(0,2,1))

也可以直接用numpy.T来表示转置:

python 复制代码
a = np.arange(12).reshape(4, 3)
print('原数组a:\n', a)
# print('transpose(0,1):\n', a.transpose(0,1))
print('transpose(1,0):\n', a.transpose(1,0))
print(a.T) #与a.transpose(1,0)相同

滚动轴

复制代码
numpy.rollaxis(a, axis, start)

向后滚动特定的轴到一个特定位置

参数说明:

  • a:待滚动的数组
  • axis:要向后滚动的轴,其它轴的相对位置不会改变
  • start:默认为零,表示完整的滚动。会滚动到特定位置。

先看二维的情况:

python 复制代码
a = np.arange(6).reshape(3, 2)
print(a)
print('滚动轴:\n', np.rollaxis(a, 1))

'''
[[0 1]
 [2 3]
 [4 5]]
滚动轴:
 [[0 2 4]
 [1 3 5]]
'''

从效果来看就是转置。

再看三维的情况:

python 复制代码
a = np.arange(24).reshape(2, 3, 4)
print('原数组a:\n', a)
print('滚动轴:\n', np.rollaxis(a, 1))

'''
原数组a:
 [[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
滚动轴:
 [[[ 0  1  2  3]
  [12 13 14 15]]

 [[ 4  5  6  7]
  [16 17 18 19]]

 [[ 8  9 10 11]
  [20 21 22 23]]]
'''

数组(2,3,4)变化为(3,2,4),可以看出0轴和1轴进行了变换。

交换轴

复制代码
numpy.swapaxes(arr, axis1, axis2)

交换数组的两个轴

参数说明:

  • arr:输入的数组
  • axis1:对应第一个轴的整数
  • axis2:对应第二个轴的整数
python 复制代码
a = np.arange(24).reshape(2, 3, 4)
print('原数组a:\n', a)
print('滚动轴:\n', np.rollaxis(a, 1))
print('交换轴:\n', np.swapaxes(a, 1, 0))

'''
原数组a:
 [[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
滚动轴:
 [[[ 0  1  2  3]
  [12 13 14 15]]

 [[ 4  5  6  7]
  [16 17 18 19]]

 [[ 8  9 10 11]
  [20 21 22 23]]]
交换轴:
 [[[ 0  1  2  3]
  [12 13 14 15]]

 [[ 4  5  6  7]
  [16 17 18 19]]

 [[ 8  9 10 11]
  [20 21 22 23]]]
'''

从上例子可以看到,滚动轴和交换1,0轴是一样的,这两个方法在某些场景有相同的效果。

修改数组维度

函数 描述
broadcast 产生模仿广播的对象
broadcast_to 将数组广播到新形状
expand_dims 扩展数组的形状
squeeze 从数组的形状中删除一维条目

产生模仿广播的对象

numpy.broadcast(x,y)

扩展y,让它能按照广播的原则按x的形状进行扩展。

numpy.broadcast_to(array, shape, subok=False)

将数组广播到新形状

  • array:要广播的数组
  • shape:新形状
  • subok:如果为True,则为子类,否则默认情况下,返回的数组将被强制为base-class数组

函数将数组广播到新形状。 它在原始数组上返回只 读视图。 它通常不连续。 如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError。

python 复制代码
x = np.arange(12).reshape(3, 4)
y = np.array([2,2,2,2])
y1 = np.broadcast_to(y, x.shape)
print(y1)

'''
[[2 2 2 2]
 [2 2 2 2]
 [2 2 2 2]]
'''

扩展数组的维度

复制代码
numpy.expand_dims(arr, axis)

通过在指定位置插入新的轴来扩展数组形状

参数说明:

  • arr:输入数组
  • axis:新轴插入的位置
python 复制代码
x = np.array([[11,12],[21,22]])
print('原始数组:\n', x)
y = np.expand_dims(x, axis = 0)
print('插入维度后的数组:\n', y)
y = np.expand_dims(x, axis = 1)
print('插入维度后的数组:\n', y)

'''
原始数组:
 [[11 12]
 [21 22]]
插入维度后的数组:
 [[[11 12]
  [21 22]]]
插入维度后的数组:
 [[[11 12]]

 [[21 22]]]

'''

删除单维度

复制代码
numpy.squeeze(arr, axis)

从数组的形状中删除单维度条目,即把shape中为1的维度去掉

参数说明:

  • arr:输入数组
  • axis:整数或整数元组,指定需要删除的维度,但是指定的维度必须为单维度,否则将会报错;axis的取值可为None 或 int 或 tuple of ints, 可选。若axis为空,则删除所有单维度的条目;
python 复制代码
x = np.arange(12).reshape(1, 3, 4)
print('原始数组:\n', x)
y = np.squeeze(x)
print('删除1轴后:\n', y)

'''
原始数组:
 [[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]]
删除1轴后:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''

连接数组

函数 描述
concatenate 连接沿现有轴的数组序列
stack 沿着新的轴加入一系列数组。
hstack 水平堆叠序列中的数组(列方向)
vstack 竖直堆叠序列中的数组(行方向)

沿轴连接

复制代码
numpy.concatenate((a1, a2, ...), axis)

函数用于沿指定轴连接相同形状的两个或多个数组

参数说明:

  • a1, a2, ...:相同形状的数组
  • axis:沿着它连接数组的轴,默认为 0
python 复制代码
import numpy as np
 
a = np.array([[1,2],[3,4]])
 
print ('第一个数组:')
print (a)
print ('\n')
b = np.array([[5,6],[7,8]])
 
print ('第二个数组:')
print (b)
print ('\n')
# 两个数组的维度相同
 
print ('沿轴 0 连接两个数组:')
print (np.concatenate((a,b)))
print ('\n')
 
print ('沿轴 1 连接两个数组:')
print (np.concatenate((a,b),axis = 1))

'''
第一个数组:
[[1 2]
 [3 4]]


第二个数组:
[[5 6]
 [7 8]]


沿轴 0 连接两个数组:
[[1 2]
 [3 4]
 [5 6]
 [7 8]]


沿轴 1 连接两个数组:
[[1 2 5 6]
 [3 4 7 8]]
'''
复制代码
numpy.stack(arrays, axis)

函数用于沿轴连接数组序列

参数说明:

  • arrays相同形状的数组序列
  • axis:返回数组中的轴,输入数组沿着它来堆叠
python 复制代码
import numpy as np
 
a = np.array([[1,2],[3,4]])
 
print ('第一个数组:')
print (a)
print ('\n')
b = np.array([[5,6],[7,8]])
 
print ('第二个数组:')
print (b)
print ('\n')
 
print ('沿轴 0 堆叠两个数组:')
print (np.stack((a,b),0))
print ('\n')
 
print ('沿轴 1 堆叠两个数组:')
print (np.stack((a,b),1))

'''
第一个数组:
[[1 2]
 [3 4]]


第二个数组:
[[5 6]
 [7 8]]


沿轴 0 堆叠两个数组:
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]


沿轴 1 堆叠两个数组:
[[[1 2]
  [5 6]]

 [[3 4]
  [7 8]]]
'''

水平堆叠

numpy.hstack(arrays)

numpy.stack 函数的变体,它通过水平堆叠来生成数组

python 复制代码
import numpy as np
 
a = np.array([[1,2],[3,4]])
 
print ('第一个数组:')
print (a)
print ('\n')
b = np.array([[5,6],[7,8]])
 
print ('第二个数组:')
print (b)
print ('\n')
 
print ('水平堆叠:')
c = np.hstack((a,b))
print (c)
print ('\n')

'''
第一个数组:
[[1 2]
 [3 4]]


第二个数组:
[[5 6]
 [7 8]]


水平堆叠:
[[1 2 5 6]
 [3 4 7 8]]
'''

垂直堆叠

numpy.vstack(arrays)

numpy.stack 函数的变体,它通过垂直堆叠来生成数组。

python 复制代码
import numpy as np
 
a = np.array([[1,2],[3,4]])
 
print ('第一个数组:')
print (a)
print ('\n')
b = np.array([[5,6],[7,8]])
 
print ('第二个数组:')
print (b)
print ('\n')
 
print ('竖直堆叠:')
c = np.vstack((a,b))
print (c)

'''
第一个数组:
[[1 2]
 [3 4]]


第二个数组:
[[5 6]
 [7 8]]


竖直堆叠:
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
'''

分割数组

函数 数组及操作
split 将一个数组分割为多个子数组
hsplit 将一个数组水平分割为多个子数组(按列)
vsplit 将一个数组垂直分割为多个子数组(按行)

沿轴分割

复制代码
numpy.split(ary, indices_or_sections, axis)

参数说明:

  • ary:被分割的数组
  • indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)
  • axis:设置沿着哪个方向进行切分,默认为 0,横向切分,即水平方向。为 1 时,纵向切分,即竖直方向。
python 复制代码
import numpy as np
 
a = np.arange(9)
 
print ('第一个数组:')
print (a)
print ('\n')
 
print ('将数组分为三个大小相等的子数组:')
b = np.split(a,3)
print (b)
print ('\n')
 
print ('将数组在一维数组中表明的位置分割:')
b = np.split(a,[4,7])
print (b)

'''
第一个数组:
[0 1 2 3 4 5 6 7 8]


将数组分为三个大小相等的子数组:
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]


将数组在一维数组中表明的位置分割:
[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]
'''

axis 为 0 时在水平方向分割,axis 为 1 时在垂直方向分割:

python 复制代码
import numpy as np

a = np.arange(16).reshape(4, 4)
print('第一个数组:')
print(a)

print('默认分割(0轴):')
b1,b2 = np.split(a,2)
print('数组1:\n', b1,'\n数组2:\n', b2)

print('沿纵向分割:')
c1,c2 = np.split(a,2,1)
print('数组1:\n', c1,'\n数组2:\n', c2)


'''
第一个数组:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
默认分割(0轴):
数组1:
 [[0 1 2 3]
 [4 5 6 7]] 
数组2:
 [[ 8  9 10 11]
 [12 13 14 15]]
沿纵向分割:
数组1:
 [[ 0  1]
 [ 4  5]
 [ 8  9]
 [12 13]] 
数组2:
 [[ 2  3]
 [ 6  7]
 [10 11]
 [14 15]]
'''

水平分割

numpy.hsplit(ary, indices_or_sections)

用于水平分割数组,通过指定要返回的相同形状的数组数量来拆分原数组

垂直分割

numpy.vsplit(ary, indices_or_sections)

沿着垂直轴分割,其分割方式与hsplit用法相同。

数组元素的添加与删除

函数 元素及描述
append 将值添加到数组末尾
insert 沿指定轴将值插入到指定下标之前
delete 删掉某个轴的子数组,并返回删除后的新数组
unique 查找数组内的唯一元素

末尾添加值

复制代码
numpy.append(arr, values, axis=None)

函数在数组的末尾添加值。 追加操作会分配整个数组,并把原来的数组复制到新数组中。 此外,输入数组的维度必须匹配否则将生成ValueError。返回的始终是一个一维数组。

参数说明:

  • arr:输入数组
  • values:要向arr添加的值,需要和arr形状相同(除了要添加的轴)
  • axis:默认为 None。当axis无定义时,是横向加成,返回总是为一维数组!当axis有定义的时候,分别为0和1的时候(列数要相同)。当axis为1时,数组是加在右边(行数要相同)。
python 复制代码
import numpy as np

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

print('第一个数组:\n', a)

print('向数组添加元素:')
print(np.append(a, [7, 8, 9]))

print('沿轴 0 添加元素:')
print(np.append(a, [[7, 8, 9]], axis=0))

print('沿轴 1 添加元素:')
print(np.append(a, [[10, 11, 12], [21, 22, 23]], axis=1))

'''
第一个数组:
 [[1 2 3]
 [4 5 6]]
向数组添加元素:
[1 2 3 4 5 6 7 8 9]
沿轴 0 添加元素:
[[1 2 3]
 [4 5 6]
 [7 8 9]]
沿轴 1 添加元素:
[[ 1  2  3 10 11 12]
 [ 4  5  6 21 22 23]]
'''

按索引插入值

复制代码
numpy.insert(arr, obj, values, axis)

在给定索引之前,沿给定轴在输入数组中插入值,将返回一个新数组。如果未提供轴,则输入数组会被展开。

参数说明:

  • arr:输入数组
  • obj:在其之前插入值的索引
  • values:要插入的值
  • axis:沿着它插入的轴,如果未提供,则输入数组会被展开;传递了 Axis 参数。 会广播值数组来配输入数组。
python 复制代码
import numpy as np

a = np.arange(12).reshape(3,4)
print('第一个数组:\n', a)
print('未传递 Axis 参数。 在3前插入[100, 200]之前输入数组会被展开。')
print(np.insert(a, 3, [100, 200]))

#传递了 Axis 参数。 会广播值数组来配输入数组
print('指定0轴的2行(0行开始)前插入[100,101,102,103]:')
print(np.insert(a, 2, [100,101,102,103], axis=0))
print('指定0轴的2行(0行开始)前插入[100],按广播扩展:')
print(np.insert(a, 2, [100], axis=0))

print('指定1轴的3列前插入[100,101,102](会自动转置):')
print(np.insert(a, 3, [100,101,102], axis=1))
print('指定1轴的3列前插入[100],按广播扩展:')
print(np.insert(a, 3, 100, axis=1))

'''
第一个数组:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
未传递 Axis 参数。 在3前插入[100, 200]之前输入数组会被展开。
[  0   1   2 100 200   3   4   5   6   7   8   9  10  11]
指定0轴的2行(0行开始)前插入[100,101,102,103]:
[[  0   1   2   3]
 [  4   5   6   7]
 [100 101 102 103]
 [  8   9  10  11]]
指定0轴的2行(0行开始)前插入[100],按广播扩展:
[[  0   1   2   3]
 [  4   5   6   7]
 [100 100 100 100]
 [  8   9  10  11]]
指定1轴的3列前插入[100,101,102](会自动转置):
[[  0   1   2 100   3]
 [  4   5   6 101   7]
 [  8   9  10 102  11]]
指定1轴的3列前插入[100],按广播扩展:
[[  0   1   2 100   3]
 [  4   5   6 100   7]
 [  8   9  10 100  11]]
'''

删除指定子数组

复制代码
Numpy.delete(arr, obj, axis)

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

参数说明:

  • arr:输入数组
  • obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组
  • axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
python 复制代码
import numpy as np

a = np.arange(12).reshape(3,4)
print('第一个数组:\n', a)
print('删除元素5,未传递 Axis 参数,在插入之前输入数组会被展开。')
print(np.delete(a, 5))

print('如果指定轴1,删除第二列:')
print(np.delete(a, 1, axis=1))

print('包含从数组中删除的替代值的切片:')
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(np.delete(a, np.s_[::2]))


'''
第一个数组:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
删除元素5,未传递 Axis 参数,在插入之前输入数组会被展开。
[ 0  1  2  3  4  6  7  8  9 10 11]
如果指定轴1,删除第二列:
[[ 0  2  3]
 [ 4  6  7]
 [ 8 10 11]]
包含从数组中删除的替代值的切片:
[ 2  4  6  8 10]
'''

数组去重

复制代码
numpy.unique(arr, return_index, return_inverse, return_counts)

返回见下面的说明

参数说明:

  • arr:输入数组,如果不是一维数组则会展开
  • return_index:如果为true,返回新列表元素在旧列表中的位置(下标),并以列表形式储
  • return_inverse:如果为true,返回旧列表元素在新列表中的位置(下标),并以列表形式储
  • return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数
python 复制代码
import numpy as np

a = np.array([[1,2,3,4],[1,2,3,4],[4,5,6,7]])
print('待去重的数组:\n', a)

print('去重:\n', np.unique(a))

print('去重索引数组:')
u, indices = np.unique(a, return_index=True)
print(indices)

print('去重下标:')
u, indices = np.unique(a, return_inverse=True)
print(indices)

print('返回去重元素的重复数量:')
u, indices = np.unique(a, return_counts=True)
print(indices)

'''
待去重的数组:
 [[1 2 3 4]
 [1 2 3 4]
 [4 5 6 7]]
去重:
 [1 2 3 4 5 6 7]
去重索引数组:
[ 0  1  2  3  9 10 11]
去重下标:
[0 1 2 3 0 1 2 3 3 4 5 6]
返回去重元素的重复数量:
[2 2 2 3 1 1 1]
'''
相关推荐
深度学习lover1 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
API快乐传递者2 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
阡之尘埃4 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控
记录成长java5 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js