【发布时间】:2018-07-24 10:03:28
【问题描述】:
假设我有一个数组my_array 和一个奇异值my_val。 (注意my_array 总是排序的)。
my_array = np.array([1, 2, 3, 4, 5])
my_val = 1.5
因为my_val 是1.5,我想把它放在1 和2 之间,给我数组[1, 1.5, 2, 3, 4, 5]。
我的问题是:当my_array 任意增长时,生成有序输出数组的最快方法是什么(即以微秒为单位)?
我最初的想法是将值连接到原始数组然后排序:
arr_out = np.sort(np.concatenate((my_array, np.array([my_val]))))
[ 1. 1.5 2. 3. 4. 5. ]
我知道np.concatenate 很快,但我不确定np.sort 将如何随着my_array 的增长而扩展,即使my_array 始终会被排序。
编辑:
我已经汇总了接受答案时列出的各种方法的时间:
输入:
import timeit
timeit_setup = 'import numpy as np\n' \
'my_array = np.array([i for i in range(1000)], dtype=np.float64)\n' \
'my_val = 1.5'
num_trials = 1000
my_time = timeit.timeit(
'np.sort(np.concatenate((my_array, np.array([my_val]))))',
setup=timeit_setup, number=num_trials
)
pauls_time = timeit.timeit(
'idx = my_array.searchsorted(my_val)\n'
'np.concatenate((my_array[:idx], [my_val], my_array[idx:]))',
setup=timeit_setup, number=num_trials
)
sanchit_time = timeit.timeit(
'np.insert(my_array, my_array.searchsorted(my_val), my_val)',
setup=timeit_setup, number=num_trials
)
print('Times for 1000 repetitions for array of length 1000:')
print("My method took {}s".format(my_time))
print("Paul Panzer's method took {}s".format(pauls_time))
print("Sanchit Anand's method took {}s".format(sanchit_time))
输出:
Times for 1000 repetitions for array of length 1000:
My method took 0.017865657746239747s
Paul Panzer's method took 0.005813951002013821s
Sanchit Anand's method took 0.014003945532323987s
对于长度为 1,000,000 的数组重复 100 次也是如此:
Times for 100 repetitions for array of length 1000000:
My method took 3.1770704101754195s
Paul Panzer's method took 0.3931240139911161s
Sanchit Anand's method took 0.40981490723551417s
【问题讨论】:
-
您可以简单地运行一个实验来查看每种方法如何随着列表的增大而扩展。你期待别人为你做这件事吗?
-
@YilunZhang 我更想知道还有哪些我没有想到的方法。
-
@YilunZhang 那么您将如何识别正确的索引并执行插入?这显然是 OP 正在寻找的方法,他们已经在这个问题上表现出了努力。
-
其实查找索引的速度并不重要,因为插入一个numpy数组需要线性时间,任何搜索索引的提升都可以忽略不计,我们最多只能赢50% ,但对于大型数组来说仍然会(非常)慢。
-
insert创建一个新数组。要么使用连接,要么创建一个空白并复制值。你不能就地增长 ndarray 。它的大小是固定的。
标签: python sorting numpy concatenation