最简单的方法来总结单个列

时间:2014-09-13 21:47:16

标签: python optimization numpy

我正在寻找优化我写过的程序,我真的遇到了一些绊脚石。我有很多问题,我不知道从哪里开始,但对于初学者,我会尽量将它简化为一个我似乎无法克服的障碍。

我正在编写的代码是一个小型的日程安排生成器,需要全天候覆盖。每个班次涵盖两周的时间跨度(一些班次轮换两周,但必须保持覆盖要求 - 这就是为什么我必须使用14天)。截至目前,我正在试图找出最快的方法来检查一系列轮班是否会在给定的一天加起来。我一直听说Numpy在这种类型的东西上超级快,但是当我运行以下内容时:

import numpy as np
import time

c_ar = np.array([1,1,1,1,0,0,0,1,1,1,1,0,0,0])
d_ar = np.array([0,0,0,1,1,1,1,0,0,0,1,1,1,1])
e_ar = np.array([0,0,0,1,1,1,1,0,0,0,1,1,1,1])
m_ar = np.array([0,1,1,0,1,1,0,0,1,1,0,1,1,0])
p_ar = np.array([1,1,0,0,0,1,1,1,1,0,0,0,1,1])

t0 = time.time()
x = c_ar[0] + d_ar[0] + e_ar[0] + m_ar[0] + p_ar[0]
t1 = time.time()
print t1-t0

我回来了:

  

2.19345092773e-05

但是,如果我跑:

c = [1,1,1,1,0,0,0,1,1,1,1,0,0,0]
d = [0,0,0,1,1,1,1,0,0,0,1,1,1,1]
e = [0,0,0,1,1,1,1,0,0,0,1,1,1,1]
m = [0,1,1,0,1,1,0,0,1,1,0,1,1,0]
p = [1,1,0,0,0,1,1,1,1,0,0,0,1,1]

t2 = time.time()
y = c[0] + d[0] + e[0] + m[0] + p[0]
t3 = time.time()
print t3-t2

我回来了:

  

1.90734863281e-06

我是否错过了一些关于Numpy会比我的例子更快的内容?还有,比我上面使用的两种方法还有更快的方法吗?

3 个答案:

答案 0 :(得分:1)

将所有数据放入一个NumPy数组,然后调用numpy.sum 一次

arr.sum(axis=0)

NumPy数组并不比普通的Python代码快,因为你所使用的只是逐项访问单个值,如下所示:

c_ar[0] + d_ar[0] + e_ar[0] + m_ar[0] + p_ar[0]

此外,对于数组,这个小的常规Python代码可能比使用NumPy数组更快:

c = [1,1,1,1,0,0,0,1,1,1,1,0,0,0]
d = [0,0,0,1,1,1,1,0,0,0,1,1,1,1]
e = [0,0,0,1,1,1,1,0,0,0,1,1,1,1]
m = [0,1,1,0,1,1,0,0,1,1,0,1,1,0]
p = [1,1,0,0,0,1,1,1,1,0,0,0,1,1]
arr = np.row_stack([c,d,e,m,p])

In [226]: %timeit c[0] + d[0] + e[0] + m[0] + p[0]
10000000 loops, best of 3: 189 ns per loop

In [231]: %timeit arr[:,0].sum()
100000 loops, best of 3: 4.73 µs per loop

In [239]: %timeit [c[i] + d[i] + e[i] + m[i] + p[i] for i in range(len(c))]
100000 loops, best of 3: 3.68 µs per loop

In [240]: %timeit arr.sum(axis=0)
100000 loops, best of 3: 5.04 µs per loop

答案 1 :(得分:1)

不要过于关注速度和可读性,直接使用功能,因为尽可能给予它们。实现可能会有所不同,但如果你在语义上做正确的事情,从长远来看,你做出了正确的决定。如果您对代码进行分析并确定它是一个昂贵的瓶颈,那么只能以这些东西为代价进行优化。

>>> np.array([[1, 1], [1, 1], [1, 1]])
array([[1, 1],
       [1, 1],
       [1, 1]])
>>> np.array([[1,1],[1,1], [1,1]]).sum(axis=0)
array([3, 3])

如果您需要保留维度:

>>> np.array([[1,1],[1,1], [1,1]]).sum(axis=0, keepdims=True)
array([[3, 3]])

您可能想要这样做的一个原因是将总和连接成一行:

>>> arr = np.array([[1,1],[1,1], [1,1]])
>>> np.vstack((arr, arr.sum(axis=0, keepdims=True)))
array([[1, 1],
       [1, 1],
       [1, 1],
       [3, 3]])

答案 2 :(得分:0)

可能很大程度上取决于您如何对数据进行排序以及您希望如何处理数据。转换为numpy数组只是为了总结是没有必要的。使用此设置:

import numpy as np

a = [1,1,1,1,0,0,0,1,1,1,1,0,0,0]
....
l = [0,0,0,1,1,1,1,0,0,0,1,1,1,1]

arr = np.row_stack([a, b, c, d, e, f, g, h, i, j, k, l])

我使用 Python

>>> %timeit [sum(col) for col in zip(a, b, c, d, e, f, g, h, i, j, k, l)]
100000 loops, best of 3: 8.84 µs per loop

<强> numpy的

>>> %timeit arr.sum(0)
100000 loops, best of 3: 6.71 µs per loop

我经历了 Cython 更快地获取小数组的总和,但只有在cython中运行而不是经常从python 调用它时。也就是说,如果你将一堆计算移动到cython中,那么使用一个小的求和程序可能会比使用numpy例程更好。从python

调用时,自制的cython函数sumcols碰巧变慢了
%timeit sumcols(arr)
100000 loops, best of 3: 9.86 µs per loop

请记住,如果你有很长的行,转换的数组可能会更快,导致numpy数组默认为Row-Major Order。但是在这种情况下并没有什么不同。

>>> arr_T = arr.transpose(1, 0).copy()
>>> %timeit arr_T.sum(1)
100000 loops, best of 3: 6.59 µs per loop