# 1. 加载两个数据集
def load_data(path_1, path_0):
# 加载标签为1的数据
with h5py.File(path_1, 'r') as data_1:
X_1 = np.array(data_1['X_all']) # shape: (n, ch, time)
y_1 = np.array(data_1['labelOne']).flatten()
# 加载标签为0的数据
with h5py.File(path_0, 'r') as data_0:
X_0 = np.array(data_0['X_all']) # shape: (n, ch, time)
y_0 = np.array(data_0['labelZero']).flatten()
print(f"原始维度: X_1.shape = {X_1.shape}, X_0.shape = {X_0.shape}")
# 维度变换 -> (样本数, 时间点, 通道)
X_1 = np.transpose(X_1, (0, 2, 1)) # (n, time, ch)
X_0 = np.transpose(X_0, (0, 2, 1))
print(f"转置后维度: X_1.shape = {X_1.shape}, X_0.shape = {X_0.shape}")
# 合并数据
X = np.concatenate([X_1, X_0], axis=0)
y = np.concatenate([y_1, y_0])
return X, y
✅ 函数结构总览(Python 和 MATLAB 的区别)
项目 | Python | MATLAB |
---|---|---|
函数定义 | def 函数名(参数): | function [输出] = 函数名(输入) |
函数结束 | 缩进结束即表示结束(没有end关键字) | 通过 end 明确结束 |
输入输出 | 通过参数传入;返回值用 return | 输入和输出都要显式写在函数头上 |
这段函数功能:
从两个文件中读取数据,合并后返回合并的 X
(特征)和 y
(标签)。
# 1. 加载两个数据集
def load_data(path_1, path_0):
-
def
:define,定义函数 -
load_data
:函数名,“加载数据” -
path_1, path_0
:函数的输入参数,分别表示标签为 1 和标签为 0 的文件路径
# 加载标签为1的数据
with h5py.File(path_1, 'r') as data_1:
-
with ... as ...
:上下文管理器(自动打开并关闭文件,防止资源泄漏) -
h5py.File()
:用h5py
模块打开.mat
文件(这个.mat
文件必须是 v7.3 版本,也就是 基于 HDF5 格式的 .mat 文件。)-
'r'
:read,只读模式
-
-
data_1
:变量名,代表打开的文件对象(里面可以按键访问)
X_1 = np.array(data_1['X_all']) # shape: (n, ch, time)
y_1 = np.array(data_1['labelOne']).flatten()
-
X_1
:标签为1的数据特征-
np.array(...)
:转成 NumPy 数组 -
注意这里读取的维数会发生变化,我的原数据是(time,ch,n)
-
-
data_1['X_all']
:从.h5
文件中读取键名为'X_all'
的内容 -
y_1
:标签-
'labelOne'
:表示标签为1的分类 -
.flatten()
:将原始数据拉平成一维数组(比如(1000,1) 变成 (1000,)
-
Python 在读取过程中到底对数据“做了什么”?
原数据是(time,ch,n ), X_1 # shape: (n, ch, time)
本质原因:维度解释方式不同(没做显式变换)
Python 并没有显式对数据“转换维度”,而是:
-
按 C 语言风格(C-style,行优先)解释数据内存排列
-
而 MATLAB 的
.mat
文件是按 Fortran-style(列优先) 保存的。 -
所以维度变化的根源是:“读取时的内存解释方式不同”,数据在磁盘上是一样的字节顺序,但 Python 解释的维度顺序和 MATLAB 不一样!
举例演示(2 × 3 × 4 小数组)
MATLAB 中创建:
A = reshape(1:24, [2, 3, 4]); size(A) % 显示 (2, 3, 4)
这是:
-
第一维(行):2
-
第二维(列):3
-
第三维(页):4
-
内存顺序是:先变第1维(内存中优先变的是“行”维度(也就是第1维))再第2,再第3。
内存顺序(Fortran-style,列优先):
第1页(第3维 = 1):
列1 列2 列3 1 → 3 → 5 2 4 6
第2页(第3维 = 2):
7 9 11 8 10 12
第3页:
13 15 17 14 16 18
第4页:
19 21 23 20 22 24
这就是 MATLAB 的
A(:,:,1)
到A(:,:,4)
。
✅ 二、Python 中读取
with h5py.File('file.mat', 'r') as f: A = np.array(f['A']) print(A.shape) # (4, 3, 2)
Python 把它当成
(4 页, 3 列, 2 行)
读取,也就是(4, 3, 2)
,换句话说,维度顺序倒过来了。内存按 C-style(行优先)来解释:
也就是说,Python 读取后,数组 A 的排布是这样的(按照原 MATLAB 的内存顺序):
A[0, :, :] = # 第0页(其实是 MATLAB 的第4页) [[19, 20], [21, 22], [23, 24]] A[1, :, :] = # MATLAB 的第3页 [[13, 14], [15, 16], [17, 18]] A[2, :, :] = # MATLAB 的第2页 [[7, 8], [9, 10], [11, 12]] A[3, :, :] = # MATLAB 的第1页 [[1, 2], [3, 4], [5, 6]]
你可以看到,顺序倒了!
# 加载标签为0的数据
with h5py.File(path_0, 'r') as data_0:
X_0 = np.array(data_0['X_all']) # shape: (n, ch, time)
y_0 = np.array(data_0['labelZero']).flatten()
-
同样结构:读取标签为 0 的数据和标签
-
labelZero
:标签为 0 的样本 -
.flatten()
:将原始数据拉平成一维数组(比如(1000,1) 变成 (1000,) -
(1000, 1)
和(1000,)
好像差不多,都是“1000 个数”,但实际上它们的结构是完全不同的,尤其是在 NumPy 和模型训练中很关键。(1000, 1) 的结构:
这是一个二维数组,有 1000 行,1 列,每个元素还嵌套在一个小列表里:
[[1], [2], [3], ... [1000]]
shape 是
(1000, 1)
→ 二维结构。(1000,) 的结构:
这是一个 一维数组,直接就是 1000 个数,排成一条“线”:
[1, 2, 3, ..., 1000]
shape 是
(1000,)
→ 一维结构。重点在于结构维度
-
(1000, 1)
是二维,适合做矩阵运算、广播等; -
(1000,)
是一维,更简洁,很多函数(尤其是模型的标签y
)只接受一维向量作为输入。 -
模型为什么更喜欢
(1000,)
?例如,在训练神经网络时: -
model.fit(X, y)
如果
y
是(1000, 1)
,模型可能认为你有 1000 个样本,每个标签是一个向量,但你只是要给一个标签[1, 0, 1, ...]
,所以一维更清晰。
print(f"原始维度: X_1.shape = {X_1.shape}, X_0.shape = {X_0.shape}")
-
f"..."
:格式化字符串,{}
里能放变量 -
.shape
:查看数组的维度,方便 debug
# 维度变换 -> (样本数, 时间点, 通道)
X_1 = np.transpose(X_1, (0, 2, 1)) # (n, time, ch)
X_0 = np.transpose(X_0, (0, 2, 1))
-
np.transpose(arr, axes)
:交换维度顺序-
原来是
(n, ch, time)
➜ 变成(n, time, ch)
-
(0, 2, 1)
的意思是:新的维度位置 对应旧的维度编号 原来的含义 现在的新顺序含义 第0维 0 样本 n 样本 n 第1维 2 通道 ch 时间 time 第2维 1 时间 time 通道 ch 也就是说:
把原来的(n, ch, time)
→ 变成了(n, time, ch)
,适配模型的输入需求:(batch_size, time_steps, channels)
-
每个样本是一个时间序列(time_steps 个时间点)
-
每个时间点是一个向量(channels 个通道)
-
就是把原来的
(样本数, 通道, 时间)
→ 转换成了(样本数, 时间, 通道)
,便于送入模型。
-
print(f"转置后维度: X_1.shape = {X_1.shape}, X_0.shape = {X_0.shape}")
-
再次打印,确认转置是否成功
# 合并数据
X = np.concatenate([X_1, X_0], axis=0)
y = np.concatenate([y_1, y_0])
-
np.concatenate([A, B], axis=0)
:在第 0 个维度上拼接两个数组(样本数方向) -
所以:把标签为 1 和标签为 0 的样本拼到一起
-
X
:拼接后的数据,y
:拼接后的标签
return X, y
-
return
:返回结果 -
这里返回两个变量:特征
X
和 标签y
def 开头,缩进块里做事,return 返回值就结束。
不用写输入输出名在开头,返回值谁接谁用。