【问题标题】:How to copy data from a numpy array to another如何将数据从numpy数组复制到另一个
【发布时间】:2022-05-24 14:49:09
【问题描述】:

在不修改数组a的地址的情况下,将数据从数组b复制到数组a的最快方法是什么。我需要这个,因为外部库 (PyFFTW) 使用指向我的数组的指针,该指针无法更改。

例如:

a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
  a[i] = b[i]

可以不循环吗?

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    我相信

    a = numpy.empty_like(b)
    a[:] = b
    

    将快速复制值。正如 Funsi 所提到的,最新版本的 numpy 也具有 copyto 函数。

    【讨论】:

    • +1。但是numpy.empty 不会比numpy.zeros 快很多吗?
    • @M.ElSaka a = b 只是创建一个对b 的新引用。 a[:] = b 表示“将a 的所有元素设置为等于b 的元素”。区别很重要,因为 numpy 数组是可变类型。
    • @mg007 我进行了一些测试,结果表明empty()zeros() 快10%。令人惊讶的是empty_like() 甚至更快。 copyto(a,b) 比数组语法 a[:] = b 快。见gist.github.com/bhawkins/5095558
    • @Brian Hawkins 是对的。关于何时使用np.copyto(a, b) 以及何时使用a = b.astype(b.dtype) 来提高速度,请参阅下面的答案:stackoverflow.com/a/33672015/3703716
    • @MarcoSulla b=a.copy() 创建一个新数组。我们需要修改现有对象,而不是创建新对象。 (OP 需要一个恒定的内存地址。)
    【解决方案2】:

    NumPy 1.7 版具有 numpy.copyto 函数,可以满足您的需求:

    numpy.copyto(dst, src)

    将值从一个数组复制到另一个数组,并根据需要进行广播。

    见: https://docs.scipy.org/doc/numpy/reference/generated/numpy.copyto.html

    【讨论】:

    • 这对我不起作用。我得到AttributeError: 'module' object has no attribute 'copyto'
    【解决方案3】:
    a = numpy.array(b)
    

    甚至比 numpy v1.6 之前的建议解决方案更快,并且还制作了数组的副本。但是我无法针对 copyto(a,b) 对其进行测试,因为我没有最新版本的 numpy。

    【讨论】:

    • 这是复制数组的好方法,但它会创建一个新对象。 OP 需要知道如何快速将值分配给已经创建的数组。
    【解决方案4】:

    为了回答您的问题,我使用了一些变体并对其进行了分析。

    结论:将数据从 numpy 数组复制到另一个数组时,请尽可能使用内置 numpy 函数 numpy.array(src)numpy.copyto(dst, src) 之一。

    2022-05 更新:使用 numpy v1.22 和 CPython v3.9 重新测试表明,src.astype(...) 目前在我的系统上几乎始终是最快的。所以,最好运行提供的代码,自己剪断以获得特定设置的数字。

    (但如果dst 的内存已分配,请始终选择numpy.copyto(dst, src),以重用内存。请参阅帖子末尾的分析。)

    分析设置

    import timeit
    import numpy as np
    import pandas as pd
    from IPython.display import display
        
    def profile_this(methods, setup='', niter=10 ** 4, p_globals=None, **kwargs):
        if p_globals is not None:
            print('globals: {0}, tested {1:.0e} times'.format(p_globals, niter))
        timings = np.array([timeit.timeit(method, setup=setup, number=niter,
                                          globals=p_globals, **kwargs) for 
                            method in methods])
        ranking = np.argsort(timings)
        timings = np.array(timings)[ranking]
        methods = np.array(methods)[ranking]
        speedups = np.amax(timings) / timings
    
        # pd.set_option('html', False)
        data = {'time (s)': timings,
                'speedup': ['{:.2f}x'.format(s) if s != 1 else '' for s in speedups],
                'methods': methods}
        data_frame = pd.DataFrame(data, columns=['time (s)', 'speedup', 'methods'])
    
        display(data_frame)
        print()
    

    分析代码

    setup = '''import numpy as np; x = np.random.random(n)'''
    methods = (
        '''y = np.zeros(n, dtype=x.dtype); y[:] = x''',
        '''y = np.zeros_like(x); y[:] = x''',
        '''y = np.empty(n, dtype=x.dtype); y[:] = x''',
        '''y = np.empty_like(x); y[:] = x''',
        '''y = np.copy(x)''',
        '''y = x.astype(x.dtype)''',
        '''y = 1*x''',
        '''y = np.empty_like(x); np.copyto(y, x)''',
        '''y = np.empty_like(x); np.copyto(y, x, casting='no')''',
        '''y = np.empty(n)\nfor i in range(x.size):\n\ty[i] = x[i]'''
    )
    
    for n, it in ((2, 6), (3, 6), (3.8, 6), (4, 6), (5, 5), (6, 4.5)):
        profile_this(methods[:-1:] if n > 2 else methods, setup, 
                     niter=int(10 ** it), p_globals={'n': int(10 ** n)})
    

    结果在 Intel i7 CPU、CPython v3.5.0、numpy v1.10.1 上的 Windows 7。

    globals: {'n': 100}, tested 1e+06 times
    
         time (s) speedup                                            methods
    0    0.386908  33.76x                                    y = np.array(x)
    1    0.496475  26.31x                              y = x.astype(x.dtype)
    2    0.567027  23.03x              y = np.empty_like(x); np.copyto(y, x)
    3    0.666129  19.61x                     y = np.empty_like(x); y[:] = x
    4    0.967086  13.51x                                            y = 1*x
    5    1.067240  12.24x  y = np.empty_like(x); np.copyto(y, x, casting=...
    6    1.235198  10.57x                                     y = np.copy(x)
    7    1.624535   8.04x           y = np.zeros(n, dtype=x.dtype); y[:] = x
    8    1.626120   8.03x           y = np.empty(n, dtype=x.dtype); y[:] = x
    9    3.569372   3.66x                     y = np.zeros_like(x); y[:] = x
    10  13.061154          y = np.empty(n)\nfor i in range(x.size):\n\ty[...
    
    
    globals: {'n': 1000}, tested 1e+06 times
    
       time (s) speedup                                            methods
    0  0.666237   6.10x                              y = x.astype(x.dtype)
    1  0.740594   5.49x              y = np.empty_like(x); np.copyto(y, x)
    2  0.755246   5.39x                                    y = np.array(x)
    3  1.043631   3.90x                     y = np.empty_like(x); y[:] = x
    4  1.398793   2.91x                                            y = 1*x
    5  1.434299   2.84x  y = np.empty_like(x); np.copyto(y, x, casting=...
    6  1.544769   2.63x                                     y = np.copy(x)
    7  1.873119   2.17x           y = np.empty(n, dtype=x.dtype); y[:] = x
    8  2.355593   1.73x           y = np.zeros(n, dtype=x.dtype); y[:] = x
    9  4.067133                             y = np.zeros_like(x); y[:] = x
    
    
    globals: {'n': 6309}, tested 1e+06 times
    
       time (s) speedup                                            methods
    0  2.338428   3.05x                                    y = np.array(x)
    1  2.466636   2.89x                              y = x.astype(x.dtype)
    2  2.561535   2.78x              y = np.empty_like(x); np.copyto(y, x)
    3  2.603601   2.74x                     y = np.empty_like(x); y[:] = x
    4  3.005610   2.37x  y = np.empty_like(x); np.copyto(y, x, casting=...
    5  3.215863   2.22x                                     y = np.copy(x)
    6  3.249763   2.19x                                            y = 1*x
    7  3.661599   1.95x           y = np.empty(n, dtype=x.dtype); y[:] = x
    8  6.344077   1.12x           y = np.zeros(n, dtype=x.dtype); y[:] = x
    9  7.133050                             y = np.zeros_like(x); y[:] = x
    
    
    globals: {'n': 10000}, tested 1e+06 times
    
       time (s) speedup                                            methods
    0  3.421806   2.82x                                    y = np.array(x)
    1  3.569501   2.71x                              y = x.astype(x.dtype)
    2  3.618747   2.67x              y = np.empty_like(x); np.copyto(y, x)
    3  3.708604   2.61x                     y = np.empty_like(x); y[:] = x
    4  4.150505   2.33x  y = np.empty_like(x); np.copyto(y, x, casting=...
    5  4.402126   2.19x                                     y = np.copy(x)
    6  4.917966   1.96x           y = np.empty(n, dtype=x.dtype); y[:] = x
    7  4.941269   1.96x                                            y = 1*x
    8  8.925884   1.08x           y = np.zeros(n, dtype=x.dtype); y[:] = x
    9  9.661437                             y = np.zeros_like(x); y[:] = x
    
    
    globals: {'n': 100000}, tested 1e+05 times
    
        time (s) speedup                                            methods
    0   3.858588   2.63x                              y = x.astype(x.dtype)
    1   3.873989   2.62x                                    y = np.array(x)
    2   3.896584   2.60x              y = np.empty_like(x); np.copyto(y, x)
    3   3.919729   2.58x  y = np.empty_like(x); np.copyto(y, x, casting=...
    4   3.948563   2.57x                     y = np.empty_like(x); y[:] = x
    5   4.000521   2.53x                                     y = np.copy(x)
    6   4.087255   2.48x           y = np.empty(n, dtype=x.dtype); y[:] = x
    7   4.803606   2.11x                                            y = 1*x
    8   6.723291   1.51x                     y = np.zeros_like(x); y[:] = x
    9  10.131983                   y = np.zeros(n, dtype=x.dtype); y[:] = x
    
    
    globals: {'n': 1000000}, tested 3e+04 times
    
         time (s) speedup                                            methods
    0   85.625484   1.24x                     y = np.empty_like(x); y[:] = x
    1   85.693316   1.24x              y = np.empty_like(x); np.copyto(y, x)
    2   85.790064   1.24x  y = np.empty_like(x); np.copyto(y, x, casting=...
    3   86.342230   1.23x           y = np.empty(n, dtype=x.dtype); y[:] = x
    4   86.954862   1.22x           y = np.zeros(n, dtype=x.dtype); y[:] = x
    5   89.503368   1.18x                                    y = np.array(x)
    6   91.986177   1.15x                                            y = 1*x
    7   95.216021   1.11x                                     y = np.copy(x)
    8  100.524358   1.05x                              y = x.astype(x.dtype)
    9  106.045746                             y = np.zeros_like(x); y[:] = x

    此外,请查看在值复制期间目标内存已预分配的分析变体的结果,因为y = np.empty_like(x) 是设置的一部分:

    globals: {'n': 100}, tested 1e+06 times
    
       time (s) speedup                        methods
    0  0.328492   2.33x                np.copyto(y, x)
    1  0.384043   1.99x                y = np.array(x)
    2  0.405529   1.89x                       y[:] = x
    3  0.764625          np.copyto(y, x, casting='no')
    
    
    globals: {'n': 1000}, tested 1e+06 times
    
       time (s) speedup                        methods
    0  0.453094   1.95x                np.copyto(y, x)
    1  0.537594   1.64x                       y[:] = x
    2  0.770695   1.15x                y = np.array(x)
    3  0.884261          np.copyto(y, x, casting='no')
    
    
    globals: {'n': 6309}, tested 1e+06 times
    
       time (s) speedup                        methods
    0  2.125426   1.20x                np.copyto(y, x)
    1  2.182111   1.17x                       y[:] = x
    2  2.364018   1.08x                y = np.array(x)
    3  2.553323          np.copyto(y, x, casting='no')
    
    
    globals: {'n': 10000}, tested 1e+06 times
    
       time (s) speedup                        methods
    0  3.196402   1.13x                np.copyto(y, x)
    1  3.523396   1.02x                       y[:] = x
    2  3.531007   1.02x                y = np.array(x)
    3  3.597598          np.copyto(y, x, casting='no')
    
    
    globals: {'n': 100000}, tested 1e+05 times
    
       time (s) speedup                        methods
    0  3.862123   1.01x                np.copyto(y, x)
    1  3.863693   1.01x                y = np.array(x)
    2  3.873194   1.01x                       y[:] = x
    3  3.909018          np.copyto(y, x, casting='no')

    【讨论】:

    • 另外x.copy()np.array(x) 一样快,我更喜欢这种语法:$ python3 -m timeit -s "import numpy as np; x = np.random.random((100, 100))" "x.copy()" - 100000 loops, best of 3: 4.7 usec per loop。我对np.array(x) 有类似的结果。使用 i5-4210U 和 numpy 1.10.4 在 Linux 上测试
    • 是的,Marco,这是个人品味的问题。但请注意,np.copy 更宽容:np.copy(False)np.copy(None) 仍然有效,而 a = None; a.copy() 抛出 AttributeError: 'NoneType' object has no attribute 'copy'。此外,我们更精确地使用函数而不是方法语法在这行代码中声明我们想要发生的事情。
    • 好吧,np.copy(None) 没有抛出错误的事实真的很不合 Python。更多使用a.copy() 的原因之一:)
    • 我刚刚使用 Python 2.7.12、NumPy 1.11.2 运行了这些基准测试,发现y[:] = x 现在比copyto(y, x) 快一点。代码和输出gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dc
    【解决方案5】:

    你可以轻松使用:

    b = 1*a
    

    这是最快的方式,但也有一些问题。如果您不直接定义adtype 并且不检查bdtype,您可能会遇到麻烦。例如:

    a = np.arange(10)        # dtype = int64
    b = 1*a                  # dtype = int64
    
    a = np.arange(10.)       # dtype = float64
    b = 1*a                  # dtype = float64
    
    a = np.arange(10)        # dtype = int64
    b = 1. * a               # dtype = float64
    

    我希望我能说清楚。有时您只需一点操作即可更改数据类型。

    【讨论】:

    • 没有。这样做会创建一个新数组。相当于 b = a.copy()。
    • 抱歉,我没听懂。创建一个新数组是什么意思?此处介绍的所有其他方法具有相同的行为。 a = numpy.zeros(len(b))a = numpy.empty(n,dtype=complex) 也会创建一个新数组。
    • 假设你有一个 = numpy.empty(1000) 。现在,您需要用数据填充 a,而不更改其在内存中的地址。如果执行 a[0] = 1,则不会重新创建数组,只需更改数组的内容。
    • @CharlesBrunet 必须在某个时候创建​​数组。这种巧妙的单线只需一次操作即可完成所有操作。
    【解决方案6】:

    你可以做很多不同的事情:

    a=np.copy(b)
    a=np.array(b) # Does exactly the same as np.copy
    a[:]=b # a needs to be preallocated
    a=b[np.arange(b.shape[0])]
    a=copy.deepcopy(b)
    

    没用的东西

    a=b
    a=b[:] # This have given my code bugs 
    

    【讨论】:

      【解决方案7】:

      为什么不使用

      a = 0 + b
      

      我认为它类似于以前的乘法,但可能更简单。

      【讨论】:

        猜你喜欢
        • 2017-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-28
        相关资源
        最近更新 更多