我有:
test = np.random.randn(40,40,3)
我希望你能翻译:
result = Repeat(test, 10)
所以result
包含重复了10次的数组test
,具有以下形状:
(10, 40, 40, 3)
那么创建一个带有新轴的张量来容纳10个test
的副本。我还希望尽可能高效地完成这项工作。如何使用Numpy实现这一点?
因此,使用Numpy创建一个带有新轴的张量,其中包含10个test
的副本。如何以最佳方式执行此操作?
可以使用np.repeat
方法和np.newaxis
一起使用:
import numpy as np
test = np.random.randn(40,40,3)
result = np.repeat(test[np.newaxis,...], 10, axis=0)
print(result.shape)
>> (10, 40, 40, 3)
stack
函数将数组堆叠10次:def repeat(arr, count):
return np.stack([arr for _ in range(count)], axis=0)
axis=0
实际上是默认值,所以在这里并不是必要的,但我认为它使你在前面添加新轴更清晰。
事实上,这与stack
的示例几乎完全相同:
>>> arrays = [np.random.randn(3, 4) for _ in range(10)]
>>> np.stack(arrays, axis=0).shape
(10, 3, 4)
repeat
或者 tile
更适合。repeat
用于沿着现有轴重复(或展平数组),因此您需要先后使用 reshape
。(这样效率也很高,但我认为不太简单。)tile
(假设您使用类似于数组的 reps
—— 对于标量 reps
,它基本上是 repeat
)用于在所有方向填充多维规格,这比您想要的这种简单情况要复杂得多。broadcast_to
:def repeat(arr, count):
return np.broadcast_to(arr, (count,)+arr.shape)
broadcast_to
实际上并不保证避免复制,只是返回一种只读视图,其中“广播数组的多个元素可能引用单个内存位置”。在实践中,它将避免复制。如果您确实需要出于某种原因保证这一点(或者如果您想要一个可写视图——通常是一个可怕的想法,但也许你有一个好的理由……),您必须下降到as_strided
:def repeat(arr, count):
shape = (count,) + arr.shape
strides = (0,) + arr.strides
return np.lib.stride_tricks.as_strided(
arr, shape=shape, strides=strides, writeable=False)
请注意,对于as_strided
的一半文档警告您可能不应该使用它,而另一半文档警告您绝对不应该将其用于可写视图,因此在使用之前,请确保这是您想要的。
np.broadcast_to(arr, (count,)+arr.shape)
。 - miradulobroadcast_to
基本上是一个便利函数,旨在确保没有人会将as_strided
用于此用例... - abarnertstack
的粉丝,但在这里concatenate
更快。stack
会为列表中的每个参数添加一个维度。将其添加一次,进行列表复制,然后连接起来会更快。 - hpauljconcatenate
沿着现有的轴进行连接,而不是创建一个新的轴。因此,它既需要像 repeat
一样预先或后重塑,又需要像 stack
一样明确地传递 arr 的10个参数。 - abarnert[[arr for _ in range(10)]]
而不是仅传入[arr for _ in range(10)]
以模拟额外的轴,但这样会变慢而不是更快。从一个快速的%timeit
:stack
需要27.3微秒,带有错误答案的concatenate
需要23.6微秒,带有正确答案的concatenate
需要35.6微秒。同时,对于1000倍大小的数组,它们都在17毫秒左右。 - abarnertimport numpy as np
def f_pp_0():
out = np.empty((10, *a.shape), a.dtype)
out[...] = a
return out
def f_pp_1():
out = np.empty((10, *a.shape), a.dtype)
np.copyto(out, a)
return out
def f_oddn():
return np.repeat(a[np.newaxis,...], 10, axis=0)
def f_abar():
return np.stack([a for _ in range(10)], axis=0)
def f_arry():
return np.array(10*[a])
from timeit import timeit
a = np.random.random((40, 40, 3))
for f in list(locals().values()):
if callable(f) and f.__name__.startswith('f_'):
print(f.__name__, timeit(f, number=100000)/100, 'ms')
样例执行:
f_pp_0 0.019641224660445003 ms
f_pp_1 0.019557840081397444 ms
f_oddn 0.01983011547010392 ms
f_abar 0.03257150553865358 ms
f_arry 0.02305851033888757 ms
但是差异很小,例如repeat
几乎没有变慢。
np.repeat
是有效的。否则,请尝试np.tile
。as_strided
可能更有效,但它实际上不会复制。np.repeat(test[None], 10,0)
- hpaulj