【问题标题】:Concatenate big numpy arrays连接大的numpy数组
【发布时间】:2016-05-20 22:51:48
【问题描述】:

假设我有一些 NumPy 数组 ab,其中 a.shape(N, 5000)b.shape(N, 2500)N 是一些样本,可能会根据我的问题/算法而有所不同 - 但对于 ab,它总是相同的。

现在我想要另一个形状为(N, 7500) 的数组c,它在[0:5000] 中保存a 的值,在[5000:7500] 中保存b 的值。

目前我正在创建一个零填充的缓冲区数组并将值切片到其中:

# ...retrieving a
# ...retrieving b
c = zeros.((N, 7500)).astype(np.float32)

# insert values of a
c[:, 0:5000] = a

# insert values of b
c[:, 5000:7500] = b

# free up memory
del a, b

这是一种快速/高效的(因此是“pythonic”/“numpy'ish”)方式吗?或者是否存在在空间/内存消耗或计算时间方面更好的解决方案

ab 是从其他地方加载并进行预处理的,因此不能以某种方式直接将数据插入缓冲区 c 而不创建 ab

【问题讨论】:

  • 对于像这样的二维数组 hstack 只是 concatenate on axis=1; concatenate 是编译后的代码,但据我了解,它只是做你正在做的事情——分配接收器并复制值。

标签: python arrays numpy concatenation slice


【解决方案1】:

c = np.hstack([a,b]) 会做你想做的事。另见np.concatenate


Timeit 结果

a = np.ones((1000,5000), dtype=np.float64)
b = np.ones((1000,2500), dtype=np.float64)

%timeit c = np.concatenate([a,b], axis=1)
1000 loops, best of 3: 66.4 ms per loop

%timeit c = np.hstack([a,b])
1000 loops, best of 3: 67.3 ms per loop

# Check that it is really the same:
np.testing.assert_array_equal(np.concatenate([a,b], axis=1), np.hstack([a,b]))

所以连接可能会快一点,因为hstack 只是concatenate 周围的一个包装器(不必要的函数调用)

作为参考

%%timeit
c = np.zeros((1000, 7500), dtype=np.float64)

# insert values of a
c[:, 0:5000] = a

# insert values of b
c[:, 5000:7500] = b

1000 loops, best of 3: 69.7 ms per loop

似乎几乎和concatenate 一样快。但这只是因为第一个轴是1000。如果我将第一个轴更改为仅包含 10 元素,则时间完全不同:

a = np.ones((10,5000), dtype=np.float64)
b = np.ones((10,2500), dtype=np.float64)

# concatenate
1000 loops, best of 3: 349 µs per loop
# hstack
1000 loops, best of 3: 406 µs per loop
# your approach
1000 loops, best of 3: 452 µs per loop

【讨论】:

  • 您会添加一个示例和使用连接的性能测试吗?我必须做很多实验才能得到我想要的连接......所以我放弃了它并实现了切片方法^^
  • 我还添加了关于第一个轴上的元素数量如何影响时序的简短讨论。因此,如果您的N 非常高,您可能想要使用您的方法,如果它很小,您可以使用numpy.concatenate
  • 有趣。知道为什么我的方法随着更高的 N 变得更快吗?没想到会这样..
  • 当我将速度与@MikeMüller 的回答中的速度进行比较时,我自己发现了这一点。我没有明确的答案,但这可能只是函数调用的开销。 (必须将大数据传输到函数 - 有时需要付出代价)
  • 实际上,经过进一步调查,这似乎只是统计上的侥幸。对 timeit 进行 1000 次测试的另一项测试表明,您的方法比 concatenate 稍慢。
【解决方案2】:

对于这些大小,只使用hstack 是合理的。

【讨论】:

  • 只是出于好奇:“对于这些尺寸”是什么意思?如果阵列真的很小或更大怎么办? hstack 或 OP 方法是否有替代方案?
  • 您可以创建一个大小合适的空数组c。获取a,部分填充c,并删除a。然后获取b,填写完c,删除b
【解决方案3】:

hstack 更快:

a = np.ones((5, 2500)).astype(np.float32)
b = np.zeros((5, 5000)).astype(np.float32)
n = 5

%%timeit
c = np.zeros((n, 7500)).astype(np.float32)
c[:, :2500] = a
c[:, 2500:] = b
10000 loops, best of 3: 70 µs per loop

%timeit c = np.hstack((a, b))
10000 loops, best of 3: 27 µs per loop

如果您使用小型数组,hstack 会比其他解决方案慢一些。 在内存使用方面,这两种方法应该是相似的。

【讨论】:

  • 您知道 hstack 和切片方法确实存在哪些“绑定”吗?比如一个数组有多小或多大,hstack 会变​​慢或快得多?
猜你喜欢
  • 2015-09-25
  • 2015-08-07
  • 1970-01-01
  • 2016-04-17
  • 2022-01-09
  • 2017-05-27
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
相关资源
最近更新 更多