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是通过嵌套几层中括号来表示的,形状是通过中括号里的元素个数来表示的(中括号里的每一个中括号也是一个元素)。
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:
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的异常:
a = np.array([1,2,3,4, [1,2]])
print(a)
#ValueError: setting an array element with a sequence.
但注意:python会根据输入的数据类型的兼容性,进行自我适应,调整最终的dtype对象:
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']
元素也可以支持字典:
s = np.array([{1:'1'}, {2:'2', 3:'3'}])
print(s) #[{1: '1'} {2: '2', 3: '3’}]
print(s.dtype) #object
元素也支持自定义对象
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类型,所以它们也可以被放在一起:
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
如果要生成多维数组,需要列表对象是嵌套对象:
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会把它识别为多维数组:
a = np.array([(1,2,3,4), (10,20,30,40)])
print(a)
‘’’
[[ 1 2 3 4]
[10 20 30 40]]
’‘’
也可以通过指定ndmin来指定最小维数
b = np.array(('a', 'b', 'c'), ndmin=2)
print(b)
#[['a' 'b' 'c']]
通过dtype指定数组元素的类型:
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,则是对内置数据类型对象的引用
dt = np.dtype(np.int32)
print(dt)
#int32
dt = np.dtype('i4')
print(dt)
#int32
dt = np.dtype('<i4')
print(dt)
#int32
将数据类型应用于 ndarray 对象:
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 对象。
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()的视图相当于新增加了一个指向当前内存的引用,不存在复制操作,速度更快且节约内存。注意通过其中的一个引用修改数据,其他引用的数据也会跟着变,因为他们指向同一块内存区域。
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 的列数组。
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 的列数组。
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来填充。
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 数组的形状。
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
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,读取所有数据。
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:数组的元素类型,如果没有提供,则会使用输入数据的类型。
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:终止值,如果
endpoint
为true
,该值包含于数列中 - num:要生成的等步长的样本数量,默认为
50
- endpoint:该值为
true
时,数列中包含stop
值,反之不包含,默认是True。 - retstep:如果为 True 时,生成的数组中会显示间距,反之不显示。
- dtype:数组的元素类型
numpy.linspace是numpy.arange的增强版本。
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:终止值,如果
endpoint
为true
,该值包含于数列中 - num:要生成的等步长的样本数量,默认为
50
- endpoint:该值为
true
时,数列中包含stop
值,反之不包含,默认是True。 - base:对数 log 的底数。
- dtype:数组的元素类型
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。
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的偏移量
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开始,每个下标代表一行数据,下标的下标代表一个元素,也可以直接用逗号分割各维度:
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列表一样:
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也是可以的,将根据步长取全部的数据。
多维数组切片
多维数组的切片,对于每一个维度,都是遵循一维的切片规则,不同的维度之间通过逗号分割。
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列:
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])
print(a[:,2:3])
‘’'
[[ 3]
[ 30]
[1000]]
‘''
如果直接使用第2列的下标,但得到的不是列数据,而是转置为行的数据:
a = np.array([[1,2,3,4], [10,20,30,40], [10, 100, 1000, 10000]])
print(a[:,2])
’’’
[ 3 30 1000]
‘’‘
如果维度很高,也可以通过...代替前面或后面的维数:
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]]
'''
切片赋值
也可以直接对切片进行赋值,切片是原数组的试图,对切片的赋值,会修改原数组的值。
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) 位置处的元素:
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]
‘''
布尔索引(条件过滤)
可以通过布尔索引做条件过滤。直接在中括号中写过滤条件:
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]
a = np.array([np.nan, 1,2,np.nan,3,4,5])
print (a[~np.isnan(a)])
#[ 1. 2. 3. 4. 5.]
花式索引
花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。
对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素,如果目标是二维数组,那么就是对应下标的行。
花式索引跟切片不一样,它总是将数据复制到新数组中。
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,..]]来获得多行的数据,这就是花式索引。
并且可以用行号重新组织数组,如下:
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 数组对应位相乘。这要求形状相同(维数相同,且各维度的长度也要相同)。
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是一个单一的数,单一的数可以向任何维度复制自己
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是一维数据
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
的错误。
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形状相同的立方体
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一样的形状的数组。
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]]]
‘’‘
立方体和面的和:按面去加和。
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' -- 元素在内存中的出现顺序。
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
:返回数组的新形状
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
一个数组元素迭代器,可以访问全部的数组元素。
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' -- 元素在内存中的出现顺序。
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' -- 元素在内存中的出现顺序。
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:整数列表,对应维度,通常所有维度都会对换。
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)返回的就是转置数组。
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]]
’‘’
对于高维数组,可以任意的排列各轴:
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来表示转置:
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
:默认为零,表示完整的滚动。会滚动到特定位置。
先看二维的情况:
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]]
’‘’
从效果来看就是转置。
再看三维的情况:
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
:对应第二个轴的整数
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。
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
:新轴插入的位置
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为空,则删除所有单维度的条目;
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
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
:返回数组中的轴,输入数组沿着它来堆叠
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 函数的变体,它通过水平堆叠来生成数组
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 函数的变体,它通过垂直堆叠来生成数组。
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 时,纵向切分,即竖直方向。
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 时在垂直方向分割:
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时,数组是加在右边(行数要相同)。
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 参数。 会广播值数组来配输入数组。
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
:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
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
,返回去重数组中的元素在原数组中的出现次数
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]
‘''