我有两个阵列a& B'/ P>
a.shape
(5, 4, 3)
array([[[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ],
[ 0.10772717, 0.604584 , 0.41664413]],
[[ 0. , 0. , 0. ],
[ 0. , 0. , 0. ],
[ 0.10772717, 0.604584 , 0.41664413],
[ 0.95879616, 0.85575133, 0.46135877]],
[[ 0. , 0. , 0. ],
[ 0.10772717, 0.604584 , 0.41664413],
[ 0.95879616, 0.85575133, 0.46135877],
[ 0.70442301, 0.74126523, 0.88965603]],
[[ 0.10772717, 0.604584 , 0.41664413],
[ 0.95879616, 0.85575133, 0.46135877],
[ 0.70442301, 0.74126523, 0.88965603],
[ 0.8039435 , 0.62802183, 0.58885027]],
[[ 0.95879616, 0.85575133, 0.46135877],
[ 0.70442301, 0.74126523, 0.88965603],
[ 0.8039435 , 0.62802183, 0.58885027],
[ 0.95848603, 0.72429311, 0.71461332]]])
和b
array([ 0.79212707, 0.66629398, 0.58676553], dtype=float32)
b.shape
(3,)
我想获得数组
ab.shape
(5,5,3)
我做如下 第一
b = b.reshape(1,1,3)
然后
b=np.concatenate((b, b,b, b, b), axis = 0)
和
ab=np.concatenate((a, b), axis = 1)
ab.shape
(5, 5, 3)
我得到了正确的结果,但特别是在步骤
时不太方便b=np.concatenate((b, b,b, b, b), axis = 0)
当我必须多次键入时(真实数据集有很多维度)。有没有更快的方法来达到这个结果?
答案 0 :(得分:4)
只需将b
广播到3D
,然后沿第二轴连接 -
b3D = np.broadcast_to(b,(a.shape[0],1,len(b)))
out = np.concatenate((a,b3D),axis=1)
broadcasting
np.broadcast_to
部分没有实际复制或复制,只是一个复制的视图,然后在下一步中,我们进行连接,即时复制
我们正在将np.repeat
version from @cᴏʟᴅsᴘᴇᴇᴅ's solution与np.broadcast_to
进行比较
在本节中,重点关注性能。基于广播的一个在第二步中执行复制和连接,作为合并命令可以这么说,而np.repeat
版本进行复制,然后在两个单独的步骤中连接。
整体方法的时间安排:
案例#1:a = (500,400,300)
和b = (300,)
In [321]: a = np.random.rand(500,400,300)
In [322]: b = np.random.rand(300)
In [323]: %%timeit
...: b3D = b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
...: r = np.concatenate((a, b3D), axis=1)
10 loops, best of 3: 72.1 ms per loop
In [325]: %%timeit
...: b3D = np.broadcast_to(b,(a.shape[0],1,len(b)))
...: out = np.concatenate((a,b3D),axis=1)
10 loops, best of 3: 72.5 ms per loop
对于较小的输入形状,由于设置广播所需的工作显然更复杂,因此拨打np.broadcast_to
的时间会比np.repeat
稍长,因为时间安排如下:
In [360]: a = np.random.rand(5,4,3)
In [361]: b = np.random.rand(3)
In [366]: %timeit np.broadcast_to(b,(a.shape[0],1,len(b)))
100000 loops, best of 3: 3.12 µs per loop
In [367]: %timeit b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
1000000 loops, best of 3: 957 ns per loop
但是,广播部分将具有与输入的形状无关的恒定时间,即3 u-sec
部分将保持在该标记周围。对应方的时间:b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
取决于输入形状。所以,让我们深入挖掘,看看两种方法的连接步骤如何公平/行为。
深入挖掘
尝试深入挖掘连接部分消耗的程度:
In [353]: a = np.random.rand(500,400,300)
In [354]: b = np.random.rand(300)
In [355]: b3D = np.broadcast_to(b,(a.shape[0],1,len(b)))
In [356]: %timeit np.concatenate((a,b3D),axis=1)
10 loops, best of 3: 72 ms per loop
In [357]: b3D = b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
In [358]: %timeit np.concatenate((a,b3D),axis=1)
10 loops, best of 3: 72 ms per loop
结论:似乎没有太大不同。
现在,让我们尝试一种情况,b
所需的复制数量越大,b
的元素数量就越多。
In [344]: a = np.random.rand(10000, 10, 1000)
In [345]: b = np.random.rand(1000)
In [346]: b3D = np.broadcast_to(b,(a.shape[0],1,len(b)))
In [347]: %timeit np.concatenate((a,b3D),axis=1)
10 loops, best of 3: 130 ms per loop
In [348]: b3D = b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
In [349]: %timeit np.concatenate((a,b3D),axis=1)
10 loops, best of 3: 141 ms per loop
结论:似乎合并的连接+与np.broadcast_to
的复制在这里做得更好。
让我们试试(5,4,3)
形状的原始案例:
In [360]: a = np.random.rand(5,4,3)
In [361]: b = np.random.rand(3)
In [362]: b3D = np.broadcast_to(b,(a.shape[0],1,len(b)))
In [363]: %timeit np.concatenate((a,b3D),axis=1)
1000000 loops, best of 3: 948 ns per loop
In [364]: b3D = b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
In [365]: %timeit np.concatenate((a,b3D),axis=1)
1000000 loops, best of 3: 950 ns per loop
结论:再次,并没有太大的不同。
所以,最后的结论是,如果b
中有很多元素,并且a
的第一个轴也是一个大数字(因为复制数是那个),{ {1}}是一个不错的选择,否则基于np.broadcast_to
的版本可以很好地处理其他情况。
答案 1 :(得分:3)
您可以使用np.repeat
:
r = np.concatenate((a, b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)), axis=1)
这样做,首先重塑您的b
数组,使其与a
的维度相匹配,然后根据a
&#39},根据需要多次重复其值。第一轴:
b3D = b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
array([[[1, 2, 3]],
[[1, 2, 3]],
[[1, 2, 3]],
[[1, 2, 3]],
[[1, 2, 3]]])
b3D.shape
(5, 1, 3)
然后将此中间结果与a
-
r = np.concatenate((a, b3d), axis=0)
r.shape
(5, 5, 3)
这与您当前的答案不同,主要在于重复值不是硬编码的事实(即重复处理)。
如果您需要针对不同数量的维度(而不是3D数组)处理此问题,则需要进行一些更改(主要是如何删除b
的硬编码重塑)。
<强>计时强>
a = np.random.randn(100, 99, 100)
b = np.random.randn(100)
# Tai's answer
%timeit np.insert(a, 4, b, axis=1)
100 loops, best of 3: 3.7 ms per loop
# Divakar's answer
%%timeit
b3D = np.broadcast_to(b,(a.shape[0],1,len(b)))
np.concatenate((a,b3D),axis=1)
100 loops, best of 3: 3.67 ms per loop
# solution in this post
%timeit np.concatenate((a, b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)), axis=1)
100 loops, best of 3: 3.62 ms per loop
这些都是非常有竞争力的解决方案。但请注意,性能取决于您的实际数据,因此请务必先测试一下!
答案 2 :(得分:1)
以下是一些基于cᴏʟᴅsᴘᴇᴇᴅ和Divakar解决方案的简单时间:
%timeit np.concatenate((a, b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)), axis=1)
输出: 最慢的运行时间比最快的运行时长6.44倍。这可能意味着正在缓存中间结果。 100000个循环,最佳3:3.68μs/循环
%timeit np.concatenate((a, np.broadcast_to(b[None,None], (a.shape[0], 1, len(b)))), axis=1)
输出: 最慢的运行速度比最快运行时长4.12倍。这可能意味着正在缓存中间结果。 100000个循环,最佳3:每循环10.7μs
现在,这是基于原始代码的时间:
%timeit original_func(a, b)
输出: 最慢的运行时间比最快的运行时间长4.62倍。这可能意味着正在缓存中间结果。 100000个循环,最佳3:每循环4.69μs
由于问题要求更快的方法来得出相同的结果,我会根据这些问题计算得到cᴏʟᴅsᴘᴇᴇᴅ的解决方案。
答案 3 :(得分:0)
您也可以使用np.insert
。
b_broad = np.expand_dims(b, axis=0) # b_broad.shape = (1, 3)
ab = np.insert(a, 4, b_broad, axis=1)
"""
Because now we are inserting along axis 1
a'shape without axis 1 = (5, 3)
b_broad's shape (1, 3)
can be aligned and broadcast b_broad to (5, 3)
"""
在此示例中,我们沿轴1插入,并将b_broad
放在给定的索引之前,此处为4。换句话说,b_broad
将在轴的长度上占据索引4,并使ab.shape
等于(5, 5, 3)
。
注意,在我们进行插入之前,我们将b
转换为b_broad
,以便安全地实现您想要的正确广播。 b
的维度较小,插入时会有广播。我们可以使用expand_dims
来实现这一目标。
如果a
具有(3, 4, 5)
形状,则如果沿轴1插入,则需要b_broad
形状(3, 1)
以匹配尺寸。这可以通过< / p>
b_broad = np.expand_dims(b, axis=1) # shape = (3, 1)
将b_broad
设置为正确的形状是一种很好的做法,因为您可能拥有a.shape = (3, 4, 3)
,并且您确实需要指定在这种情况下广播的方式!
时间安排
来自OP的数据集:COLDSPEED的答案快了3倍。
def Divakar(): # Divakar's answer
b3D = b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)
r = np.concatenate((a, b3D), axis=1)
# COLDSPEED's result
%timeit np.concatenate((a, b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)), axis=1)
2.95 µs ± 164 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# Divakar's result
%timeit Divakar()
3.03 µs ± 173 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# Mine's
%timeit np.insert(a, 4, b, axis=1)
10.1 µs ± 220 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
数据集2(从COLDSPEED借用时间实验):在这种情况下无法得出结论,因为它们具有几乎相同的均值和标准差。
a = np.random.randn(100, 99, 100)
b = np.random.randn(100)
# COLDSPEED's result
%timeit np.concatenate((a, b.reshape(1, 1, -1).repeat(a.shape[0], axis=0)), axis=1)
2.37 ms ± 194 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# Divakar's
%timeit Divakar()
2.31 ms ± 249 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# Mine's
%timeit np.insert(a, 99, b, axis=1)
2.34 ms ± 154 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
速度取决于数据的大小,形状和体积。如果您关心速度,请在您的数据集上进行测试。