多个HDF5数据集的原地洗牌

7

我在同一个文件 my_file.h5 中保存了多个 HDF5 数据集。这些数据集具有不同的维度,但是第一维上观测值的数量相同:

features.shape = (1000000, 24, 7, 1)
labels.shape = (1000000)
info.shape = (1000000, 4)

重要的是将信息/标签数据正确连接到每组特征中,因此我希望使用相同的种子对这些数据集进行洗牌。此外,我想在不完全加载它们到内存的情况下对它们进行洗牌。使用numpy和h5py是否可能实现这一点?

3个回答

2
在磁盘上对数组进行洗牌将会非常耗时,因为这意味着你需要在hdf5文件中分配新的数组,然后按不同的顺序复制所有行。如果你想避免一次性将所有数据加载到内存中,可以使用PyTables或h5py迭代行(或使用行块)。
另一种方法是保持数据不变,仅在一个单独的数组中将新的行号映射到旧的行号(由于你的数组大小只有4MB,因此可以将其完全加载到RAM中)。例如,要对一个numpy数组 x 进行洗牌:
x = np.random.rand(5)
idx_map = numpy.arange(x.shape[0])
numpy.random.shuffle(idx_map)

然后你可以使用 高级NumPy索引 来访问你的洗牌数据,
x[idx_map[2]] # equivalent to x_shuffled[2]
x[idx_map]    # equivament to x_shuffled[:], etc.

这也适用于保存在hdf5中的数组。当然,与将洗牌的数组写入磁盘相比,会有一些开销,但根据您的使用情况,它可能足够了。

1
有人刚刚给这两个答案点了踩,我想知道为什么?是因为我们说这件事做不到而让那个人失望了吗?还是那个人有解决方案?评论通常比踩更具信息性。 - hpaulj
1
可能是因为问题指定了“在不完全加载它们到内存中的情况下”。在两个答案中,X必须加载到内存中。 - wassname

1
在numpy中像这样洗牌数组非常简单。创建大的洗牌索引(洗牌np.arange(1000000)),然后索引数组即可。
features = features[I, ...]
labels = labels[I]
info = info[I, :]

这不是一个原地操作。 labels[I]labels 的副本,而不是切片或视图。
另一种选择:
features[I,...] = features

表面上看起来像是原地操作。但我怀疑在C代码中并非如此。它必须进行缓冲,因为I值不能保证唯一。实际上,有一个特殊的ufunc .at方法用于无缓冲操作。

但是看看h5py对于这种“花式索引”的说法:

http://docs.h5py.org/en/latest/high/dataset.html#fancy-indexing

labels[I]选择已实现,但有限制。

List selections may not be empty
Selection coordinates must be given in increasing order
Duplicate selections are ignored
Very long lists (> 1000 elements) may produce poor performance

你的打乱后的 I ,根据定义,不是按照递增顺序排列的。并且它非常大。
此外,我没有看到任何关于在左侧使用这种高级索引的信息,labels[I] = ...

0
import numpy as np
import h5py

data = h5py.File('original.h5py', 'r')

with h5py.File('output.h5py', 'w') as out:
    indexes = np.arange(data['some_dataset_in_original'].shape[0])
    np.random.shuffle(indexes)
    for key in data.keys():
        print(key)
        feed = np.take(data[key], indexes, axis=0)
        out.create_dataset(key, data=feed)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接