【问题标题】:Fastest Way to Sum Individual Columns对各个列求和的最快方法
【发布时间】:2014-09-15 01:57:30
【问题描述】:

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

我正在编写的代码是一个需要 24/7 全天候工作的小型日程生成器。每个班次涵盖两周的时间跨度(有些班次在两周内轮换,但必须保持覆盖要求 - 这就是我必须使用 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 的东西,它会让它比我的例子更快?另外,有没有比我上面使用的两种方法更快的方法?

【问题讨论】:

  • 加一个有趣的问题。

标签: python optimization numpy


【解决方案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

【讨论】:

  • 谢谢!我正在处理的数组通常是 11 或 12 行 14 列。我会试一试这些建议,看看会发生什么
  • 顺便说一下,use the timeit module 对代码进行基准测试。使用time.time() 而不重复运行can produce misleading results。但无论如何,除非您要处理大得多的数组,否则不清楚 NumPy 是否会比普通的 Python 代码更快。
  • 我一定会记得的!再次感谢。
【解决方案2】:

不要太在意速度而是关注可读性和直接使用功能,因为它们已尽可能提供。实现可能会有所不同,但如果你在语义上做正确的事情,从长远来看,你做出了正确的决定。只有在分析代码并确定它是一个代价高昂的瓶颈时,才能以这些事情为代价进行优化。

>>> 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]])

【讨论】:

  • 谢谢!我会试试这个。
【解决方案3】:

可能很大程度上取决于您如何排列数据以及您想用它做什么。没有必要仅仅为了求和而转换为 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 例程更好。一个自制的 cython 函数 sumcols 从 python 调用时会变慢

%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

【讨论】:

    猜你喜欢
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 2021-02-19
    • 2020-03-26
    • 2021-06-01
    • 2023-03-25
    • 2019-10-03
    相关资源
    最近更新 更多