数组变形与合并
在数据处理中,经常需要改变数组的形状、拆分或合并数组。本章介绍 NumPy 提供的各种变形与组合操作。
一、改变形状
1、reshape
python
import numpy as np
a = np.arange(12) # shape (12,)
# 变为 3×4
b = a.reshape(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 变为 2×2×3
c = a.reshape(2, 2, 3)
# [[[ 0 1 2]
# [ 3 4 5]]
# [[ 6 7 8]
# [ 9 10 11]]]
# 使用 -1 自动推算
d = a.reshape(3, -1) # shape (3, 4) — 自动算出 4
e = a.reshape(-1, 6) # shape (2, 6) — 自动算出 2
f = a.reshape(2, 2, -1) # shape (2, 2, 3)-1 的妙用
reshape 中最多只能有一个维度使用 -1,NumPy 会根据总元素数自动推算该维度的大小。例如 a.reshape(3, -1) 中,总元素 12 ÷ 3 = 4,所以 -1 变为 4。
2、resize(原地修改)
python
a = np.array([1, 2, 3, 4, 5, 6])
# np.resize: 返回新数组(可以改变总元素数)
b = np.resize(a, (2, 2))
print(b) # [[1 2]
# [3 4]]
c = np.resize(a, (2, 4))
print(c) # [[1 2 3 4]
# [5 6 1 2]] — 重复填充
# a.resize: 原地修改(不返回新数组)
a.resize((2, 3))
print(a)
# [[1 2 3]
# [4 5 6]]3、ravel 与 flatten
python
a = np.array([[1, 2, 3],
[4, 5, 6]])
# ravel: 返回视图(如果可能),更快
b = a.ravel() # [1 2 3 4 5 6] (C-order)
c = a.ravel(order='F') # [1 4 2 5 3 6] (Fortran-order)
# flatten: 总是返回副本
d = a.flatten() # [1 2 3 4 5 6]
d[0] = 99
print(a) # 不变 — 副本
b[0] = 99
print(a) # 被修改 — 视图4、转置与轴变换
python
a = np.arange(24).reshape(2, 3, 4)
# .T 转置(反转所有轴)
print(a.T.shape) # (4, 3, 2)
# transpose: 自定义轴顺序
b = a.transpose(2, 0, 1) # shape (4, 2, 3)
# 原轴 2 → 新轴 0
# 原轴 0 → 新轴 1
# 原轴 1 → 新轴 2
# swapaxes: 交换两个轴
c = a.swapaxes(0, 2) # shape (4, 3, 2)
# 等价于 a.transpose(2, 1, 0)
# moveaxis: 移动轴到新位置
d = np.moveaxis(a, 0, -1) # shape (3, 4, 2)5、expand_dims 与 squeeze
python
a = np.array([1, 2, 3]) # shape (3,)
# expand_dims: 增加维度
b = np.expand_dims(a, axis=0) # shape (1, 3)
c = np.expand_dims(a, axis=1) # shape (3, 1)
# 等价写法
d = a[np.newaxis, :] # shape (1, 3)
e = a[:, np.newaxis] # shape (3, 1)
# squeeze: 移除大小为 1 的维度
f = np.array([[[1, 2, 3]]]) # shape (1, 1, 3)
g = np.squeeze(f) # shape (3,)
h = np.squeeze(f, axis=0) # shape (1, 3) — 只移除指定轴二、数组拼接
1、np.concatenate
沿已有轴拼接:
python
a = np.array([[1, 2],
[3, 4]]) # shape (2, 2)
b = np.array([[5, 6]]) # shape (1, 2)
# 沿 axis=0(行方向)拼接
c = np.concatenate([a, b], axis=0)
# [[1 2]
# [3 4]
# [5 6]] shape (3, 2)
d = np.array([[7],
[8]]) # shape (2, 1)
# 沿 axis=1(列方向)拼接
e = np.concatenate([a, d], axis=1)
# [[1 2 7]
# [3 4 8]] shape (2, 3)2、np.stack
沿新轴堆叠(要求数组形状完全相同):
python
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])
# 沿新 axis=0 堆叠
d = np.stack([a, b, c], axis=0)
# [[1 2 3]
# [4 5 6]
# [7 8 9]] shape (3, 3)
# 沿新 axis=1 堆叠
e = np.stack([a, b, c], axis=1)
# [[1 4 7]
# [2 5 8]
# [3 6 9]] shape (3, 3)3、便捷函数
python
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# hstack: 水平拼接(沿 axis=1)
print(np.hstack([a, b]))
# [[1 2 5 6]
# [3 4 7 8]]
# vstack: 垂直拼接(沿 axis=0)
print(np.vstack([a, b]))
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# dstack: 深度拼接(沿 axis=2)
print(np.dstack([a, b]))
# [[[1 5]
# [2 6]]
# [[3 7]
# [4 8]]] shape (2, 2, 2)
# column_stack: 按列拼接(一维数组先变为列向量)
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
print(np.column_stack([x, y]))
# [[1 4]
# [2 5]
# [3 6]]三、数组拆分
1、np.split
python
a = np.arange(12).reshape(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 沿 axis=0 拆分为 3 份
parts = np.split(a, 3, axis=0)
# [array([[0, 1, 2, 3]]),
# array([[4, 5, 6, 7]]),
# array([[ 8, 9, 10, 11]])]
# 沿 axis=1 按位置拆分
parts = np.split(a, [1, 3], axis=1)
# [array([[0], [4], [8]]), — 第 0 列
# array([[ 1, 2], [ 5, 6], [ 9, 10]]), — 第 1-2 列
# array([[ 3], [ 7], [11]])] — 第 3 列2、便捷函数
python
a = np.arange(12).reshape(3, 4)
# hsplit: 水平拆分(沿 axis=1)
left, right = np.hsplit(a, 2)
# left: [[0 1] [4 5] [8 9]]
# right: [[2 3] [6 7] [10 11]]
# vsplit: 垂直拆分(沿 axis=0)
top, bottom = np.vsplit(a, [2])
# top: [[0 1 2 3] [4 5 6 7]]
# bottom: [[8 9 10 11]]
# dsplit: 深度拆分(沿 axis=2)
c = np.arange(24).reshape(2, 3, 4)
front, back = np.dsplit(c, 2)四、数组重复与平铺
1、np.tile
整体重复数组:
python
a = np.array([1, 2, 3])
print(np.tile(a, 3)) # [1 2 3 1 2 3 1 2 3]
print(np.tile(a, (2, 1)))
# [[1 2 3]
# [1 2 3]]
print(np.tile(a, (2, 3)))
# [[1 2 3 1 2 3 1 2 3]
# [1 2 3 1 2 3 1 2 3]]2、np.repeat
逐元素重复:
python
a = np.array([1, 2, 3])
print(np.repeat(a, 3)) # [1 1 1 2 2 2 3 3 3]
print(np.repeat(a, [1, 2, 3]))# [1 2 2 3 3 3] — 每个元素重复不同次数
b = np.array([[1, 2],
[3, 4]])
print(np.repeat(b, 2, axis=0))
# [[1 2]
# [1 2]
# [3 4]
# [3 4]]
print(np.repeat(b, 2, axis=1))
# [[1 1 2 2]
# [3 3 4 4]]五、数组翻转与旋转
python
a = np.arange(6).reshape(2, 3)
# [[0 1 2]
# [3 4 5]]
# 上下翻转
print(np.flipud(a))
# [[3 4 5]
# [0 1 2]]
# 左右翻转
print(np.fliplr(a))
# [[2 1 0]
# [5 4 3]]
# 沿指定轴翻转
print(np.flip(a, axis=0)) # 同 flipud
print(np.flip(a, axis=1)) # 同 fliplr
# 旋转 90°
print(np.rot90(a))
# [[2 5]
# [1 4]
# [0 3]]
print(np.rot90(a, k=2)) # 旋转 180°六、数组排序
python
a = np.array([3, 1, 4, 1, 5, 9, 2, 6])
# 返回排序后的副本
print(np.sort(a)) # [1 1 2 3 4 5 6 9]
# 原地排序
a.sort()
print(a) # [1 1 2 3 4 5 6 9]
# 返回排序索引
a = np.array([3, 1, 4, 1, 5])
idx = np.argsort(a)
print(idx) # [1 3 0 2 4]
print(a[idx]) # [1 1 3 4 5]
# 二维排序
b = np.array([[3, 1],
[1, 4],
[4, 2]])
# 按列排序
print(np.sort(b, axis=0))
# [[1 1]
# [3 2]
# [4 4]]
# 按行排序
print(np.sort(b, axis=1))
# [[1 3]
# [1 4]
# [2 4]]
# 部分排序(最快找前 k 个最小值)
print(np.partition(a, 3)) # 前 3 个位置放最小的 3 个值📖 官方文档