如何将数据从numpy数组复制到另一个


86

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

例如:

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

是否可以不循环地进行?

Answers:


86

我相信

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

将快速制作出深层副本。正如Funsi所提到的,最新版本的numpy也具有该copyto功能。


4
+1。但是numpy.empty不会比numpy.zeros快很多吗?
mg007 2012年

9
@ M.ElSakaa = b仅创建对的新引用ba[:] = b表示“将所有元素设置为a等于b”。区别很重要,因为numpy数组是可变类型。
Brian Hawkins

14
@ mg007我进行了一些测试,结果显示empty()比大约快10%zeros()。令人惊讶的empty_like()是甚至更快。copyto(a,b)比数组语法快a[:] = b。参见gist.github.com/bhawkins/5095558
Brian Hawkins

2
@布莱恩·霍金斯是对的。有关何时使用np.copyto(a, b)以及何时a = b.astype(b.dtype)提高速度的信息,请参见以下答案:stackoverflow.com/a/33672015/3703716
mab

1
@michael_n令我惊讶的empty_like是它的速度如此之快empty,尤其是因为zeros_like它的速度慢于zeros。BTW我只是重新运行我的基准(现在更新),之间的差异copyto(a,b),并a[:] = b似乎已经蒸发。gist.github.com/bhawkins/5095558
Brian Hawkins


19
a = numpy.array(b)

甚至比numpy v1.6之前的建议解决方案还要快,并且还可以复制阵列。但是,由于我没有numpy的最新版本,因此无法针对copyto(a,b)对其进行测试。


这是复制数组的好方法,但是会创建一个新对象。OP需要知道如何快速将值分配给已创建的数组。
布莱恩·霍金斯

15

为了回答您的问题,我试用了一些变体并进行了介绍。

结论:要将数据从numpy数组复制到另一个,请使用内置的numpy函数之一,numpy.array(src)或者numpy.copyto(dst, src)在任何可能的地方。

(但如果dst已分配的内存,请始终选择后者,以重用该内存。请参阅文章末尾的概要分析。)

分析设置

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 1 != s 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)})

结果为Windows 7英特尔i7处理器,CPython的V3.5.0,numpy的v1.10.1。


另外,请参阅配置文件变体的结果,其中在值复制期间已经预先分配了目标内存,这y = np.empty_like(x)是设置的一部分:


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)。在Linux上使用i5-4210U和numpy 1.10.4进行了测试
Marco Sulla

是的,马可,这完全是个人喜好。但要注意的np.copy是更多的宽容:np.copy(False)np.copy(None)还是工作,同时a = None; a.copy()抛出AttributeError: 'NoneType' object has no attribute 'copy'。同样,使用函数而不是方法语法来声明我们希望在此代码行中发生的事情更为精确。
2016年

1
好吧,np.copy(None)没有抛出错误的事实确实是不可思议的。多使用一个理由a.copy():)
Marco Sulla,

1
我刚刚使用Python 2.7.12,NumPy 1.11.2运行了这些基准测试,发现它y[:] = x现在的速度略快于copyto(y, x)gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dc上的
Brian Hawkins

10

您可以轻松使用:

b = 1*a

这是最快的方法,但是也有一些问题。如果您不直接定义dtypeof a,也没有检查dtypeof b,则会遇到麻烦。例如:

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

我希望我能阐明这一点。有时,您只需进行少量操作即可更改数据类型。


1
否。这样做会创建一个新的数组。它等效于b = a.copy()。
Charles Brunet

抱歉,但我不明白你的意思。您创建新数组是什么意思?这里介绍的所有其他方法都具有相同的行为。a = numpy.zeros(len(b))a = numpy.empty(n,dtype=complex)还将创建一个新数组。
2011年

2
假设您有一个= numpy.empty(1000)。现在,您需要填充数据,而无需更改其在内存中的地址。如果执行a [0] = 1,则无需重新创建数组,只需更改数组的内容即可。
Charles Brunet

1
@CharlesBrunet必须在某个时候创建​​数组。这种巧妙的单线只需一次操作即可完成。
heltonbiker 2013年

7

您可以执行许多不同的操作:

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 

1

为什么不使用

a = 0 + b

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.