ChatGPT解决这个技术问题 Extra ChatGPT

反转numpy数组的最有效方法

信不信由你,在分析了我当前的代码之后,numpy 数组还原的重复操作占用了运行时间的一大块。我现在拥有的是常见的基于视图的方法:

reversed_arr = arr[::-1]

有没有其他方法可以更有效地做到这一点,或者这只是我痴迷于不切实际的 numpy 性能的一种错觉?

呃... arr[::-1] 只是返回一个反向视图。它尽可能快,并且不依赖于数组中的项目数,因为它只是改变了步幅。你正在反转的实际上是一个 numpy 数组吗?
是的,确实,arr 是一个 numpy 数组。
嗯......好吧,在我的笔记本电脑上,无论数组的长度如何,它都需要大约 670 纳秒。如果这是你的瓶颈,你可能需要切换语言......我很确定你不会找到一种更快的方法来反转一个 numpy 数组。无论如何,祝你好运!
那么,您是否必须在循环中运行它?在某些情况下,最好创建一个包含数百万项的 numpy 数组,然后对整个数组进行操作。即使您正在执行有限差分法或类似的结果取决于先前结果的方法,您有时也可以这样做。 (有时强调...)无论如何,如果速度是主要目标,fortran 仍然是王道。 f2py 是您的朋友!用另一种语言编写算法的性能关键部分(尤其是在科学计算中)并从 python 调用它通常是值得的。祝你好运!
@berto。它比较慢,因为它是 arr[::-1]: github.com/numpy/numpy/blob/master/numpy/lib/twodim_base.py 的包装器。搜索 def flipud。该函数实际上是四行长。

C
Community

创建 reversed_arr 时,您正在创建原始数组的视图。然后您可以更改原始数组,并且视图将更新以反映更改。

您重新创建视图的频率是否超出了您的需要?你应该能够做这样的事情:

arr = np.array(some_sequence)
reversed_arr = arr[::-1]

do_something(arr)
look_at(reversed_arr)
do_something_else(arr)
look_at(reversed_arr)

我不是 numpy 专家,但这似乎是在 numpy 中做事的最快方法。如果这是您已经在做的事情,我认为您无法改进。

PS 在这里对 numpy 视图进行了很好的讨论:

View onto a numpy array?


创建切片对象然后在许多数组上重用它是否有帮助?
实际上我只是对其进行了测试,并没有看到与在循环之外创建的切片对象有任何区别。 (哦,等等,它的速度要快一些。对于 1000000 循环,可重复 43.4 毫秒与 44.3 毫秒)
look_at 函数应该做什么?
@mrgloom 它应该代表查看数据的任何任务。该示例的重点是显示视图 reversed_arr 在基础数据更改后仍然可用。将新值写入数组不会使视图无效。实际上,您也可以使用视图将新值写入数组。 reversed_arr[0] = 99 将数组中的最后一个元素设置为 99,与 arr[-1] = 99 相同。
N
Nico Schlömer

正如刚才提到的,

a[::-1]

实际上只创建一个视图,所以它是一个恒定时间的操作(因此随着数组的增长不需要更长的时间)。如果您需要数组是连续的(例如,因为您要使用它执行许多向量运算),ascontiguousarray 的速度大约与 flipud/fliplr 一样快:

https://i.stack.imgur.com/QTJga.png

生成绘图的代码:

import numpy
import perfplot


perfplot.show(
    setup=lambda n: numpy.random.randint(0, 1000, n),
    kernels=[
        lambda a: a[::-1],
        lambda a: numpy.ascontiguousarray(a[::-1]),
        lambda a: numpy.fliplr([a])[0],
    ],
    labels=["a[::-1]", "ascontiguousarray(a[::-1])", "fliplr"],
    n_range=[2 ** k for k in range(25)],
    xlabel="len(a)",
)

perfplot 至少需要 Python 3.6,因为它使用 f 字符串(文字字符串插值)
H
Hobo

因为这似乎还没有被标记为已回答...... Thomas Arildsen 的回答应该是正确的:只需使用

np.flipud(your_array) 

如果它是一维数组(列数组)。

随着矩阵做

fliplr(matrix)

如果要反转行,flipud(matrix) 如果要翻转列。无需将一维列数组设为二维行数组(具有一个 None 层的矩阵)然后翻转它。


u
user

np.fliplr() 将数组从左向右翻转。

请注意,对于一维数组,您需要稍微花点心思:

arr1d = np.array(some_sequence)
reversed_arr = np.fliplr([arr1d])[0]

reversed_arr = np.flipud(arr1d) 似乎可以直接工作。
一维数组被视为一列,而不是一行,因此将使用 np.flipud(上下),而不是 fliplr(左右)。
u
user

我将扩展关于 np.fliplr() 的较早答案。这是一些代码,演示了构造一维数组,将其转换为二维数组,翻转它,然后转换回一维数组。 time.clock() 将用于保持时间,以秒为单位。

import time
import numpy as np

start = time.clock()
x = np.array(range(3))
#transform to 2d
x = np.atleast_2d(x)
#flip array
x = np.fliplr(x)
#take first (and only) element
x = x[0]
#print x
end = time.clock()
print end-start

未注释打印语句:

[2 1 0]
0.00203907123594

使用 print 语句注释掉:

5.59799927506e-05

所以,就效率而言,我认为这是体面的。对于那些喜欢在一行中完成的人,这里是那种形式。

np.fliplr(np.atleast_2d(np.array(range(3))))[0]

用这么小的数组来计时是没有用的。如果你想比较一些东西,最好使用一些需要一段时间的东西,比如 3000 甚至更多的元素。
V
Victoria

基于切片符号的类似 np.flip 将是 [::-1,::-1]

a = np.array([[1., 2.], [3., 4.], [5, 6]])
print(a)

out: [[1. 2.]
      [3. 4.]
      [5. 6.]]

b=a[::-1,::-1]
print(b)

out: [[1. 2.]
      [3. 4.]
      [5. 6.]]

J
John Mil.

扩展其他人所说的内容,我将举一个简短的例子。

如果你有一个一维数组......

>>> import numpy as np
>>> x = np.arange(4) # array([0, 1, 2, 3])
>>> x[::-1] # returns a view
Out[1]: 
array([3, 2, 1, 0])

但是,如果您正在使用 2D 数组...

>>> x = np.arange(10).reshape(2, 5)
>>> x
Out[2]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> x[::-1] # returns a view:
Out[3]: array([[5, 6, 7, 8, 9],
               [0, 1, 2, 3, 4]])

这实际上并没有反转矩阵。

应该使用 np.flip 来实际反转元素

>>> np.flip(x)
Out[4]: array([[9, 8, 7, 6, 5],
               [4, 3, 2, 1, 0]])

如果要逐个打印矩阵的元素,请使用 flat 和 Flip

>>> for el in np.flip(x).flat:
>>>     print(el, end = ' ')
9 8 7 6 5 4 3 2 1 0

我认为您也可以使用 x [...,::-1] 来创建多维数组的反向视图,而无需使用 np.flip,如此处所示 stackoverflow.com/questions/7416170/…
T
Taher Khorshidi

为了让它使用负数和长列表,您可以执行以下操作:

b = numpy.flipud(numpy.array(a.split(),float))

Flipud 用于 1d arra 的位置