Numpy np.ascontiguousarray和np.asarray方法
在本文中,我们将介绍Numpy中的np.ascontiguousarray和np.asarray方法,以及在使用Cython时它们的区别。
阅读更多:Numpy 教程
Numpy数组的内存布局
在使用Numpy中的数组时,我们需要关注它的内存布局。Numpy的数组可以具有不同的内存布局,例如默认的C语言风格(即行优先顺序或者称之为C连续)和Fortran语言风格(即列优先顺序或者称之为Fortran连续)。
对于简单的二维数组,我们可以使用Numpy的flags
属性来查看它的内存布局:
当然,对于高维数组来说,判断内存布局就比较麻烦了,这里我们就不展开了。
为什么需要关注数组的内存布局呢?因为在某些操作中,比如通过指针操作数组的值,或者在Python和C语言之间传递数组时,内存布局就会直接影响到性能。
np.ascontiguousarray和np.asarray方法
现在,让我们来介绍Numpy中的np.ascontiguousarray
和np.asarray
方法。这两个方法都可以将输入的数组转换成一个C连续的Numpy数组,但是它们的行为有所不同。
首先,让我们看看np.asarray
方法:
np.asarray
方法会尝试将输入的变量转换成Numpy数组,如果输入的本来就是一个Numpy数组,那么就会返回它自己。如果不是,那么就会新建一个数组。例如,下面的代码中,输入的a
数组是一个Python内置的二维列表:
经过np.asarray
方法转换后,b
就变成了一个新的Numpy数组,而它的内存布局与输入a
的内存布局无关。
接着,我们再看看np.ascontiguousarray
方法:
np.ascontiguousarray
方法的行为类似于np.asarray
,但是有所不同。当输入的数组本来就是C连续的时候,np.ascontiguousarray
方法会直接返回它本身,而不是新建一个数组。这样做是为了避免不必要的内存分配操作。例如:
在这个例子中,输入的a
本来就是一个C连续的数组。因此,np.ascontiguousarray
方法不需要新建一个数组,而是直接返回a
本身。
在Cython中使用np.ascontiguousarray和np.asarray
最后,让我们看看在Cython中使用np.ascontiguousarray
和np.asarray
有什么区别。
假设我们有以下的Cython代码:
这个代码会遍历输入的数组a
,将它的所有元素相加,并返回结果。然而,由于我们使用了Cython来编写这段代码,它的性能应该比纯Python代码要高很多。
现在,让我们来看看在不同情况下,使用np.asarray
和np.ascontiguousarray
会对性能有何影响。
首先,我们来看看使用np.asarray
的情况:
这个版本的代码,我们使用了np.asarray
方法将输入的数组转换成了一个新的Numpy数组b
。这样做的结果是,我们将Python内置的二维列表转换成了一个Numpy数组,因此这个数组的内存布局与输入a
的内存布局无关。由于Cython默认会对数组进行边界检查(boundschecking),因此在遍历b
的时候,Cython会自动检查每一个访问的元素是否超出了数组的边界。这个过程虽然非常安全,但是会对性能有一定的损耗。
接下来,我们来看看使用np.ascontiguousarray
的情况:
这个版本的代码,我们使用了np.ascontiguousarray
方法将输入的数组转换成了一个新的Numpy数组b
。这样做的结果是,如果输入的数组本来就是C连续的,那么b
就是它本身,否则就新建一个C连续的数组。由于b
是一个C连续的数组,因此Cython在遍历它时不需要进行边界检查。这样做可以大大提高代码的性能,因为边界检查对性能有很大的影响。
接下来,我们再看看两个版本的代码在性能上的差异:
在我的电脑上,运行上面的代码,可以得到一下的结果:
Using np.asarray: 24.963209351977557
Using np.ascontiguousarray: 13.282685144961774
可以看到,使用np.ascontiguousarray
比使用np.asarray
要快了近50%。这说明,在使用Cython时,我们应该尽量使用np.ascontiguousarray
方法来避免不必要的内存分配和边界检查操作。
总结
本文介绍了Numpy中的np.ascontiguousarray
和np.asarray
方法,以及它们在使用Cython时的区别。其中,np.ascontiguousarray
方法将会尝试将输入的数组转换成一个C连续的Numpy数组,并且如果输入的数组本来就是C连续的时候,它会直接返回它本身,而不是新建一个数组。这样做是为了避免不必要的内存分配操作,从而提高代码的性能。
最后,本文介绍了在Cython中使用np.ascontiguousarray
和np.asarray
方法的区别。由于Cython默认会对数组进行边界检查,在使用np.asarray
方法时,由于它会将输入数组转换成一个新的Numpy数组,因此在访问这个新数组时,Cython需要对每一个访问的元素进行边界检查,这样会对性能产生一定的损耗。而使用np.ascontiguousarray
方法时,由于它所返回的数组是C连续的,因此Cython在遍历它时不需要进行边界检查,从而可以大大提高代码的性能。