【问题标题】:Optimizing Kadane's Algorithm for numpy为 numpy 优化 Kadane 的算法
【发布时间】:2014-11-13 21:44:58
【问题描述】:

找到最大子数组的标准方法是Kadene's algorithm。如果输入是一个大型numpy数组,有什么比原生python实现更快的吗?

import timeit

setup = '''
import random
import numpy as np

def max_subarray(A):
    max_so_far = max_ending_here = 0
    for x in A:
        max_ending_here = max(0, max_ending_here + x)
        max_so_far      = max(max_so_far, max_ending_here)
    return max_so_far

B = np.random.randint(-100,100,size=100000)
'''

print min(timeit.Timer('max_subarray(B)',setup=setup).repeat(5, 100))

【问题讨论】:

  • 更好是什么意思?快点?您绝对可以比纯 python 实现更快。您可以使用 Cython 进行优化,用纯 C 编写并通过 ctypesCython 包含它,例如
  • @cel 是的,如果我不清楚,对不起。更好 => 更快。由于 numpy 数组已经是一种优化的数据类型(例如固定数据类型、连续数组等),我想知道是否有(numpy)内置操作可以利用。我没有想到 Cython 路线,因为我不熟悉它。
  • 您只是希望它快速执行还是以良好的时间复杂度执行?无论如何,只需在 numpy 中执行 cumsumsort 就会非常快:)
  • @Wolph 我正在寻找真实世界的执行时间,因为 Kadene 已经是 O(N)。 cumsum/sort 组合如何工作?那不需要数组的初始索引在开头吗?如果确实有效,请将时间与发布的答案进行比较,我可以接受!
  • 这种顺序数组更新通常不可能向量化,除非它恰好符合某些内置函数。不过,我认为这里不是这种情况......

标签: python numpy subset subset-sum


【解决方案1】:

在 iPython 笔记本中使用 Cython 进行小测试(因为没有 timeit,似乎不适用于 %%cython 环境:)

原版:

import numpy as np

B = np.random.randint(-100,100,size=100000)

def max_subarray(A):
    max_so_far = max_ending_here = 0
    for x in A:
        max_ending_here = max(0, max_ending_here + x)
        max_so_far      = max(max_so_far, max_ending_here)
    return max_so_far

import time

measurements = np.zeros(100, dtype='float')
for i in range(measurements.size):
    a = time.time()
    max_subarray(B)
    measurements[i] = time.time() - a

print 'non-c:', measurements.min(), measurements.max(), measurements.mean()

Cython 版本:

%%cython

import numpy as np
cimport numpy as np

B = np.random.randint(-100,100,size=100000)

DTYPE = np.int
ctypedef np.int_t DTYPE_t

cdef DTYPE_t c_max_subarray(np.ndarray A):
    # Type checking for safety
    assert A.dtype == DTYPE

    cdef DTYPE_t max_so_far = 0, max_ending_here = 0, x = 0
    for x in A:
        max_ending_here = max(0, max_ending_here + x)
        max_so_far      = max(max_so_far, max_ending_here)
    return max_so_far

import time

measurements = np.zeros(100, dtype='float')
for i in range(measurements.size):
    a = time.time()
    c_max_subarray(B)
    measurements[i] = time.time() - a

print 'Cython:', measurements.min(), measurements.max(), measurements.mean()

结果:

  • 赛通:0.00420188903809 0.00658392906189 0.00474049091339
  • 非 c: 0.0485298633575 0.0644249916077 0.0522959709167

不用太多努力就可以显着提高 :)

【讨论】:

  • 你应该在这里静态输入x。它是循环变量,出现在算术中。我很确定你会获得很大的速度。
  • 我得到:Cython: 0.0273659229279 0.0550830364227 0.0315420007706FastCython: 0.00628685951233 0.0138258934021 0.00742509126663,而 x 保证是 int
  • @cel 对于那些不熟悉 Cython 的人,你对静态类型 x 作为 int 有什么特别的看法?
  • 在 Cython 中,您可以使用 cdef 告诉编译器变量应该具有哪种类型。如果你写cdef int x,那么你告诉编译器它可以预期x总是一个int。这将为您的整个程序提供x 一个固定(静态)类型,并允许编译器加速您的代码。
  • @cel:完全忘记了,我会改变它。只需快 5 倍 :)
猜你喜欢
  • 2015-09-18
  • 2011-11-06
  • 2012-02-20
  • 1970-01-01
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 2021-03-03
  • 2022-08-13
相关资源
最近更新 更多