Skip to content

数组形状操作

在这一章中,我们将学习如何操作 NumPy 数组的形状,包括重塑、转置、拼接、分割等操作,这些是数据处理中的重要技能。

数组形状基础

理解数组形状

python
import numpy as np

# 创建不同形状的数组
array_1d = np.array([1, 2, 3, 4, 5, 6])
array_2d = np.array([[1, 2, 3], [4, 5, 6]])
array_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])

print("一维数组:")
print(f"数组: {array_1d}")
print(f"形状: {array_1d.shape}")
print(f"维度: {array_1d.ndim}")
print(f"大小: {array_1d.size}")
print()

print("二维数组:")
print(f"数组:\n{array_2d}")
print(f"形状: {array_2d.shape}")
print(f"维度: {array_2d.ndim}")
print(f"大小: {array_2d.size}")
print()

print("三维数组:")
print(f"数组:\n{array_3d}")
print(f"形状: {array_3d.shape}")
print(f"维度: {array_3d.ndim}")
print(f"大小: {array_3d.size}")

输出结果:

一维数组:
数组: [1 2 3 4 5 6]
形状: (6,)
维度: 1
大小: 6

二维数组:
数组:
[[1 2 3]
 [4 5 6]]
形状: (2, 3)
维度: 2
大小: 6

三维数组:
数组:
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
形状: (2, 2, 2)
维度: 3
大小: 8

数组重塑(Reshape)

基本重塑操作

python
import numpy as np

# 创建一维数组
array_1d = np.arange(12)
print("原始一维数组:", array_1d)
print("形状:", array_1d.shape)
print()

# 重塑为二维数组
array_2d_3x4 = array_1d.reshape(3, 4)
print("重塑为3x4:")
print(array_2d_3x4)
print("形状:", array_2d_3x4.shape)
print()

array_2d_4x3 = array_1d.reshape(4, 3)
print("重塑为4x3:")
print(array_2d_4x3)
print("形状:", array_2d_4x3.shape)
print()

# 重塑为三维数组
array_3d = array_1d.reshape(2, 2, 3)
print("重塑为2x2x3:")
print(array_3d)
print("形状:", array_3d.shape)
print()

# 使用-1自动计算维度
auto_reshape = array_1d.reshape(3, -1)  # 自动计算列数
print("自动计算维度(3, -1):")
print(auto_reshape)
print("形状:", auto_reshape.shape)

auto_reshape2 = array_1d.reshape(-1, 4)  # 自动计算行数
print("自动计算维度(-1, 4):")
print(auto_reshape2)
print("形状:", auto_reshape2.shape)

输出结果:

原始一维数组: [ 0  1  2  3  4  5  6  7  8  9 10 11]
形状: (12,)

重塑为3x4:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
形状: (3, 4)

重塑为4x3:
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
形状: (4, 3)

重塑为2x2x3:
[[[ 0  1  2]
  [ 3  4  5]]

 [[ 6  7  8]
  [ 9 10 11]]]
形状: (2, 2, 3)

自动计算维度(3, -1):
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
形状: (3, 4)
自动计算维度(-1, 4):
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
形状: (3, 4)

重塑的注意事项

python
import numpy as np

array = np.arange(12)
print("原始数组:", array)

# 重塑必须保持元素总数不变
try:
    # 这会出错,因为 3*5 = 15 ≠ 12
    wrong_reshape = array.reshape(3, 5)
except ValueError as e:
    print(f"错误: {e}")

# 正确的重塑
correct_reshape = array.reshape(3, 4)
print("正确重塑:")
print(correct_reshape)
print()

# reshape 返回视图,不是副本
original = np.arange(6)
reshaped = original.reshape(2, 3)

print("原始数组:", original)
print("重塑数组:")
print(reshaped)
print("是否共享内存:", np.shares_memory(original, reshaped))

# 修改重塑后的数组会影响原数组
reshaped[0, 0] = 999
print("修改重塑数组后:")
print("原始数组:", original)
print("重塑数组:")
print(reshaped)

输出结果:

原始数组: [ 0  1  2  3  4  5  6  7  8  9 10 11]
错误: cannot reshape array of size 12 into shape (3,5)
正确重塑:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

原始数组: [0 1 2 3 4 5]
重塑数组:
[[0 1 2]
 [3 4 5]]
是否共享内存: True
修改重塑数组后:
原始数组: [999   1   2   3   4   5]
重塑数组:
[[999   1   2]
 [  3   4   5]]

数组展平

flatten() vs ravel()

python
import numpy as np

# 创建二维数组
array_2d = np.array([[1, 2, 3], [4, 5, 6]])
print("原始二维数组:")
print(array_2d)
print()

# flatten() - 返回副本
flattened = array_2d.flatten()
print("flatten() 结果:", flattened)
print("是否共享内存:", np.shares_memory(array_2d, flattened))

# 修改 flatten 结果不会影响原数组
flattened[0] = 999
print("修改 flatten 结果后:")
print("原数组:", array_2d)
print("flatten 结果:", flattened)
print()

# ravel() - 返回视图(如果可能)
array_2d = np.array([[1, 2, 3], [4, 5, 6]])  # 重新创建
raveled = array_2d.ravel()
print("ravel() 结果:", raveled)
print("是否共享内存:", np.shares_memory(array_2d, raveled))

# 修改 ravel 结果会影响原数组
raveled[0] = 888
print("修改 ravel 结果后:")
print("原数组:", array_2d)
print("ravel 结果:", raveled)

输出结果:

原始二维数组:
[[1 2 3]
 [4 5 6]]

flatten() 结果: [1 2 3 4 5 6]
是否共享内存: False
修改 flatten 结果后:
原数组: [[1 2 3]
 [4 5 6]]
flatten 结果: [999   2   3   4   5   6]

ravel() 结果: [1 2 3 4 5 6]
是否共享内存: True
修改 ravel 结果后:
原数组: [[888   2   3]
 [  4   5   6]]
ravel 结果: [888   2   3   4   5   6]

不同的展平顺序

python
import numpy as np

array_2d = np.array([[1, 2, 3], [4, 5, 6]])
print("原始数组:")
print(array_2d)
print()

# C风格展平(行优先,默认)
c_order = array_2d.flatten('C')
print("C风格展平(行优先):", c_order)

# Fortran风格展平(列优先)
f_order = array_2d.flatten('F')
print("Fortran风格展平(列优先):", f_order)

# 演示三维数组的展平
array_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("\n三维数组:")
print(array_3d)
print("形状:", array_3d.shape)

print("C风格展平:", array_3d.flatten('C'))
print("F风格展平:", array_3d.flatten('F'))

输出结果:

原始数组:
[[1 2 3]
 [4 5 6]]

C风格展平(行优先): [1 2 3 4 5 6]
Fortran风格展平(列优先): [1 4 2 5 3 6]

三维数组:
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
形状: (2, 2, 2)
C风格展平: [1 2 3 4 5 6 7 8]
F风格展平: [1 5 3 7 2 6 4 8]

数组转置

基本转置操作

python
import numpy as np

# 二维数组转置
array_2d = np.array([[1, 2, 3], [4, 5, 6]])
print("原始数组:")
print(array_2d)
print("形状:", array_2d.shape)
print()

# 使用 .T 属性
transposed_T = array_2d.T
print("使用 .T 转置:")
print(transposed_T)
print("形状:", transposed_T.shape)
print()

# 使用 transpose() 方法
transposed_method = array_2d.transpose()
print("使用 transpose() 转置:")
print(transposed_method)
print("形状:", transposed_method.shape)
print()

# 使用 np.transpose() 函数
transposed_func = np.transpose(array_2d)
print("使用 np.transpose() 转置:")
print(transposed_func)
print("形状:", transposed_func.shape)

输出结果:

原始数组:
[[1 2 3]
 [4 5 6]]
形状: (2, 3)

使用 .T 转置:
[[1 4]
 [2 5]
 [3 6]]
形状: (3, 2)

使用 transpose() 转置:
[[1 4]
 [2 5]
 [3 6]]
形状: (3, 2)

使用 np.transpose() 转置:
[[1 4]
 [2 5]
 [3 6]]
形状: (3, 2)

多维数组转置

python
import numpy as np

# 三维数组转置
array_3d = np.arange(24).reshape(2, 3, 4)
print("原始三维数组:")
print(array_3d)
print("形状:", array_3d.shape)
print()

# 默认转置(反转所有轴)
default_transpose = array_3d.T
print("默认转置:")
print(default_transpose)
print("形状:", default_transpose.shape)
print()

# 指定轴的顺序进行转置
# 原始轴顺序: (0, 1, 2) -> 新轴顺序: (2, 0, 1)
custom_transpose = array_3d.transpose(2, 0, 1)
print("自定义转置 (2, 0, 1):")
print(custom_transpose)
print("形状:", custom_transpose.shape)
print()

# 另一种轴顺序: (1, 2, 0)
another_transpose = array_3d.transpose(1, 2, 0)
print("自定义转置 (1, 2, 0):")
print(another_transpose)
print("形状:", another_transpose.shape)

输出结果:

原始三维数组:
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
形状: (2, 3, 4)

默认转置:
[[[ 0 12]
  [ 4 16]
  [ 8 20]]

 [[ 1 13]
  [ 5 17]
  [ 9 21]]

 [[ 2 14]
  [ 6 18]
  [10 22]]

 [[ 3 15]
  [ 7 19]
  [11 23]]]
形状: (4, 3, 2)

自定义转置 (2, 0, 1):
[[[ 0  4  8]
  [12 16 20]]

 [[ 1  5  9]
  [13 17 21]]

 [[ 2  6 10]
  [14 18 22]]

 [[ 3  7 11]
  [15 19 23]]]
形状: (4, 2, 3)

自定义转置 (1, 2, 0):
[[[ 0 12]
  [ 1 13]
  [ 2 14]
  [ 3 15]]

 [[ 4 16]
  [ 5 17]
  [ 6 18]
  [ 7 19]]

 [[ 8 20]
  [ 9 21]
  [10 22]
  [11 23]]]
形状: (3, 4, 2)

数组拼接

基本拼接操作

python
import numpy as np

# 创建示例数组
array1 = np.array([1, 2, 3])
array2 = np.array([4, 5, 6])
array3 = np.array([7, 8, 9])

print("数组1:", array1)
print("数组2:", array2)
print("数组3:", array3)
print()

# 水平拼接(一维数组)
hstack_result = np.hstack([array1, array2, array3])
print("水平拼接:", hstack_result)

# 垂直拼接(创建二维数组)
vstack_result = np.vstack([array1, array2, array3])
print("垂直拼接:")
print(vstack_result)
print()

# 使用 concatenate
concat_result = np.concatenate([array1, array2, array3])
print("concatenate 拼接:", concat_result)

输出结果:

数组1: [1 2 3]
数组2: [4 5 6]
数组3: [7 8 9]

水平拼接: [1 2 3 4 5 6 7 8 9]
垂直拼接:
[[1 2 3]
 [4 5 6]
 [7 8 9]]

concatenate 拼接: [1 2 3 4 5 6 7 8 9]

二维数组拼接

python
import numpy as np

# 创建二维数组
array2d_1 = np.array([[1, 2], [3, 4]])
array2d_2 = np.array([[5, 6], [7, 8]])

print("数组1:")
print(array2d_1)
print("数组2:")
print(array2d_2)
print()

# 水平拼接(沿列方向)
hstack_2d = np.hstack([array2d_1, array2d_2])
print("水平拼接:")
print(hstack_2d)
print()

# 垂直拼接(沿行方向)
vstack_2d = np.vstack([array2d_1, array2d_2])
print("垂直拼接:")
print(vstack_2d)
print()

# 使用 concatenate 指定轴
concat_axis0 = np.concatenate([array2d_1, array2d_2], axis=0)
print("沿轴0拼接(行方向):")
print(concat_axis0)
print()

concat_axis1 = np.concatenate([array2d_1, array2d_2], axis=1)
print("沿轴1拼接(列方向):")
print(concat_axis1)

输出结果:

数组1:
[[1 2]
 [3 4]]
数组2:
[[5 6]
 [7 8]]

水平拼接:
[[1 2 5 6]
 [3 4 7 8]]

垂直拼接:
[[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]]

深度拼接和其他拼接方法

python
import numpy as np

# 创建二维数组
array1 = np.array([[1, 2], [3, 4]])
array2 = np.array([[5, 6], [7, 8]])

print("数组1:")
print(array1)
print("数组2:")
print(array2)
print()

# 深度拼接(沿第三个轴)
dstack_result = np.dstack([array1, array2])
print("深度拼接:")
print(dstack_result)
print("形状:", dstack_result.shape)
print()

# 使用 stack 创建新轴
stack_axis0 = np.stack([array1, array2], axis=0)
print("stack 沿轴0:")
print(stack_axis0)
print("形状:", stack_axis0.shape)
print()

stack_axis1 = np.stack([array1, array2], axis=1)
print("stack 沿轴1:")
print(stack_axis1)
print("形状:", stack_axis1.shape)
print()

stack_axis2 = np.stack([array1, array2], axis=2)
print("stack 沿轴2:")
print(stack_axis2)
print("形状:", stack_axis2.shape)

输出结果:

数组1:
[[1 2]
 [3 4]]
数组2:
[[5 6]
 [7 8]]

深度拼接:
[[[1 5]
  [2 6]]

 [[3 7]
  [4 8]]]
形状: (2, 2, 2)

stack 沿轴0:
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
形状: (2, 2, 2)

stack 沿轴1:
[[[1 2]
  [5 6]]

 [[3 4]
  [7 8]]]
形状: (2, 2, 2)

stack 沿轴2:
[[[1 5]
  [2 6]]

 [[3 7]
  [4 8]]]
形状: (2, 2, 2)

数组分割

基本分割操作

python
import numpy as np

# 一维数组分割
array_1d = np.arange(12)
print("原始数组:", array_1d)
print()

# 等分分割
split_equal = np.split(array_1d, 3)  # 分成3个相等部分
print("等分为3部分:")
for i, part in enumerate(split_equal):
    print(f"  部分{i+1}: {part}")
print()

# 指定分割点
split_points = np.split(array_1d, [3, 7])  # 在索引3和7处分割
print("在索引3和7处分割:")
for i, part in enumerate(split_points):
    print(f"  部分{i+1}: {part}")
print()

# 使用 array_split(允许不等分)
array_split_result = np.array_split(array_1d, 5)  # 分成5部分(不等分)
print("不等分为5部分:")
for i, part in enumerate(array_split_result):
    print(f"  部分{i+1}: {part}")

输出结果:

原始数组: [ 0  1  2  3  4  5  6  7  8  9 10 11]

等分为3部分:
  部分1: [0 1 2 3]
  部分2: [4 5 6 7]
  部分3: [ 8  9 10 11]

在索引3和7处分割:
  部分1: [0 1 2]
  部分2: [3 4 5 6]
  部分3: [ 7  8  9 10 11]

不等分为5部分:
  部分1: [0 1 2]
  部分2: [3 4]
  部分3: [5 6]
  部分4: [7 8]
  部分5: [ 9 10 11]

二维数组分割

python
import numpy as np

# 创建二维数组
array_2d = np.arange(24).reshape(4, 6)
print("原始二维数组:")
print(array_2d)
print("形状:", array_2d.shape)
print()

# 水平分割(沿列分割)
hsplit_result = np.hsplit(array_2d, 3)  # 分成3列
print("水平分割(3列):")
for i, part in enumerate(hsplit_result):
    print(f"  部分{i+1}:")
    print(part)
print()

# 垂直分割(沿行分割)
vsplit_result = np.vsplit(array_2d, 2)  # 分成2行
print("垂直分割(2行):")
for i, part in enumerate(vsplit_result):
    print(f"  部分{i+1}:")
    print(part)
print()

# 使用 split 指定轴
split_axis0 = np.split(array_2d, 2, axis=0)  # 沿轴0分割
print("沿轴0分割:")
for i, part in enumerate(split_axis0):
    print(f"  部分{i+1}:")
    print(part)
print()

split_axis1 = np.split(array_2d, 2, axis=1)  # 沿轴1分割
print("沿轴1分割:")
for i, part in enumerate(split_axis1):
    print(f"  部分{i+1}:")
    print(part)

输出结果:

原始二维数组:
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]
形状: (4, 6)

水平分割(3列):
  部分1:
[[ 0  1]
 [ 6  7]
 [12 13]
 [18 19]]
  部分2:
[[ 2  3]
 [ 8  9]
 [14 15]
 [20 21]]
  部分3:
[[ 4  5]
 [10 11]
 [16 17]
 [22 23]]

垂直分割(2行):
  部分1:
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
  部分2:
[[12 13 14 15 16 17]
 [18 19 20 21 22 23]]

沿轴0分割:
  部分1:
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
  部分2:
[[12 13 14 15 16 17]
 [18 19 20 21 22 23]]

沿轴1分割:
  部分1:
[[ 0  1  2]
 [ 6  7  8]
 [12 13 14]
 [18 19 20]]
  部分2:
[[ 3  4  5]
 [ 9 10 11]
 [15 16 17]
 [21 22 23]]

数组维度操作

增加和删除维度

python
import numpy as np

# 创建一维数组
array_1d = np.array([1, 2, 3, 4, 5])
print("原始一维数组:", array_1d)
print("形状:", array_1d.shape)
print()

# 增加维度
# 使用 np.newaxis
array_row = array_1d[np.newaxis, :]  # 添加行维度
array_col = array_1d[:, np.newaxis]  # 添加列维度

print("添加行维度:")
print(array_row)
print("形状:", array_row.shape)
print()

print("添加列维度:")
print(array_col)
print("形状:", array_col.shape)
print()

# 使用 np.expand_dims
expand_axis0 = np.expand_dims(array_1d, axis=0)
expand_axis1 = np.expand_dims(array_1d, axis=1)

print("expand_dims axis=0:")
print(expand_axis0)
print("形状:", expand_axis0.shape)
print()

print("expand_dims axis=1:")
print(expand_axis1)
print("形状:", expand_axis1.shape)
print()

# 删除维度
array_with_extra_dim = np.array([[[1, 2, 3, 4, 5]]])
print("带额外维度的数组:")
print(array_with_extra_dim)
print("形状:", array_with_extra_dim.shape)

# 使用 squeeze 删除长度为1的维度
squeezed = np.squeeze(array_with_extra_dim)
print("删除多余维度后:")
print(squeezed)
print("形状:", squeezed.shape)

输出结果:

原始一维数组: [1 2 3 4 5]
形状: (5,)

添加行维度:
[[1 2 3 4 5]]
形状: (1, 5)

添加列维度:
[[1]
 [2]
 [3]
 [4]
 [5]]
形状: (5, 1)

expand_dims axis=0:
[[1 2 3 4 5]]
形状: (1, 5)

expand_dims axis=1:
[[1]
 [2]
 [3]
 [4]
 [5]]
形状: (5, 1)

带额外维度的数组:
[[[1 2 3 4 5]]]
形状: (1, 1, 5)
删除多余维度后:
[1 2 3 4 5]
形状: (5,)

轴的交换和移动

python
import numpy as np

# 创建三维数组
array_3d = np.arange(24).reshape(2, 3, 4)
print("原始三维数组:")
print(array_3d)
print("形状:", array_3d.shape)
print()

# 交换轴
swapped = np.swapaxes(array_3d, 0, 2)  # 交换轴0和轴2
print("交换轴0和轴2:")
print(swapped)
print("形状:", swapped.shape)
print()

# 移动轴
moved = np.moveaxis(array_3d, 0, -1)  # 将轴0移动到最后
print("将轴0移动到最后:")
print(moved)
print("形状:", moved.shape)
print()

# 移动多个轴
moved_multiple = np.moveaxis(array_3d, [0, 1], [2, 0])  # 轴0->轴2, 轴1->轴0
print("轴0->轴2, 轴1->轴0:")
print(moved_multiple)
print("形状:", moved_multiple.shape)

输出结果:

原始三维数组:
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
形状: (2, 3, 4)

交换轴0和轴2:
[[[ 0 12]
  [ 4 16]
  [ 8 20]]

 [[ 1 13]
  [ 5 17]
  [ 9 21]]

 [[ 2 14]
  [ 6 18]
  [10 22]]

 [[ 3 15]
  [ 7 19]
  [11 23]]]
形状: (4, 3, 2)

将轴0移动到最后:
[[[ 0 12]
  [ 1 13]
  [ 2 14]
  [ 3 15]]

 [[ 4 16]
  [ 5 17]
  [ 6 18]
  [ 7 19]]

 [[ 8 20]
  [ 9 21]
  [10 22]
  [11 23]]]
形状: (3, 4, 2)

轴0->轴2, 轴1->轴0:
[[[ 0 12]
  [ 1 13]
  [ 2 14]
  [ 3 15]]

 [[ 4 16]
  [ 5 17]
  [ 6 18]
  [ 7 19]]

 [[ 8 20]
  [ 9 21]
  [10 22]
  [11 23]]]
形状: (3, 4, 2)

实际应用示例

示例1:图像数据处理

python
import numpy as np

# 模拟RGB图像数据 (高度, 宽度, 通道)
height, width, channels = 4, 6, 3
image = np.random.randint(0, 256, (height, width, channels), dtype=np.uint8)

print(f"原始图像形状: {image.shape}")
print(f"图像数据类型: {image.dtype}")
print("图像数据(前2行):")
print(image[:2])
print()

# 转换为不同的通道顺序(HWC -> CHW)
image_chw = np.transpose(image, (2, 0, 1))
print(f"转换为CHW格式: {image_chw.shape}")
print()

# 提取单个通道
red_channel = image[:, :, 0]
green_channel = image[:, :, 1]
blue_channel = image[:, :, 2]

print(f"红色通道形状: {red_channel.shape}")
print("红色通道数据:")
print(red_channel)
print()

# 重新组合通道(改变顺序:RGB -> BGR)
bgr_image = np.stack([blue_channel, green_channel, red_channel], axis=2)
print(f"BGR图像形状: {bgr_image.shape}")
print()

# 图像批处理(添加批次维度)
batch_size = 2
batch_images = np.stack([image, image], axis=0)  # 复制图像创建批次
print(f"批次图像形状: {batch_images.shape}")

# 展平图像用于机器学习
flattened_image = image.reshape(-1, channels)  # 展平为 (像素数, 通道数)
print(f"展平图像形状: {flattened_image.shape}")

示例2:数据重组和分析

python
import numpy as np

# 模拟时间序列数据:30天,每天24小时,3个传感器
days, hours, sensors = 30, 24, 3
data = np.random.normal(20, 5, (days, hours, sensors))  # 温度数据

print(f"原始数据形状: {data.shape}")
print(f"数据范围: {data.min():.1f} - {data.max():.1f}")
print()

# 重组数据:按传感器分组
sensor_data = np.transpose(data, (2, 0, 1))  # (传感器, 天数, 小时)
print(f"按传感器分组: {sensor_data.shape}")

# 计算每个传感器的日平均值
daily_averages = np.mean(sensor_data, axis=2)  # 对小时维度求平均
print(f"日平均值形状: {daily_averages.shape}")
print("传感器1前5天的日平均值:", daily_averages[0, :5])
print()

# 重组为周数据(假设从周一开始)
weeks = days // 7
weekly_data = data[:weeks*7].reshape(weeks, 7, hours, sensors)
print(f"周数据形状: {weekly_data.shape}")

# 计算周平均值
weekly_averages = np.mean(weekly_data, axis=(1, 2))  # 对天和小时求平均
print(f"周平均值形状: {weekly_averages.shape}")
print("各周各传感器平均值:")
for week in range(weeks):
    print(f"  第{week+1}周: {weekly_averages[week]}")
print()

# 数据展平用于统计分析
flat_data = data.reshape(-1, sensors)
print(f"展平数据形状: {flat_data.shape}")
print("各传感器总体统计:")
for i in range(sensors):
    sensor_values = flat_data[:, i]
    print(f"  传感器{i+1}: 均值={np.mean(sensor_values):.2f}, "
          f"标准差={np.std(sensor_values):.2f}")

示例3:矩阵操作和线性代数

python
import numpy as np

# 创建矩阵
matrix_a = np.array([[1, 2, 3], [4, 5, 6]])
matrix_b = np.array([[7, 8], [9, 10], [11, 12]])

print("矩阵A:")
print(matrix_a)
print(f"形状: {matrix_a.shape}")
print()

print("矩阵B:")
print(matrix_b)
print(f"形状: {matrix_b.shape}")
print()

# 矩阵乘法
matrix_product = np.dot(matrix_a, matrix_b)
print("矩阵乘积 A × B:")
print(matrix_product)
print(f"形状: {matrix_product.shape}")
print()

# 转置在矩阵运算中的应用
# A^T × A(常用于最小二乘法)
ata = np.dot(matrix_a.T, matrix_a)
print("A^T × A:")
print(ata)
print(f"形状: {ata.shape}")
print()

# 创建对称矩阵
symmetric = np.array([[1, 2, 3], [2, 4, 5], [3, 5, 6]])
print("对称矩阵:")
print(symmetric)
print("是否对称:", np.allclose(symmetric, symmetric.T))
print()

# 矩阵的块操作
# 创建块矩阵
block_matrix = np.block([[matrix_a, matrix_product], 
                        [matrix_product.T, matrix_a]])
print("块矩阵:")
print(block_matrix)
print(f"形状: {block_matrix.shape}")

性能优化技巧

内存布局和性能

python
import numpy as np
import time

# 创建大数组测试性能
size = 1000
array_c = np.random.random((size, size))
array_f = np.asfortranarray(array_c)  # Fortran顺序

print(f"C顺序数组标志: {array_c.flags['C_CONTIGUOUS']}")
print(f"Fortran顺序数组标志: {array_f.flags['F_CONTIGUOUS']}")
print()

# 测试行访问性能
start_time = time.time()
for i in range(100):
    _ = array_c[i, :].sum()  # 访问行
c_row_time = time.time() - start_time

start_time = time.time()
for i in range(100):
    _ = array_f[i, :].sum()  # 访问行
f_row_time = time.time() - start_time

print(f"C顺序行访问时间: {c_row_time:.4f}秒")
print(f"F顺序行访问时间: {f_row_time:.4f}秒")
print()

# 测试列访问性能
start_time = time.time()
for i in range(100):
    _ = array_c[:, i].sum()  # 访问列
c_col_time = time.time() - start_time

start_time = time.time()
for i in range(100):
    _ = array_f[:, i].sum()  # 访问列
f_col_time = time.time() - start_time

print(f"C顺序列访问时间: {c_col_time:.4f}秒")
print(f"F顺序列访问时间: {f_col_time:.4f}秒")

本章小结

在这一章中,我们深入学习了:

  • 数组形状的基本概念和属性
  • 数组重塑(reshape)的各种方法
  • 数组展平(flatten vs ravel)的区别
  • 数组转置的多种实现方式
  • 数组拼接的各种方法(hstack, vstack, concatenate, stack等)
  • 数组分割的不同技巧
  • 数组维度的增加和删除
  • 轴的交换和移动操作
  • 实际应用中的形状操作技巧
  • 性能优化的考虑因素

下一步

在下一章中,我们将学习 NumPy 的数学运算和函数,包括基本运算、统计函数、三角函数等。

练习题

  1. 创建一个 3x4 的数组,将其重塑为 2x6,然后转置
  2. 创建三个 2x3 的数组,分别进行水平、垂直和深度拼接
  3. 创建一个 4x6 的数组,将其分割为 2x2 的子数组
  4. 实现一个函数,将图像从 HWC 格式转换为 CHW 格式
  5. 创建一个批处理函数,将多个一维数组组合成二维批次数组

本站内容仅供学习和研究使用。