1. 新增元素
在现有数组中添加新元素或子数组:
函数/方法 | 描述 |
---|---|
insert(arr, obj, values, axis=None) | 在指定轴的位置前插入值。 |
append(arr, values, axis=None) | 在数组末尾追加值。 |
pad(array, pad_width, mode='constant') | 在数组边缘填充值。 |
resize(a, new_shape) | 返回指定形状的新数组(若新形状大于原数组,填充重复值)。 |
1.1 insert
numpy.insert()
:在数组的指定轴(维度)的给定索引位置前插入值,返回新数组(原数组不变)。
函数定义:
def insert(arr, obj, values, axis=None)
参数说明:
arr
:输入的原始数组。obj
:插入位置的索引或索引序列。支持以下形式:- 标量整数:在指定索引前插入(如
obj=1
在索引1
前插入)。 - 整数数组:在多个索引位置插入(如
obj=[1,3]
在1
和3
前插入)。 - 布尔数组(
v2.1.2+
):True
的位置插入值(视为掩码)。 - 切片对象:在切片范围内插入(如
slice(2,4)
)。
- 标量整数:在指定索引前插入(如
values
:要插入的值。若类型与arr
不同,会自动转换为arr
的类型。插入后的数组在指定轴上的切片可被values
填充。axis
:操作的轴。若为None
,先展平数组再插入(默认行为)。
示例 1 ,一维数组:
a = np.array([0, 1, 2, 3])
# 在索引 2 前插入值 99
b = np.insert(a, 2, 99)
print(b) # [0, 1, 99, 2, 3]
示例 2 ,二维数组沿 1
轴(列方向)插入:
a = np.array([[0, 1],
[2, 3],
[4, 5]])
# 在每行的索引 1 前插入 6(沿轴 1 )
b = np.insert(a, 1, 6, axis=1)
print(b)
# [[0, 6, 1],
# [2, 6, 3],
# [4, 6, 5]]
示例 3 ,指定插入位置为布尔数组:
a = np.array([0, 1, 2, 3])
# 在掩码为 True 的位置(索引 1 和 3 前)插入
mask = np.array([False, True, False, True])
b = np.insert(a, mask, 10)
print(b) # [0, 10, 1, 2, 10, 3]
示例 4 ,当 axis=None
时,数组会先被展平为一维数组,然后插入:
# 原数组形状 (3, 2)
a = np.array([[0, 1], [2, 3], [4, 5]])
# 默认 axis=None,展平后插入
result = np.insert(a, 1, 6)
print(result) # 输出: [0 6 1 2 3 4 5]
# 原数组形状 (2, 2, 2)
b = np.array([[[0, 1], [2, 3]], [[4, 5], [6, 7]]])
# 展平后插入值99到索引3前
result = np.insert(b, 3, 99)
print(result)
# 输出: [ 0 1 2 99 3 4 5 6 7]
1.2 append
numpy.append()
:将值追加到数组的末尾,返回新数组(原数组不变)。
函数定义:
def append(arr, values, axis=None)
参数说明:
arr
:原始数组,追加操作基于其副本进行。values
:要追加的值。其形状需满足以下条件:- 若
axis=None
:可任意形状,追加前会被展平。 - 若指定
axis
:values
的形状需与arr
在非axis
轴上的维度一致。
- 若
axis
:操作的轴。若为None
,arr
和values
会被展平后再追加。
示例 1 ,axis=None
时,会展平为一维数组后进行追加:
arr = np.array([1, 2, 3])
values = [[4, 5],
[6, 7]]
result = np.append(arr, values) # 展平后追加
print(result) # [1, 2, 3, 4, 5, 6, 7]
示例 2 ,指定 axis
时,形状不匹配引发错误:
arr = np.array([[1, 2], [3, 4]]) # 形状 (2, 2)
values = [5, 6] # 形状 (2,)
try:
np.append(arr, values, axis=0) # 尝试沿行方向追加
except ValueError as e:
print(e) # 错误:输入数组维度不匹配
示例 3 ,指定 axis = 0
时,列方向上的维度数一样,才能进行追加操作 :
arr = np.array([[1, 2],
[3, 4]]) # 形状 (2, 2)
values = [[5, 6]] # 形状 (1, 2)
result = np.append(arr, values, axis=0) # 沿行方向追加
print(result)
# [[1, 2],
# [3, 4],
# [5, 6]]
1.3 pad
numpy.pad()
:对数组进行边缘填充,支持多种填充模式,适用于数据预处理、图像处理、信号处理等场景。
函数定义:
def pad(array, pad_width, mode='constant', **kwargs)
参数说明:
arr
:输入数组(支持任意维度)。pad_width
:各轴边缘的填充宽度。int
:所有轴前后填充相同数量。((before_1, after_1), ...)
:按轴分别指定。
mode
:填充模式(默认 ‘constant
’),可选 ‘edge
’、‘reflect
’、‘linear_ramp
’ 等。constant_values
:mode
= ‘constant
’ 时指定填充值,格式同pad_width
(默认0
)。stat_length
:mode
为统计类(如 ‘maximum
’)时,计算统计值的边缘长度。end_values
:mode= '
linear_ramp`’ 时指定填充的起始/结束值。reflect_type
:mode
= ‘reflec
t’ 或 ‘symmetric
’ 时的反射类型,可选 ‘even
’、‘odd
’。
填充模式 (mode
) 配置项说明:
constant
: 用常数值填充(默认0
)。edge
:用数组边缘值填充。linear_ramp
:用起始值到边缘值的线性渐变填充。maximum
:用边缘区域的最大值填充。mean
:用边缘区域的均值填充。reflect
:用边缘值的镜像反射填充(默认even
)。symmetric
:用对称于边缘的镜像填充。wrap
:用数组对侧的循环值填充。- 自定义函数: 用户定义填充逻辑(需操作
vector[:pad_before]
和vector[-pad_after:]
)。
注意事项:
- 多维数组按轴顺序填充,后轴填充可能依赖前轴结果(如角落值)。
- 避免对大数组频繁填充,推荐预分配内存。
- 填充值类型与原数组不同时,自动转换可能导致精度损失。
示例 1 ,常数值填充:
a = [1, 2, 3, 4, 5]
# 前填充 2 个 4 ,后填充 3 个 6
result = np.pad(a, (2, 3), 'constant', constant_values=(4, 6))
print(result) # [4, 4, 1, 2, 3, 4, 5, 6, 6, 6]
示例 2 ,边缘值填充:
a = [1, 2, 3, 4, 5]
# 前填充 2 个 1 ,后填充 3 个 5
result = np.pad(a, (2, 3), 'edge')
print(result) # [1, 1, 1, 2, 3, 4, 5, 5, 5, 5]
示例 3 ,线性渐变填充:
a = [1, 2, 3, 4, 5]
# 前填充从 5 到 1 的线性渐变,后填充从 5 到 -4 的渐变
result = np.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4))
print(result) # [5, 3, 1, 2, 3, 4, 5, 2, -1, -4]
示例 4 ,最大值填充:
a = [1, 2, 3, 4, 5]
# 前填充 2 个 5(原数组最大值),后填充 3 个 5
result = np.pad(a, (2,), 'maximum')
print(result) # [5, 5, 1, 2, 3, 4, 5, 5, 5]
示例 5 ,镜像反射填充:
a = [1, 2, 3, 4, 5]
# 反射类型为 'even'(默认)
result = np.pad(a, (2, 3), 'reflect')
print(result) # [3, 2, 1, 2, 3, 4, 5, 4, 3, 2]
# 反射类型为 'odd'(填充值 = 2 * 边缘值 - 反射值)
result = np.pad(a, (2, 3), 'reflect', reflect_type='odd')
print(result) # [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
示例 6 ,自定义填充函数:
def pad_with(vector, pad_width, iaxis, kwargs):
pad_value = kwargs.get('padder', 10)
vector[:pad_width[0]] = pad_value # 前填充
vector[-pad_width[1]:] = pad_value # 后填充
a = np.arange(6).reshape((2, 3))
print(a)
# [[0 1 2]
# [3 4 5]]
# 所有方向填充 2 层,值设为 10
result = np.pad(a, 2, pad_with)
print(result)
# [[10 10 10 10 10 10 10]
# [10 10 10 10 10 10 10]
# [10 10 0 1 2 10 10]
# [10 10 3 4 5 10 10]
# [10 10 10 10 10 10 10]
# [10 10 10 10 10 10 10]]
1.4 resize
resize()
:改变数组的形状并允许调整元素数量。
注意事项:
- 直接改变原数组本身,所以不会返回任何值,
- 若新形状的元素总数
<
原数组元素总数,则截断原数组。 - 若新形状的元素总数
>
原数组元素总数,则填充默认值,填充的值取决于数组数据类型,如整数填充0
,浮点数填充0.0
。 - 当形状兼容时,尽量使用
numpy.reshape
函数。
函数定义:
def resize(a, new_shape)
参数说明:
a
:需要调整形状的数组。new_shape
:新形状。
方法定义:
@overload
def resize(self, new_shape: _ShapeLike, /, *, refcheck: builtins.bool = ...) -> None: ...
参数说明:
new_shape
:新形状。refcheck
:默认为True
,检查是否有其他对象引用该数组,若为False
则强制调整(可能引发内存错误)。
numpy.resize
函数和 arr.resize
方法的主要区别:
方法 | 是否修改原数组 | 返回值 | 填充方式 | 适用场景 |
---|---|---|---|---|
arr.resize() | ✅ 是 | None | 零填充 | 需要原地修改数组时 |
np.resize(arr) | ❌ 否 | 新数组 | 循环重复数据 | 需要保留原数组时 |
示例 1 ,numpy.resize
函数会循环填充原数据:
import numpy as np
arr = np.array([[1, 2], [3, 4]]) # 原始形状 (2, 2)
print(arr)
# 输出:
# [[1 2]
# [3 4]]
new_arr = np.resize(arr, new_shape=(3, 3)) # 扩展为 3 x 3,填充 0
print(new_arr)
# 输出:
# [[1 2 3]
# [4 1 2]
# [3 4 1]]
示例 2 ,arr.resize
方法默认填充 0
:
arr1 = np.array([[5, 6], [7, 8]])
arr1.resize((3, 3))
print(arr1)
# 输出:
# [[5 6 7]
# [8 0 0]
# [0 0 0]]
注意:arr.resize
方是直接改变原数组本身,所以不会返回任何值,以下写法会直接返回 None
:
new_arr= arr1.resize((3, 3))
print(new_arr) # None
示例 3 ,若原数组存在其他引用时,默认会报错 ValueError
:
arr = np.array([1, 2, 3])
arr_ref = arr # 创建引用
arr.resize((4,)) # 等价于 arr.resize((4,), refcheck=True)
print(arr) # 报错
# ValueError: cannot resize an array that references or is referenced
# by another array in this way.
# Use the np.resize function or refcheck=False
# 可以设置 refcheck=False 强制调整(不推荐),可能引发未定义行为
arr.resize((4,), refcheck=False)
reshape
和 resize
都可用于调整数组的形状,主要的区别是:
特性 | reshape | resize |
---|---|---|
元素数量要求 | 新形状的元素数必须与原数组一致,否则报错。 | 允许新形状的元素数与原数组不同,自动填充或截断数据。 |
内存行为 | 返回原数组的视图(共享内存),修改新数组会影响原数组。 | 默认返回新数组的副本(不共享内存),除非使用 refcheck=False 参数修改原数组。 |
是否修改原数组 | 不修改原数组,返回新视图。 | 默认不修改原数组,但通过 numpy.resize() 函数返回新数组;ndarray.resize() 方法会直接修改原数组。 |
适用场景 | 保持数据完整性的形状变换(如适配模型输入)。 | 动态调整数组大小(如填充缺失值或截断冗余数据)。 |
2. 删除元素
在现有数组中删除新元素或子数组:
函数/方法 | 描述 |
---|---|
delete(arr, obj, axis=None) | 沿指定轴删除子数组,返回新数组。 |
trim_zeros(filt, trim='fb', axis=None) | 删除数组中全零的维度。 |
unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None) | 返回数组中唯一元素(排序后)。 |
2.1 delete
numpy.delete()
:删除数组沿指定轴的子数组或元素,返回新数组(原数组不变)。
函数定义:
def delete(arr, obj, axis=None)
参数说明:
arr
:输入的原始数组。obj
:要删除的索引或掩码。- 标量整数:删除单个索引对应的子数组。
- 整数数组:删除多个索引对应的子数组。
- 布尔数组(
v1.19.0+
):True
的位置删除对应的子数组(视为掩码)。 - 切片对象:删除切片范围内的子数组。
axis
:操作的轴。若为None
,先展平数组再删除。
示例 1 ,展平后删除指定元素(axis=None
):
arr = np.array([1, 2, 3])
values = [[4, 5],
[6, 7]]
result = np.append(arr, values) # 展平后追加
print(result) # [1, 2, 3, 4, 5, 6, 7]
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
result = np.delete(arr, [1, 3, 5], axis=None) # 展平后删除索引 1、3、5
print(result)
# [1, 3, 5, 7, 8, 9, 10, 11, 12]
示例 2 ,删除二维数组的行:
result = np.delete(arr, 1, axis=0) # 删除第二行(索引 1 )
print(result)
# [[ 1, 2, 3, 4],
# [ 9, 10, 11, 12]]
示例 3 ,删除二维数组的列::
# np.s_[::2] 生成一个切片对象,表示从数组起始到结束,步长为 2 的切片。
result = np.delete(arr, np.s_[::2], axis=1) # 删除偶数列(索引 0 和 2 )
print(result)
# [[ 2, 4],
# [ 6, 8],
# [10, 12]]
2.2 trim_zeros
numpy.trim_zeros()
:移除数组在指定维度(轴)边缘的全零部分。
函数定义:
def trim_zeros(filt, trim='fb', axis=None)
参数说明:
filt
:输入的数组(支持任意维度)。trim
:修剪方向。- ‘
fb
’(默认):同时修剪前后边缘的零。 - ‘
f
’:仅修剪前面的零。 - ‘
b
’:仅修剪后面的零。
- ‘
axis
:指定修剪的轴。若为None
,则修剪所有维度。
示例 1 ,axis=None
时,trim_zeros
一维数组会移除前面和后面的零,保留中间的非零区域(包括中间夹杂的零):
a = np.array([0, 0, 0, 1, 2, 3, 0, 2, 1, 0])
result = np.trim_zeros(a)
print(result) # [1 2 3 0 2 1]
axis=None
时,trim_zeros
二维数组会逐层裁剪所有轴:
- 行轴(axis=0):删除全零的行。
- 列轴(axis=1):删除全零的列。
示例 2 ,二维数组:
b = np.array([
[0, 0, 2, 3, 0, 0],
[0, 1, 0, 3, 0, 0],
[0, 0, 0, 0, 0, 0] # 全零行
])
result = np.trim_zeros(b)
print(result)
# [[0 2 3]
# [1 0 3]]
``
示例 3 ,高维数组也是一样会逐层裁剪所有轴,确保输出是包含所有非零数据的最小区域:
```python
c = np.array([
[
[0, 0, 0, 0],
[0, 0, 0, 0], # 全零深度层
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[0, 9, 5, 0], # 非零深度层
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[0, 0, 0, 0], # 全零深度层
[0, 0, 0, 0]
]
])
result = np.trim_zeros(c)
print(result) # [[[9 5]]]
``
示例 4 ,设置 `trim = "b"` 表示只裁剪后面的零:
```python
b = np.array([
[0, 0, 0, 0, 0, 0], # 全零行
[0, 0, 2, 3, 0, 0],
[0, 1, 0, 3, 0, 0],
[0, 0, 0, 0, 0, 0] # 全零行
])
result = np.trim_zeros(b, trim="b")
print(result)
# [[0 0 0 0]
# [0 0 2 3]
# [0 1 0 3]]
示例 5 ,设置 axis
表示只裁剪指定轴上的零:
c = np.array([
[
[0, 0, 0, 0],
[0, 0, 0, 0], # 全零深度层
[0, 0, 0, 0]
],
[
[0, 0, 0, 0],
[0, 9, 5, 0], # 非零深度层
[0, 0, 0, 0]
]
])
result = np.trim_zeros(c, axis=1)
print(result)
# [[[0 0 0 0]]
# [[0 9 5 0]]]
2.3 unique
numpy.unique()
:查找数组中唯一元素并返回排序结果(去重)。
函数定义:
numpy.unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None, *, equal_nan=True)
参数说明:
ar
:输入数组。如果未指定轴,且数组不是一维的,则会展平数组。return_index
:默认为False
,若为True
,返回唯一值在原数组中的首次出现索引。return_inverse
:默认为False
,若为True
,返回重构原数组所需的索引数组。return_counts
:默认为False
,若为True
,返回每个唯一元素出现的次数。axis
:指定操作的轴,默认为None
,会将数组展平后处理,若为整数,沿指定轴处理子数组。equal_nan
:默认为True
,多个NaN
视为相同元素。axis
:指定操作的轴,默认为None
,会将数组展平后处理
示例 1 ,axis
为 None
会将数组展平为一维数组后再处理:
a = [1, 1, 2, 2, 3, 3, 3]
res = np.unique(a)
print(res)
# 输出: [1 2 3]
b = np.array([[1, 0, 0],
[1, 0, 0],
[2, 3, 4]])
res = np.unique(b)
print(res)
# 输出: [0 1 2 3 4]
示例 2 ,指定操作的轴去重:
b = np.array([[1, 0, 0, 5],
[1, 0, 0, 5],
[2, 3, 3, 5]])
# 按行去重:每一行完全相同的去除(第一行和第二行)
res = np.unique(b, axis=0)
print(res)
# 输出: [[1 0 0 5]
# [2 3 3 5]]
# 按列去重:每一列完全相同的去除(第二列和第三列)
res = np.unique(b, axis=1)
print(res)
# 输出: [[0 1 5]
# [0 1 5]
# [3 2 5]]
示例 3 ,设置 return_index=True
时,除了去重排序结果,还会返回唯一值在原数组中的首次出现索引:
b = np.array([[1, 0, 0, 5],
[1, 0, 0, 5],
[2, 3, 3, 5]])
# 展平后处理
print(np.unique(b, axis=None, return_index=True))
# 输出: (array([0, 1, 2, 3, 5]), array([1, 0, 8, 9, 3]))
print(np.unique(b, axis=0, return_index=True))
# 输出: (array([[1, 0, 0, 5],
# [2, 3, 3, 5]]),
# array([0, 2]))
示例 4 ,设置 return_counts=True
时,还会返回统计次数:
# 展平后处理
print(np.unique(b, axis=None, return_counts=True))
# 输出: (array([0, 1, 2, 3, 5]), array([4, 2, 1, 2, 3]))
print(np.unique(b, axis=0, return_counts=True))
# 输出: (array([[1, 0, 0, 5],
# [2, 3, 3, 5]]), array([2, 1]))
示例 5 ,设置 return_inverse=True
时,还会返回重构索引:
# 展平后处理
print(np.unique(b, axis=None, return_inverse=True))
# 输出: (array([0, 1, 2, 3, 5]),
#
# array([[1, 0, 0, 4],
# [1, 0, 0, 4],
# [2, 3, 3, 4]]))
print(np.unique(b, axis=0, return_inverse=True))
# 输出: (array([[1, 0, 0, 5],
# [2, 3, 3, 5]]),
#
# array([0, 0, 1]))
示例 6 ,多个 return
参数多个返回值的顺序如下:
a = [1, 1, 2, 2, 3, 3, 3]
unique, return_index, return_inverse, return_counts = np.unique(a,
return_inverse=True,
return_counts=True,
return_index=True)
示例 7 ,一维数组或被展平后的数组,可以通过整数数组索引(高级索引,后续介绍)进行重构:
# 原始数组
a = np.array([1, 2, 6, 4, 2, 3, 2])
# 获取唯一值和重构索引
unique, unique_inverse = np.unique(a, return_inverse=True)
print("唯一值数组:", unique) # 输出: [1 2 3 4 6]
print("重构索引:", unique_inverse) # 输出: [0 1 4 3 1 2 1]
# 重构原始数组
reconstructed = unique[unique_inverse] # 整数数组索引(高级索引,后续介绍)
print("重构结果:", reconstructed) # 输出: [1 2 6 4 2 3 2]
b = np.array([[1, 0, 0, 5],
[1, 0, 0, 5],
[2, 3, 3, 5]])
# 展平后处理
unique, unique_inverse = np.unique(b, axis=None, return_inverse=True)
print("唯一值数组:", unique) # 输出: [0 1 2 3 5]
print("重构索引:", unique_inverse)
# 输出: [[1 0 0 4]
# [1 0 0 4]
# [2 3 3 4]]
# 重构原始数组
reconstructed = unique[unique_inverse] # 整数数组索引(高级索引,后续介绍)
print("重构结果:", reconstructed)
# 输出: [[1 0 0 5]
# [1 0 0 5]
# [2 3 3 5]]
示例 8 ,当指定 axis
参数时,unique_inverse
的维度与原始数组对应轴的长度一致。需要使用 np.take
或直接索引重构:
# 原始二维数组
a = np.array([[1, 0, 0, 5],
[1, 0, 0, 5],
[2, 3, 3, 5]])
# 按行去重(axis=0)
unique, unique_inverse = np.unique(a, axis=1, return_inverse=True)
print("唯一值数组:\n", unique)
# 输出:
# [[1 0 0]
# [2 3 4]]
print("重构索引:", unique_inverse) # 输出: [1 0 0 2]
# 重构原始数组
reconstructed = np.take(unique, unique_inverse, axis=1)
print("重构结果:\n", reconstructed)
# 输出:
# [[1 0 0 5]
# [1 0 0 5]
# [2 3 3 5]]