Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python C-连续和Fortran连续数组操作之间的性能_Python_Numpy_Multidimensional Array_Scipy - Fatal编程技术网

Python C-连续和Fortran连续数组操作之间的性能

Python C-连续和Fortran连续数组操作之间的性能,python,numpy,multidimensional-array,scipy,Python,Numpy,Multidimensional Array,Scipy,下面,我比较了处理C连续数组和Fortran连续数组()之间的和运算时的性能。我设置轴=0以确保数字按列相加。我很惊讶Fortran连续数组实际上比它的C对应数组慢。Fortran连续数组不是在列中有连续内存分配,因此更适合按列操作吗 import numpy as np a = np.random.standard_normal((10000, 10000)) c = np.array(a, order='C') f = np.array(a, order='F') 在Jupyter笔记本中

下面,我比较了处理C连续数组和Fortran连续数组()之间的和运算时的性能。我设置轴=0以确保数字按列相加。我很惊讶Fortran连续数组实际上比它的C对应数组慢。Fortran连续数组不是在列中有连续内存分配,因此更适合按列操作吗

import numpy as np
a = np.random.standard_normal((10000, 10000))
c = np.array(a, order='C')
f = np.array(a, order='F')
在Jupyter笔记本中,运行

%timeit c.sum(axis=0)
10 loops, best of 3: 84.6 ms per loop

这是意料之中的。如果你检查一下结果

%timeit f.sum(axis=1)
对于
c
的定时,它也给出了类似的结果。同样地

%timeit c.sum(axis=1)
速度较慢


一些解释:假设您具有以下结构

|1| |6|
|2| |7|
|3| |8|
|4| |9|
|5| |10|
正如Eric提到的,这些操作与
reduce
一起工作。假设我们要求列和。所以,直观的机制并没有发挥作用,以至于每一列都被访问一次、汇总和记录。事实上,相反,每一行都被访问,函数(这里是求和)的执行本质上类似于有两个数组
a,b
并执行

a += b
这是一种非常不正式的方式,可以超隐晦地重复文章中提到的内容。
这需要连续访问行,尽管我们正在执行列和[1,6]+[2,7]+[3,8]。。。因此,实现方向取决于操作,而不是数组

我认为这是在np.sum()的实现中。例如:

import numpy as np

A = np.random.standard_normal((10000,10000))
C = np.array(A, order='C')
F = np.array(A, order='F')
与Ipython进行基准测试:

In [7]: %timeit C.sum(axis=0)
10 loops, best of 3: 101 ms per loop

In [8]: %timeit C.sum(axis=1)
10 loops, best of 3: 149 ms per loop

In [9]: %timeit F.sum(axis=0)
10 loops, best of 3: 149 ms per loop

In [10]: %timeit F.sum(axis=1)
10 loops, best of 3: 102 ms per loop
因此,它的行为与预期完全相反。但让我们尝试一下其他功能:

In [17]: %timeit np.amax(C, axis=0)
1 loop, best of 3: 173 ms per loop

In [18]: %timeit np.amax(C, axis=1)
10 loops, best of 3: 70.4 ms per loop

In [13]: %timeit np.amax(F,axis=0)
10 loops, best of 3: 72 ms per loop

In [14]: %timeit np.amax(F,axis=1)
10 loops, best of 3: 168 ms per loop
当然,是苹果对桔子。但是np.amax()与sum一样沿轴工作,并返回一个向量,每行/每列有一个元素。并表现出人们所期望的

In [25]: C.strides
Out[25]: (80000, 8)

In [26]: F.strides
Out[26]: (8, 80000)
告诉我们数组实际上是按行顺序和列顺序打包的,在这个方向上循环应该快得多。例如,除非总和沿列移动时逐行求和,以提供列总和(轴=0)。但我只是在猜测,没有偷看.pyd里面的意思

编辑:

来自percusse的链接:

通过沿一个轴应用ufunc,将a的尺寸减小一

设a.shape=(N_0,…,N_i,…,N_{M-1})。 然后,reduce(a,axis=i)[k_0,…,k_{i-1},k_{i+1},…,k_{M-1}]=在范围(N_i)上迭代j的结果,累积地将ufunc应用于每个 a[k_0,…,k_{i-1},j,k_{i+1},…,k_{M-1}]

因此,在伪代码中,调用F.sum(axis=0)时:

因此,在计算列和时,它实际上会在行上迭代,在列主顺序下会大大降低速度。这种行为可以解释这种差异


eric的链接为我们提供了实现,因为有人好奇地浏览了大量代码

您正在这样做,但使用Python。。。是否有一些仿真?无法验证这一点。对我来说,
b.sum(axis=0)
是2.51s,
c.sum(axis=0)
是0.14s您使用的
numpy
的哪个版本?
np.add.reduce(x,axis=0)
显示了相同的行为,而
sum
在实现开始时所做的是什么?因此,您是否建议数组的顺序类型不一定与性能相关,我们最好测试每种情况?不,它肯定与性能相关。但是,如果您有一些对性能至关重要的东西,那么自己进行基准测试是一个比拇指法则更好的主意,尤其是对于黑盒算法。使用我们预期的行为作为示例,说明.sum(axis=0)在大型矩阵上的速度要慢几个数量级。丹尼尔在评论中说,他也看到了这种行为。所以它也可能与版本有关。我正在用Python 3.5.2运行Numpy 1.11.1。
In [25]: C.strides
Out[25]: (80000, 8)

In [26]: F.strides
Out[26]: (8, 80000)
for j=cols #axis=0
    for i=rows #axis=1
        sum(j,i)=F(j,i)+sum(j-1,i)