python - 应该使用哪个运算符(+ vs +=)来提高性能? (就地与不就地)

标签 python performance in-place

假设我在 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 指向 xx 变成 (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 文件(只有 1000 万行)然后对结果进行排序,就地算法的思想是在包含输入的相同内存空间中产生输出连续转换数据直到产生输出? - 这避免了使用两倍存储空间的需要 - 一个区域用于输入,一个大小相等的区域用于输出(使用最少的 RAM、硬盘...)

最佳答案

x = x + 1 对比 x += 1

性能

看来你理解x += 1x = x + 1 之间的语义差异。

对于基准测试,您可以使用 timeit在 IPython 中。

定义这些函数后:

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_placein_place 慢 50%。

请注意 broadcasting也有很大的不同:numpy 将 x += 1 理解为向 x 的每个元素添加一个 1,而无需创建另一个数组。

警告

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虽然。

关于python - 应该使用哪个运算符(+ vs +=)来提高性能? (就地与不就地),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47307518/

相关文章:

python - Django:从另一个应用程序导入 View

python - 将 numpy 数组设置为切片而无需任何就地操作

python - pandas - 掩码适用于整个数据框但适用于选定的列?

java - 调用函数两次与存储输出并在 Java 中使用它

algorithm - 我发明了一种新的排序算法吗?或者这和快速排序一样吗

python - 如何更改seaborn联合图中文本的位置

python - 迭代 pandas df rows 以根据条件计算新变量

Python/SQLite 按文本日期排序

sql - 对 Service Broker 的性能影响 WAITFOR RECEIVE with no TIMEOUT

performance - 如何评估 Dart 性能?