如何更高效地根据2D NumPy数组中的索引列表访问行?

4

我有一个2D的Numpy数组 arr。它相当大:arr.shape = (2400, 60000)

我目前正在做以下操作:

  • 随机(有放回地)选择 arr.shape[0] 个索引
  • 访问所选的 arr 索引(按行)
  • 计算逐列平均值并选择最大值
  • 我重复进行 k 次

看起来像这样:

no_rows = arr.shape[0]
indicies = np.array(range(no_rows))
my_vals = []
for k in range(no_samples):
    random_idxs = np.random.choice(indicies, size=no_rows, replace=True)
    my_vals.append(
        arr[random_idxs].mean(axis=0).max()
    )

我的问题是速度非常慢。对于我的arr大小,每次循环需要约3秒钟。由于我想要一个大于1k的样本,我的当前解决方案非常糟糕(1k*~3s -> ~1h)。我已经对其进行了分析,发现基于索引访问行是瓶颈所在。"mean""max"快速处理。np.random.choice也没问题。

你有看到任何可以改进的地方吗?是否有更有效率的方法来访问索引,或者更好的快速解决此问题的方法?

我尝试过的方法:

  • numpy.take (较慢)
  • numpy.ravel :

类似以下的东西:

random_idxs = np.random.choice(sample_idxs, size=sample_size, replace=True) 
test = random_idxs.ravel()[arr.ravel()].reshape(arr.shape)
  • 采用类似现有方法的方式,但不使用循环。我创建了一个三维数组,并通过额外的维度一次性访问行。

你的代码中的 no_samples 是什么意思? - Fallen Apart
no_samples 是一个整数,用于定义样本大小。我希望它大于1k。 - Slaw
2个回答

2

由于高级索引会生成副本,因此程序将在arr[random_idxs]中分配大量内存。

因此,提高效率最简单的方法之一是批处理。

BATCH = 512
max(arr[random_idxs,i:i+BATCH].mean(axis=0).max() for i in range(0,arr.shape[1],BATCH))

谢谢 - 这确实有帮助!我已经使用批处理方法将单次迭代的时间从约3秒减少到约0.79,速度提高了约3.5倍。 我只想补充一点,适当的批处理大小很重要。我运行了几个测试,以下是结果(BATCH,100次迭代的平均时间): (16, 1.13), (32, 0.87), (64, 0.79), (128, 1.2), (256, 1.33), (512, 1.8) 和 (1024, 2.47)。 - Slaw

0

这不是一个通用解决方案,但应该可以让您的特定问题更快。基本上,arr.mean(axis=0).max() 不会改变,那么为什么不从该数组中取随机样本呢?

就像这样:

mean_max = arr.mean(axis=0).max()
my_vals = np.array([np.random.choice(mean_max, size=len(mean_max), replace=True) for i in range(no_samples)])

你甚至可以这样做:my_vals = np.random.choice(mean_max, size=(no_samples, len(mean_max)), replace=True),但我不确定这是否会改变你的统计数据。

不确定是否理解。arr.mean(axis=0).max()会改变 - 这就是重点。我正在选择具有替换功能的随机索引。因此,每次迭代,每个列的平均值应该不同。然后,我选择这些列平均值中的最高值,并将其附加为我的最终列表的数据点。至于你提出的解决方案-它无法运行。您提出的mean_max是单个浮点数。那只是从arr中(其中按列计算均值)获得的最高均值。因此,您尝试从一个可用值中随机选择单个值。 - Slaw

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