在Numpy 2d数组中移动行的位置
给定数组:在Numpy 2d数组中移动行的位置,numpy,Numpy,给定数组: np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) 如果要将标记1处的行移动到标记3。 输出应为: [[1, 2], [5, 6], [7, 8], [3, 4], [9, 10]] [[1, 2], [9, 10], [3, 4], [5, 6], [7, 8]] 如果我想将标记4处的行移动到标记1。 输出应为: [[1, 2],
np.array([[1, 2],
[3, 4],
[5, 6],
[7, 8],
[9, 10]])
如果要将标记1处的行移动到标记3。
输出应为:
[[1, 2],
[5, 6],
[7, 8],
[3, 4],
[9, 10]]
[[1, 2],
[9, 10],
[3, 4],
[5, 6],
[7, 8]]
如果我想将标记4处的行移动到标记1。
输出应为:
[[1, 2],
[5, 6],
[7, 8],
[3, 4],
[9, 10]]
[[1, 2],
[9, 10],
[3, 4],
[5, 6],
[7, 8]]
执行此移动操作的最快的方法是什么?第一个轴上的tuple()
索引如何
例如:
以及:
分别用于您的预期输出
要从两个索引开始生成索引,可以使用以下方法:
def inner_roll(arr, first, last, axis):
stop = last + 1
indices = list(range(arr.shape[axis]))
indices.insert(first, last)
indices.pop(last + 1)
slicing = tuple(
slice(None) if i != axis else indices
for i, d in enumerate(arr.shape))
return arr[slicing]
对于沿操作轴相对较小的输入(例如问题中的输入),这是相当快的
将其与稍微抛光的版本进行比较,以将其封装在函数中,并使其在任意轴上正常工作
:
import numpy as np
def inner_roll2(arr, first, last, axis):
if first > last:
first, last = last, first
shift = 1
else:
shift = -1
slicing = tuple(
slice(None) if i != axis else slice(first, last + 1)
for i, d in enumerate(arr.shape))
arr[slicing] = np.roll(arr[slicing], shift=shift, axis=axis)
return arr
还有一些时间安排:
funcs = inner_roll, inner_roll2
for n in (5, 50, 500):
for m in (2, 20, 200):
arr = np.arange(n * m).reshape((n, m))
print(f'({n:<3d}, {m:<3d})', end=' ')
for func in funcs:
results = %timeit -o -q func(arr, 1, 2, 0)
print(f'{func.__name__:>12s} {results.best* 1e6:>7.3f} µs', end=' ')
print()
# (5 , 2 ) inner_roll 5.613 µs inner_roll2 15.393 µs
# (5 , 20 ) inner_roll 5.592 µs inner_roll2 15.468 µs
# (5 , 200) inner_roll 5.916 µs inner_roll2 15.815 µs
# (50 , 2 ) inner_roll 10.117 µs inner_roll2 15.517 µs
# (50 , 20 ) inner_roll 10.360 µs inner_roll2 15.505 µs
# (50 , 200) inner_roll 12.067 µs inner_roll2 15.886 µs
# (500, 2 ) inner_roll 55.833 µs inner_roll2 15.409 µs
# (500, 20 ) inner_roll 57.364 µs inner_roll2 15.319 µs
# (500, 200) inner_roll 194.408 µs inner_roll2 15.731 µs
funcs=内部滚动,内部滚动2
对于n in(5,50,500):
对于m in(2,20,200):
arr=np.arange(n*m).重塑(n,m))
打印(f'({n:7.3f}µs',结束=“”)
打印()
#(5,2)内辊5.613µs内辊2 15.393µs
#(5,20)内辊5.592µs内辊2 15.468µs
#(5200)内辊5.916µs内辊2 15.815µs
#(50,2)内辊10.117µs内辊2 15.517µs
#(50,20)内辊10.360µs内辊2 15.505µs
#(50200)内辊12.067µs内辊2 15.886µs
#(500,2)内辊55.833µs内辊2 15.409µs
#(500,20)内辊57.364µs内辊2 15.319µs
#(500200)内辊194.408µs内辊2 15.731µs
这表明internal_roll()
是最快的输入方法。
然而,internal\u roll2()
似乎可以更好地扩展输入大小,即使是适度的输入大小,也比internal\u roll()
更快
请注意,当internal\u roll()
创建一个副本时,internal\u roll2()
在适当的位置工作(修改输入arr
)。可以通过在internal\u roll2()
主体的开头添加arr=arr.copy()
来修改此行为,这会使该功能变慢(当然)然后,它的计时将更受m
(非滚动轴的大小)值的影响
另一方面,如果要执行多个连续的滚动操作,
internal\u roll 2()
计时就会叠加,而对于internal\u roll())
你只需要做一次昂贵的部分。如果你仔细看,如果你想把i
行放在j
位置,那么只有i
和j
之间的行受到影响;外部的行不需要更改。这种更改基本上是一种滚动操作。对于a项,b,c,d,e
,将项目置于i=1
到j=3
意味着b,c,d
将变成c,d,b
,给我们a,c,d,b,e
。根据我是否回答您的问题,移位是-1
或+1
?速度可能取决于必须移动(或上移/下移)的行数。从概念上讲,最简单的方法是使用高级索引创建一个新数组(如@norok2所示)。如果只切换更大数组中的几行,就地更改可能会更快(但您的示例移动了5中的3行和5中的4行)。是的,速度当然与受影响的行数成正比。高级索引访问所有数组元素,这就是为什么当行数增加时它的伸缩性很差。当然。虽然简单地插入正确排列的索引很容易,但您手动计算这些索引;这伸缩性很差。假设您有一个大小相同的数组(50005000),不可能像你写的那样手工写索引(0,2,3,1,4)。相反,您需要编写某种逻辑来创建正确排列的索引,这将消耗相当于长度为5000的数组的内存开销。我认为您的评论应该包含在norok的答案中。但您是对的,我的数组很大,因此我相信您的解决方案是最优的。@Mercury这并没有说明速度.查看对我答案的编辑。
i, j = 1,3
i, j, s = (i, j, -1) if i<j else (j, i, 1)
arr[i:j+1] = np.roll(arr[i:j+1],shift=s,axis=0)