假设我在python中有这两段代码:
1 --------------------------
import numpy as np
x = np.array([1,2,3,4])
y = x
x = x + np.array([1,1,1,1])
print y
2 --------------------------
import numpy as np
x = np.array([1,2,3,4])
y = x
x += np.array([1,1,1,1])
print y
我认为y
的结果在两个示例中都是相同的,因为y
指向x
而x
成为(2,3,4,5)
,但是它不是
结果为(1,2,3,4) for 1
和(2,3,4,5) for 2
。
经过一些研究后,我发现第一个例子
#-First example---------------------------------------
x = np.array([1,2,3,4]) # create x --> [1,2,3,4]
y = x # made y point to x
# unril now we have x --> [1,2,3,4]
# |
# y
x = x + np.array([1,1,1,1])
# however this operation **create a new array** [2,3,4,5]
# and made x point to it instead of the first one
# so we have y --> [1,2,3,4] and x --> [2,3,4,5]
#-Second example--------------------------------------
x = np.array([1,2,3,4]) # create x --> [1,2,3,4]
y = x # made y point to x
# unril now the same x --> [1,2,3,4]
# |
# y
x += np.array([1,1,1,1])
# this operation **Modify the existing array**
# so the result will be
# unril now the same x --> [2,3,4,5]
# |
# y
您可以在此链接中找到有关此行为的更多信息(不仅适用于此示例)In-place algorithm
我的问题是:意识到这种行为为什么我应该在性能方面使用就地算法? (执行时间更快?内存分配更少?)
编辑:澄清
(+,= +)的例子只是简单地向那些不知道的人解释就地算法..但问题一般是在这种情况下使用就地算法..
另一个更复杂的例子:在一个变量中加载一个CSV文件(只有10万行)然后对结果进行排序,就地算法的想法就是在同一个包含输入的内存空间中产生一个输出连续转换数据直到产生输出? - 这样就无需使用两倍的存储空间 - 一个输入区域和一个大小相等的输出区域(使用最少量的RAM,硬盘......)
答案 0 :(得分:6)
您似乎理解x += 1
和x = x + 1
之间的语义差异。
对于基准测试,您可以在IPython中使用timeit。
定义这些功能后:
import numpy as np
def in_place(n):
x = np.arange(n)
x += 1
def not_in_place(n):
x = np.arange(n)
x = x + 1
def in_place_no_broadcast(n):
x = np.arange(n)
x += np.ones(n, dtype=np.int)
您只需使用%timeit
syntax来比较效果:
%timeit in_place(10**7)
20.3 ms ± 81.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit not_in_place(10**7)
30.4 ms ± 253 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit in_place_no_broadcast(10**7)
35.4 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
not_in_place
比in_place
慢50%。
请注意,broadcasting也有很大的不同:numpy将x += 1
理解为向1
的每个元素添加x
,而无需创建另一个数组。
in_place
应该是首选功能:它更快并且使用更少的内存。但是,如果您在代码中的不同位置使用和改变此对象,则可能会遇到错误。典型的例子是:
x = np.arange(5)
y = [x, x]
y[0][0] = 10
y
# [array([10, 1, 2, 3, 4]), array([10, 1, 2, 3, 4])]
您对就地排序的优势的理解是正确的。在对大型数据集进行排序时,它可以在内存需求方面产生巨大差异。
排序算法还有其他理想的功能(稳定,可接受的最坏情况复杂性......),看起来标准的Python算法(Timsort)有many of them。
Timsort是一种混合算法。它的某些部分是就地的,有些需要额外的内存。它永远不会超过n/2
。