NumPy 2.x 完全指南【十八】数组元素的新增和删除

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]13 前插入)。
    • 布尔数组(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:可任意形状,追加前会被展平。
    • 若指定 axisvalues 的形状需与 arr 在非 axis 轴上的维度一致。
  • axis:操作的轴。若为 Nonearrvalues 会被展平后再追加。

示例 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_valuesmode = ‘constant’ 时指定填充值,格式同 pad_width(默认 0 )。
  • stat_lengthmode 为统计类(如 ‘maximum’)时,计算统计值的边缘长度。
  • end_values:mode = 'linear_ramp`’ 时指定填充的起始/结束值。
  • reflect_typemode = ‘reflect’ 或 ‘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)

reshaperesize 都可用于调整数组的形状,主要的区别是:

特性reshaperesize
元素数量要求新形状的元素数必须与原数组一致,否则报错。允许新形状的元素数与原数组不同,自动填充或截断数据。
内存行为返回原数组的视图(共享内存),修改新数组会影响原数组。默认返回新数组的副本(不共享内存),除非使用 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 ,axisNone会将数组展平为一维数组后再处理:

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]]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨 禹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值