【问题标题】:Optimization: Return lowest value from array that is greater than (or equal to) `x`优化:从数组中返回大于(或等于)`x` 的最小值
【发布时间】:2018-08-09 22:44:14
【问题描述】:

编辑:我的问题与建议的副本不同,因为我已经有了实现lowest 的方法。我的问题不是如何实现lowest,而是如何优化lowest 运行得更快。

假设我有一个数组a。例如:

import numpy as np
a = np.array([2, 1, 3, 4, 5, 6, 7, 8, 9])

假设我有一个浮点数x。例如:

x = 6.5

我想返回a 中大于或等于x 的最小值。所以在这种情况下...

print lowest(a, x)
>>> 7

我已经尝试了一些函数来代替lowest。例如:

def lowest(a, x):
""" `a` should be a sorted numpy array"""
    return lowest[lowest >= x][0]

def lowest(a, x):
""" `a` should be a sorted `list`, not a numpy array"""
    k = sorted(a + [x])
    return k[k.index(x) + 1]

但是,函数 lowest 仍然是我代码的瓶颈,大约为 90%。

有没有更快的方法来实现函数lowest?

关于我的代码的一些规则:

  • a 可以假定长度为 10
  • 函数lowest 至少运行了100k 次。这可能是一个设计问题,但如果我的问题首先得到更快的实现,我很感兴趣。
  • a 可以在运行这些循环之前进行预处理。 x 会有所不同,但 a 不会。
  • 可以假设a[0] <= x <= a[-1]总是True

【问题讨论】:

  • 您的第一个函数使用了无效的语法。你的第二个执行非常低效的操作。这应该是时间上的 O(n) 和空间上的 O(1),或最多 O(n)。
  • 我刚刚意识到a 已排序。在这种情况下,时间上应该是 O(log n),空间上应该是 O(1)。
  • @MadPhysicist 该数组在我看来没有排序。
  • @miradulo: "a 可以在运行这些循环之前进行预处理。x 会有所不同,但 a 不会。"。这是直接引用。
  • a[a >= x].min(),或者,如果a 已排序,则a[a >= x][0]。

标签: python python-2.7 numpy optimization


【解决方案1】:

与 OP 的(第一个)解决方案和 numpy.searchsorted 相比,这是一个使用查找表的 O(1) 解决方案。这不是 100% 公平的,因为 OP 的解决方案没有矢量化。无论如何,时间安排:

True                  # results equal
True                  # results equal
0.08163515606429428   # lookup
2.1996873939642683    # OP
0.016975965932942927  # numpy.searchsorted

对于这个小列表大小seachsorted 获胜,即使它是 O(log n)。

代码:

import numpy as np

class find_next:
    def __init__(self, a, max_bins=100000):
        self.a = np.sort(a)
        self.low = self.a[0]
        self.high = self.a[-1]
        self.span = self.a[-1] - self.a[0]
        self.damin = np.diff(self.a).min()
        if self.span // self.damin > max_bins:
            raise ValueError('a too unevenly spaced for max_bins')
        self.lut = np.searchsorted(self.a, np.linspace(self.low, self.high,
                                                       max_bins + 1))
        self.no_bins = max_bins
    def f_pp(self, x):
        i = np.array((x-self.low)/self.span * self.no_bins, int)
        return self.a[self.lut[i + (x > self.a[self.lut[i]])]]
    def lowest(self, x):
        return self.a[self.a >= x][0]
    def f_ss(self, x):
        return self.a[self.a.searchsorted(x)]

a = np.array([2, 1, 3, 4, 5, 6, 7, 8, 9])

x = np.random.uniform(1, 9, (10000,))

fn = find_next(a)
sol_pp = fn.f_pp(x)
sol_OP = [fn.lowest(xi) for xi in x]
sol_ss = fn.f_ss(x)

print(np.all(sol_OP == sol_pp))
print(np.all(sol_OP == sol_ss))

from timeit import timeit
kwds = dict(globals=globals(), number=10000)

print(timeit('fn.f_pp(x)', **kwds))
print(timeit('[fn.lowest(xi) for xi in x]', **kwds))
print(timeit('fn.f_ss(x)', **kwds))

【讨论】:

    猜你喜欢
    • 2016-09-30
    • 2018-04-21
    • 1970-01-01
    • 2020-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多