I have these info:
a = array([[ 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 2],
[ 1, 1, 1, 1, 3],
[ 1, 1, 1, 18, 16],
[ 1, 1, 1, 18, 17]], dtype=int16)
b = np.arange(0,50).reshape(5,10)
change_cols = [1,2,5,7,9]
I would like to change every row of b at columns defined by change_cols with the values of a[:,:,-1] to get:
b = array([[ 0, 1, 1, 3, 4, 1, 6, 1, 8, 1],
[10, 2, 1, 13, 14, 1, 16, 1, 18, 1],
[20, 3, 1, 23, 24, 1, 26, 1, 28, 1],
[30, 16, 18, 33, 34, 1, 36, 1, 38, 1],
[40, 17, 18, 43, 44, 1, 46, 1, 48, 1]])
Presently I am doing this:
for n, i in enumerate(change_cols):
b[:,i] = a[:,-(n+1)]
How do I do this in NumPy efficiently w/o using Python's for-loop?
Update:
I tried to compare the time taken to complete the answers by @ogdencave and @U12-forward against python's for-loop_enumerate. Surprisingly, Python3 for-loop+enumerate is fastest. Why is this?
>>> def splice():
b[:, change_cols] = a[:, ::-1]
>>> def splice_arange():
b[:, change_cols] = a[:,-(np.arange(len(change_cols)) + 1)]
>>> def enumerate_for_loop():
for n, i in enumerate(change_cols):
b[:,i] = a[:,-(n+1)]
>>> timeit.timeit('splice()', number=10000, globals=globals())
0.042480306001380086
>>> timeit.timeit('splice_arange()', number=10000, globals=globals())
0.05964866199065
>>> timeit.timeit('enumerate_for_loop()', number=10000, globals=globals())
0.03969518095254898
>>>
I also tried array sizes close to my real scenario. I am surprise that python's for-loop+enumerate approach is the fastest.
>>> a = np.array([ 1, 1, 1, 18, 17]*300).reshape(300,5)
>>> b = np.arange(0,300*200).reshape(300,200)
>>> for i in range(5):
timeit.timeit('splice()', number=10000, globals=globals())
0.04873670096276328
0.04880331002641469
0.055170061998069286
0.04291973798535764
0.031961234053596854
>>> for i in range(5):
timeit.timeit('splice_arange()', number=10000, globals=globals())
0.07321989600313827
0.07536661700578406
0.06798515404807404
0.07559602102264762
0.07348818198079243
>>> for i in range(5):
timeit.timeit('enumerate_for_loop()', number=10000, globals=globals())
0.054252722999081016
0.03883319004671648
0.036229485005605966
0.036062364000827074
0.03962253499776125
for-loop.change_colstoo? I suspect increasing its size would show some interesting results.splice=4.46 µs<enumerate_for_loop=5.16 µs<splice_arange=9.7 µs(python 3.9.2, numpy 1.20.2)