多维数组
numpy.ndarray
(N-dimensional array)是 NumPy 库的基础对象,绝大部分操作都是以其作为操作对象。
属性 | 含义 |
---|---|
ndarray.ndim | 阶数或轴的数量(如:向量的阶数为 1 1 1,矩阵的阶数为 2 2 2) |
ndarray.shape | 形状即各个轴的维度(如:对于
m
×
n
m \times n
m×n 的矩阵结果为 (m, n) ) |
ndarray.size | 元素的总数量 |
ndarray.dtype | 元素的数据类型 |
ndarray.itemsize | 每个元素的占有的字节数 |
ndarray.strides | 在各个轴中跳跃到下一个维度需要跨越字节数 |
数据类型
以下是numpy.ndarray
中元素的数据类型,也是 NumPy 库的数据类型,更是ndarray.dtype
的取值范围。
数据类型 | 含义 |
---|---|
numpy.bool_ 或'b' | 布尔型 |
numpy.intp | 有符号索引型(等价于 C 语言 ssize_t ) |
numpy.intc 或'i' | 整型(等价于 C 语言 int ) |
numpy.int_ 或'l' | 长整型(等价于 C 语言 long ) |
numpy.int8 或'i1' | 单字节整型 |
numpy.int16 或'i2' | 双字节整型 |
numpy.int32 或'i4' | 4 4 4 字节整型 |
numpy.int64 或'i8' | 8 8 8 字节整型 |
numpy.uint8 或'u1' | 单字节无符号整型 |
numpy.uint16 或'u2' | 双字节无符号整型 |
numpy.uint32 或'u4' | 4 4 4 字节无符号整型 |
numpy.uint64 或'u8' | 8 8 8 字节无符号整型 |
numpy.float16 或'f2' | 半精度浮点数 |
numpy.float32 或'f4' 或'f' | 单精度浮点数 |
numpy.float_ 或numpy.float64 或'f8' 或'd' | 双精度浮点数 |
numpy.complex64 或'c8' | 单精度浮点复数(由两个单精度浮点数拼接而成,一个作实部,一个作虚部) |
numpy.complex128 或numpy.complex_ 或'c16' | 双精度浮点复数 |
在使用字符来表示数据类型时,可以添加前缀字符'<'
或'>'
来分别表示小端法存储或大端法存储。如'<u8'
表示小端法存储的
8
8
8 字节无符号整型变量。
以下几种特殊的数据类型也可做为numpy.ndarray
中元素的数据类型,但无法进行数学运算,仅作了解即可。
特殊的数据类型 | 含义 |
---|---|
'c' | 字符 |
numpy.string_ 或'S' | 字符串('S' 后可以接整数来限定字符串的长度,如'S4' 表示字符串最多容纳四个字符) |
numpy.unicode_ 或'U' | 统一编码字符串('U' 后也可接数字,用法与'S' 相同) |
numpy.object_ 或'O' | 对象的引用 |
numpy.dtype
numpy.dtype
是用来描述数据类型的对象,numpy.ndarray
的属性ndarray.dtype
就是一个numpy.dtype
实例。
- 创建单一的数据类型
代码
import numpy as np
d = np.dtype(np.uint8)
a = np.array([1, 2, 3, 4, 5, 6], dtype=d)
print(d)
print(a)
输出
uint8
[1 2 3 4 5 6]
- 创捷结构化数据类型
如果要创建如下 C 语言结构体
struct student{
char name[20];
uint8 age;
float score;
}
可以使用如下代码
import numpy as np
d = np.dtype([
('name', 'S20'),
('age', np.uint8),
('score', 'f'),
])
a = np.array([('Tom', 18, 90.5), ('Leo', '23', 100), ('Jack', 25, 95.5)], dtype=d)
print(d)
print(a)
print(a[1]['score'])
print(a['name'])
输出
[('name', 'S20'), ('age', 'u1'), ('score', '<f4')]
[(b'Tom', 18, 90.5) (b'Leo', 23, 100. ) (b'Jack', 25, 95.5)]
100.0
[b'Tom' b'Leo' b'Jack']
函数中常见参数
shape: tuple
指定数组的形状。
dtype: numpy.dtype
指定元素类型。
axis: int
axis=None
表示将多维数组当作一维数组进行操作。
axis=i
表示函数沿着第i
个轴(多维数组的第i
个下标)进行操作。
axis
为正表示从外向内的轴序号。
axis
为负表示从内向外的轴序号。
keepdims: bool
使函数输出的数组的轴的数量与输入的数组的轴的数量保持一致。
生成数组
普通方式
numpy.array
从已有数组创建
numpy.array(p_object, dtype = None, copy = True, order = None, subok = False, ndmin = 0, like=None)
参数 | 含义 |
---|---|
p_object | 传入已有的数组(可以是列表、元组、多级列表等) |
dtype | 指定创建的数组元素类型 |
import numpy as np
a = np.array(range(5))
print(type(a))
print(a)
<class 'numpy.ndarray'>
[0 1 2 3 4]
numpy.empty
创建空数组
numpy.empty(shape, dtype=None, order='C', like=None)
参数 | 含义 |
---|---|
shape | 空数组的形状 |
dtype | 空数组的元素类型 |
import numpy as np
a = np.empty((3, 4))
print(type(a))
print(a)
<class 'numpy.ndarray'>
[[2.31881454e-152 1.46922109e+195 6.01347002e-154 2.02446113e+267]
[1.17074645e+214 7.35195137e+223 6.20654037e+223 4.95238693e+223]
[1.06758000e+224 1.38983954e+093 6.01334515e-154 8.84050710e+025]]
numpy.full
使用同一元素填充成数组
numpy.full(shape, fill_value, dtype=None, order='C', like=None)
参数 | 含义 |
---|---|
shape | 数组的形状 |
fill_value | 用来填充的元素 |
dtype | 数组的元素类型 |
import numpy as np
a = np.full((3, 4), 5)
print(type(a))
print(a)
<class 'numpy.ndarray'>
[[5 5 5 5]
[5 5 5 5]
[5 5 5 5]]
numpy.ones
数值全部为 1 1 1 的数组
numpy.ones(shape, dtype=None, order='C', like=None)
参数含义参看上文numpy.empty
来举一反三
numpy.zeros
数值全部为 0 0 0 的数组
numpy.zeros(shape, dtype=None, order='C', like=None)
参看上一个函数举一反三
numpy.arange
等差数组
numpy.arange([start,] stop[, step,], dtype=None, like=None)
使用方法与 Python 内建函数range
相同。
numpy.linspace
在特定区域内生成等差数组
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
参数 | 含义 |
---|---|
start | 区域的起始点 |
end | 区域的终止点 |
num | 要在区域内均匀生成数字的数量 |
endpoint | 数字中是否包含终止点 |
dtype | 元素类型 |
numpy.geomspace
在特定区域内生成等比数组
numpy.geomspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
参看上一个函数自行脑补。
随机生成
numpy.random.rand
样本总体服从 [ 0 , 1 ) [0,1) [0,1) 上的均匀分布
numpy.random.rand(*dn)
参数 | 含义 |
---|---|
*dn | 数组的shape 序列(当不填写此参数时,函数返回一个标量) |
数组中的每个元素都是样本总体产生的独立样本。
import numpy as np
print(np.random.rand())
print(np.random.rand(2, 2))
0.5339194972793695
[[0.71516046 0.15637954]
[0.07004625 0.95339708]]
numpy.random.random
样本总体服从 [ 0 , 1 ) [0,1) [0,1) 上的均匀分布
numpy.random.random(size=None)
参数 | 含义 |
---|---|
size | 数组的shape (为None 时函数返回一个标量,为整数n 时等价于(n,) ) |
numpy.random.random() == numpy.random.rand()
numpy.random.random(2) == numpy.random.rand(2)
numpy.random.random((2, 2)) == numpy.random.rand(2, 2)
numpy.random.random_sample
与上一函数相同,只不过换了个名。
numpy.random.randn
样本总体服从标准正态分布
numpy.random.randn(*dn)
参数解释参看上上文中numpy.random.rand
函数自行脑补
numpy.random.standard_normal
样本总体服从标准正态分布
numpy.random.standard_normal(size=None)
参数 | 含义 |
---|---|
size | 数组的 shape (为 None 时函数返回一个标量,为整数 n 时等价于 (n,) ) |
numpy.random.standard_normal() == numpy.random.randn()
numpy.random.standard_normal(2) == numpy.random.randn(2)
numpy.random.standard_normal((2, 2)) == numpy.random.randn(2, 2)
numpy.random.normal
样本总体服从正态分布
numpy.random.normal(loc=0.0, scale=1.0, size=None)
参数 | 含义 |
---|---|
loc | 总体的均值 |
scale | 总体的标准差 |
size | 数组的 shape (为 None 时函数返回一个标量) |
numpy.random.normal() == numpy.random.randn()
numpy.random.normal(size=(2,2)) == numpy.random.randn(2, 2)
numpy.random.randint
在指定的左闭右开区间 ['low', 'high')
内生成服从均匀分布的整数数组
numpy.random.randint(low, high=None, size=None, dtype=None)
参数 | 含义 |
---|---|
low | 区间下界(当 high 缺省时区间为 [0, 'low') ) |
high | 区间上界 |
size | 数组的 shape (为 None 时函数返回一个标量) |
dtype | 数组元素的类型 |
import numpy as np
print(np.random.randint(4))
print(np.random.randint(1, 5, (2, 2)))
1
[[2 1]
[2 4]]
numpy.random.random_integers
在指定的闭区间 ['low', 'high']
内生成服从均匀分布的整数数组
numpy.random.randint(low, high=None, size=None)
参数 | 含义 |
---|---|
low | 区间下界(当 high 缺省时区间为 [1, 'high') ) |
high | 区间上界 |
size | 数组的 shape (为 None 时函数返回一个标量) |
切片、索引
切片
import numpy as np
a = np.arange(10)
print(a[1:4]) # start=1, stop=4, step=1
print(a[1:8:2]) # start=1, stop=8, step=2
print(a[:5]) # start=0, stop=5, step=1
print(a[2:]) # start=2, stop=len(a), step=1
print(a[::2]) # start=0, stop=len(a), step=2
[1 2 3]
[1 3 5 7]
[0 1 2 3 4]
[2 3 4 5 6 7 8 9]
[0 2 4 6 8]
使用负数
import numpy as np
a = np.arange(10)
print(a[:-1]) # start=2, stop=len(a)-1, step=1
print(a[::-1]) # start=len(a)-1, stop=0-1, step=-1
print(a[4:2:-1]) # start=4, stop=2, step=-1
[0 1 2 3 4 5 6 7 8]
[9 8 7 6 5 4 3 2 1 0]
[4 3]
在多维数组上操作
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(a[1][2])
print(a[1, 2])
6
6
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(a[1][:2])
print(a[1, :2])
[4 5]
[4 5]
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(a[:, 1]) # 索引第 1 列
print(a[..., 1]) # 索引第 1 列
[2 5 8]
[2 5 8]
使用坐标索引
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(a[[0, 1, 2], [0, 1, 2]]) # 索引 (0, 0)、(1, 1) 和 (2, 2) 处元素
b = ([0, 1, 2], [0, 1, 2])
print(a[b]) # 索引 (0, 0)、(1, 1) 和 (2, 2) 处元素
[1 5 9]
[1 5 9]
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(a[..., [0, 2]]) # 索引第 0 和 2 列元素
[[1 3]
[4 6]
[7 9]]
布尔索引
numpy.extract
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
b = np.array([ # 布尔数组
[False, False, False, ],
[False, False, True, ],
[False, True, True, ],
])
print(np.extract(b, a)) # 索引出布尔数组中为 True 的元素
print(a[b]) # 与上一句等价
print(a[~b]) # 索引出布尔数组中为 False 的元素
[6 8 9]
[6 8 9]
[1 2 3 4 5 7]
条件布尔数组
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
b = a > 5 # 数组 a 中各元素是否满足条件(大于 5)
print(b)
print(a[b]) # 索引出满足条件的元素
print('\n')
b = (a > 5) & (a < 8) # 与,本质上是两个布尔数组对应元素做与运算
print(b)
print(a[b])
print('\n')
b = (a > 5) | (a < 5) # 或
print(b)
print(a[b])
print('\n')
[[False False False]
[False False True]
[ True True True]]
[6 7 8 9]
[[False False False]
[False False True]
[ True False False]]
[6 7]
[[ True True True]
[ True False True]
[ True True True]]
[1 2 3 4 6 7 8 9]
numpy.logic_and 和 numpy.logic_or
numpy.logic_and(a > 5, a < 8)
等价于 (a > 5) & (a < 8)
numpy.logic_or(a > 5, a < 5)
等价于 (a > 5) | (a < 5)
numpy.isnan、numpy.isinf 和 numpy.isfinate
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, float('nan'), 6, ],
[float('inf'), 8, 9, ],
])
print(a[np.isnan(a)]) # 索引无效(nan)的元素
print(a[~np.isnan(a)]) # 索引有效的元素
print(a[np.isinf(a)]) # 索引无穷大的元素
print(a[np.isfinite(a)]) # 索引非无穷大的元素
[nan]
[ 1. 2. 3. 4. 6. inf 8. 9.]
[inf]
[1. 2. 3. 4. 6. 8. 9.]
查找
布尔索引也可以看成一种查找操作,但却不是一种直接查找的方式,布尔索引是通过布尔数组来间接完成查找操作。
numpy.where
返回符合条件的元素的坐标
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
b = np.where(a > 5)
print(a[b]) # 查找大于 5 的元素
print(b)
a[b] = 0 # 将大于 5 的元素全部设为 0
print(a)
[6 7 8 9]
(array([1, 2, 2, 2], dtype=int64), array([2, 0, 1, 2], dtype=int64))
[[1 2 3]
[4 5 0]
[0 0 0]]
numpy.max 和 numpy.ndarray.max 以及 numpy.min 和 numpy.ndarray.min
查找最大值和最小值
以下代码中使用的参数的含义请参看上文中函数中常见的参数
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(np.max(a))
print(np.max(a, axis=0))
print(a.max(axis=1, keepdims=True))
print('\n')
print(np.min(a))
print(np.min(a, axis=0))
print(a.min(axis=1, keepdims=True))
print('\n')
9
[7 8 9]
[[3]
[6]
[9]]
1
[1 2 3]
[[1]
[4]
[7]]
numpy.argmax 和 numpy.ndarray.argmax 以及 numpy.argmin 和 numpy.ndarray.argmin
查找最大值和最小值的下标
import numpy as np
a = np.array([
[1, 2, 3, ],
[4, 5, 6, ],
[7, 8, 9, ],
])
print(np.argmax(a))
print(np.argmax(a, axis=0))
print(a.argmax(axis=1, keepdims=True))
print('')
print(np.argmin(a))
print(np.argmin(a, axis=0))
print(a.argmin(axis=1, keepdims=True))
print('')
8
[2 2 2]
[[2]
[2]
[2]]
0
[0 0 0]
[[0]
[0]
[0]]
变形
numpy.reshape 和 numpy.ndarray.reshape
返回的是数组的引用,修改引用将会影响原始数组。
numpy.reshape(a, newshape, order='C') -> reshaped_array: numpy.ndarray
numpy.ndarray.reshape(self, shape, order='C) -> reshaped_array: numpy.ndarray
import numpy as np
a = np.arange(10)
print(a.reshape(5, 2))
print(np.reshape(a, (-1, 2))) # -1 表示自适应
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
numpy.ndarray.flatten 和 numpy.ravel 与 numpy.ndarray.ravel 以及 numpy.ndarray.flat
numpy.ndarray.flatten
将数组的拷贝拉直成一维数组而后返回,修改拷贝不会影响原始数组。
numpy.ravel
与 numpy.ndarray.ravel
将数组的引用拉直成一维数组而后返回,修改引用会影响原始数组。
numpy.ndarray.flat
数组中元素的迭代器。
import numpy as np
a = np.arange(10).reshape(2, 5)
print('a:', a)
print('')
b = a.flatten()
c = np.ravel(a)
print('b:', b)
print('c:', c)
print('')
b[0] = 666 # 此处不会影响 a
c[1] = 666 # 此处将会影响 a
print('a:', a)
print('')
c[1] = 1
for i in a:
print(i)
print('')
for i in a.flat:
print(i, end=' ')
a: [[0 1 2 3 4]
[5 6 7 8 9]]
b: [0 1 2 3 4 5 6 7 8 9]
c: [0 1 2 3 4 5 6 7 8 9]
a: [[ 0 666 2 3 4]
[ 5 6 7 8 9]]
[0 1 2 3 4]
[5 6 7 8 9]
0 1 2 3 4 5 6 7 8 9
翻转
numpy.transpose 与 numpy.ndarray.transpose 和 numpy.ndarray.T
求转置矩阵
修改返回的转置矩阵会影响到原始矩阵。
import numpy as np
a = np.arange(6).reshape(2, 3)
print(a)
print()
print(np.transpose(a))
print()
print(a.transpose())
print()
print(a.T)
print()
[[0 1 2]
[3 4 5]]
[[0 3]
[1 4]
[2 5]]
[[0 3]
[1 4]
[2 5]]
[[0 3]
[1 4]
[2 5]]
可以使用参数 axes
来指定翻转的方式,如 axes=(1, 2, 0)
表示将 0
、1
和 2
号轴分别翻转到 1
、2
和 0
号轴。
import numpy as np
a = np.arange(6).reshape(1, 2, 3)
print(a)
print()
print(np.transpose(a, axes=(1, 2, 0)))
print()
print((np.transpose(a) == np.transpose(a, axes=(2, 1, 0))).all())
[[[0 1 2]
[3 4 5]]]
[[[0]
[1]
[2]]
[[3]
[4]
[5]]]
True
numpy.swapaxes 和 numpy.ndarray.swapaxes
对换两个轴
返回的是数组的引用
import numpy as np
a = np.arange(6).reshape(2, 3)
print(np.swapaxes(a, 0, 1))
print()
print(a.swapaxes(0, 1))
[[0 3]
[1 4]
[2 5]]
[[0 3]
[1 4]
[2 5]]
改变轴的数量
numpy.expand_dims 和 numpy.newaxis
numpy.expand_dims(a, axis: Union[int, Tuple[int, ...]])
返回的是数组的引用。
import numpy as np
a = np.arange(10)
print(np.expand_dims(a, 0))
print(a[np.newaxis, ...]) # 与上句等价
print(a[..., np.newaxis]) # 在第 1 轴上扩展
print(np.expand_dims(a, (0, 2)))
[[0 1 2 3 4 5 6 7 8 9]]
[[0 1 2 3 4 5 6 7 8 9]]
[[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]]
[[[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]]]
使用 numpy.reshape
扩展。
import numpy as np
a = np.arange(10)
print(np.reshape(a, (1, *a.shape))) # 在第 0 轴上扩展
print(a.reshape((*a.shape, 1))) # 在第 1 轴上扩展
[[0 1 2 3 4 5 6 7 8 9]]
[[0]
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]]
numpy.squeeze 和 numpy.ndarray.squeeze
numpy.squeeze(a, axis: Union[int, Tuple[int, ...]])
numpy.ndarray.squeeze(axis: Union[int, Tuple[int, ...]])
返回的是数组的引用。
import numpy as np
a = np.arange(10).reshape(1, -1)
print(a)
print(np.squeeze(a, 0))
print(a.squeeze(0))
[[0 1 2 3 4 5 6 7 8 9]]
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
使用 numpy.reshape
压缩。
import numpy as np
a = np.arange(10).reshape(1, -1)
print(a)
print(a.reshape(-1))
[[0 1 2 3 4 5 6 7 8 9]]
[0 1 2 3 4 5 6 7 8 9]
连接
numpy.concatenate
在指定维度上连接
返回新的数组。
numpy.concatenate((a1, a2, ...), axis)
import numpy as np
a = np.arange(10).reshape(1, -1)
b = a.copy()
print(np.concatenate((a, b), axis=0))
print(np.concatenate((a, b), axis=1))
[[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]]
[[0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9]]
numpy.stack
在指定维度上堆叠
与上一个函数不同的是,返回的新数组相对于原数组会增加一个轴。
numpy.stack((a1, a2, ...), axis)
import numpy as np
a = np.arange(10)
b = a.copy()
print(np.stack((a, b), axis=0))
print(np.stack((a, b), axis=1))
[[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]]
[[0 0]
[1 1]
[2 2]
[3 3]
[4 4]
[5 5]
[6 6]
[7 7]
[8 8]
[9 9]]
numpy.vstack 和 numpy.hstack
numpy.vstack((a1, a2, ...))
等价于 numpy.concatenate((a1, a2, ...), 0)
numpy.hstack((a1, a2, ...))
等价于 numpy.concatenate((a1, a2, ...), 1)