Python中的算法帮助,查找y/x>;常数

Python中的算法帮助,查找y/x>;常数,python,algorithm,numpy,Python,Algorithm,Numpy,我正在建立一个相当庞大的实时赔率系统,而我现在的瓶颈是实际的计算。我有大量已排序的列表,对于每个列表,我需要找到(y/x)>const的每一对(x,y) 这就是我目前正在做的事情 for f in reversed(xrange(1, len(odds))): found = False for s in xrange(0, f): try: edge = odds[s]/odds[f] except ZeroDivisio

我正在建立一个相当庞大的实时赔率系统,而我现在的瓶颈是实际的计算。我有大量已排序的列表,对于每个列表,我需要找到(y/x)>const的每一对(x,y)

这就是我目前正在做的事情

for f in reversed(xrange(1, len(odds))):
    found = False
    for s in xrange(0, f):
        try:
            edge = odds[s]/odds[f]
        except ZeroDivisionError:
            continue
        if edge > const:
            found = True
            yield odds[f], odds[s]
        else:
            break
    if not found:
        break
只要我确定不再有双鞋,这个计划就停止了。然而,我平均每个周期做40个列表,我迫切需要缩短周期时间。我对使用numpy很好奇,看看than是否能帮助我

每个个人列表的长度小于50

谢谢你的帮助

编辑 这是一个具有结构的示例列表

(_ , odds1, odds2, odds3, _, _) (_ means not used):
[(260, Decimal('1.45'), Decimal('5.5'), Decimal('4'), 0, 2666298), (35549, Decimal('1.62'), Decimal('4.5'), Decimal('3.5'), 0, 2666298), (35551, Decimal('1.666'), Decimal('4.333'), Decimal('3.6'), 0, 2666298), (35552, Decimal('1.6'), Decimal('3.6'), Decimal('3.35'), 0, 2666298), (35553, Decimal('1.6'), Decimal('3.6'), Decimal('3.35'), 0, 2666298), (54453, Decimal('1.65'), Decimal('4.2'), Decimal('3.6'), 0, 2666298), (56234, Decimal('1.571'), Decimal('4.65'), Decimal('3.9'), 0, 2666298), (56911, Decimal('1.7'), Decimal('4.2'), Decimal('3.15'), 0, 2666298)]
我把这个列表分成3个列表,odds1\u列表,odds2\u列表,odds3\u列表,并对它们进行计算。odds1的一个示例:

[Decimal('1.7'), Decimal('1.666'), Decimal('1.65'), Decimal('1.62'), Decimal('1.6'), Decimal('1.6'), Decimal('1.571'), Decimal('1.45')]

然后,我需要识别这个列表中的所有对(x,y),其中(y/x>const)

如果您有一些列表
赔率
,您可以这样做

from itertools import product
list(filter(lambda i: i[0] != 0 and i[1]/i[0] > 2, product(odds,repeat=2)))
比如说

odds = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
产生

[(1.0, 3.0), (1.0, 4.0), (1.0, 5.0), (1.0, 6.0), (1.0, 7.0), (1.0, 8.0), (1.0, 9.0),
 (2.0, 5.0), (2.0, 6.0), (2.0, 7.0), (2.0, 8.0), (2.0, 9.0),
 (3.0, 7.0), (3.0, 8.0), (3.0, 9.0),
 (4.0, 9.0)]

如果您有一些列表
赔率
,您可以这样做

from itertools import product
list(filter(lambda i: i[0] != 0 and i[1]/i[0] > 2, product(odds,repeat=2)))
比如说

odds = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
产生

[(1.0, 3.0), (1.0, 4.0), (1.0, 5.0), (1.0, 6.0), (1.0, 7.0), (1.0, 8.0), (1.0, 9.0),
 (2.0, 5.0), (2.0, 6.0), (2.0, 7.0), (2.0, 8.0), (2.0, 9.0),
 (3.0, 7.0), (3.0, 8.0), (3.0, 9.0),
 (4.0, 9.0)]

如果列表已排序,则对于每个x,您只需在列表中搜索第一次出现的常量*x,以及匹配后的所有项目:

import numpy

odds = numpy.arange(10.)
const = 2.5

for x in odds:
    idx = numpy.searchsorted(odds, const*x, side='right')
    for y in odds[idx:]:
        print (x,y)
跑步给予

(0.0, 1.0)
(0.0, 2.0)
(0.0, 3.0)
(0.0, 4.0)
(0.0, 5.0)
(0.0, 6.0)
(0.0, 7.0)
(0.0, 8.0)
(0.0, 9.0)
(1.0, 3.0)
(1.0, 4.0)
(1.0, 5.0)
(1.0, 6.0)
(1.0, 7.0)
(1.0, 8.0)
(1.0, 9.0)
(2.0, 6.0)
(2.0, 7.0)
(2.0, 8.0)
(2.0, 9.0)
(3.0, 8.0)
(3.0, 9.0)

如果列表已排序,则对于每个x,您只需在列表中搜索第一次出现的常量*x,以及匹配后的所有项目:

import numpy

odds = numpy.arange(10.)
const = 2.5

for x in odds:
    idx = numpy.searchsorted(odds, const*x, side='right')
    for y in odds[idx:]:
        print (x,y)
跑步给予

(0.0, 1.0)
(0.0, 2.0)
(0.0, 3.0)
(0.0, 4.0)
(0.0, 5.0)
(0.0, 6.0)
(0.0, 7.0)
(0.0, 8.0)
(0.0, 9.0)
(1.0, 3.0)
(1.0, 4.0)
(1.0, 5.0)
(1.0, 6.0)
(1.0, 7.0)
(1.0, 8.0)
(1.0, 9.0)
(2.0, 6.0)
(2.0, 7.0)
(2.0, 8.0)
(2.0, 9.0)
(3.0, 8.0)
(3.0, 9.0)

如果我没弄错的话:有一个列表[开始,结束],你想找到所有的索引 其中,列表[y]>常数*列表[x]用于排序后的数字列表中的每个索引x

算法可能是:

Set the index y to the beginning of the list.
For each index x:
     Set limit := constant * list[x]
     Binary search an index y' in the range [y, end) where list[y'] > limit
     If the index y' is in the range [y, end):
         Add all pairs list[x], list[y''] where y'' is in the range [y', end]
            to the result set.
         Set y = y'
     Otherwise:
         No further results exist.

C++中的一个实现(您意外地标记了它):

#包括
#包括
#包括
int main()
{
常数无符号常数=2;
向量v={1,2,3,4,5,6,7,8,9};
自动y=v.开始();
对于(自动x=v.begin();xstd::cout如果我理解正确:有一个列表[开始,结束],你想找到所有的索引y
其中,列表[y]>常数*列表[x]用于排序后的数字列表中的每个索引x

算法可能是:

Set the index y to the beginning of the list.
For each index x:
     Set limit := constant * list[x]
     Binary search an index y' in the range [y, end) where list[y'] > limit
     If the index y' is in the range [y, end):
         Add all pairs list[x], list[y''] where y'' is in the range [y', end]
            to the result set.
         Set y = y'
     Otherwise:
         No further results exist.

C++中的一个实现(您意外地标记了它):

#包括
#包括
#包括
int main()
{
常数无符号常数=2;
向量v={1,2,3,4,5,6,7,8,9};
自动y=v.开始();
对于(自动x=v.begin();xstd::cout这里有一个使用numpy及其广播功能的替代方案:

def find_pairs(odds, const):
    with np.errstate(divide='ignore'):
        pairs = odds[np.column_stack(np.where(odds / odds[:, None] > const))]
    return pairs
理论上,时间复杂度是O(n**2)(其中n是
赔率
的长度),但您说n最多是50,这足够小,以至于理论复杂度可能无关紧要

下面是一个完整的脚本,其中包括一些其他答案(到目前为止):

下面是一个计时比较,使用一个包含50个元素的numpy数组:

In [122]: const = 1.25

In [118]: odds = np.sort(1 + np.random.rand(50))

In [119]: %timeit find_pairs(odds, const)
10000 loops, best of 3: 34.9 µs per loop

In [120]: %timeit list(dursi(odds, const))
10000 loops, best of 3: 150 µs per loop

In [121]: %timeit cyber(odds, const)
1000 loops, best of 3: 541 µs per loop

在这种情况下,
find_pairs
中的矢量化计算与显式python循环相比具有足够的优势,它比其他循环更快。

这里有一个使用numpy及其广播功能的替代方案:

def find_pairs(odds, const):
    with np.errstate(divide='ignore'):
        pairs = odds[np.column_stack(np.where(odds / odds[:, None] > const))]
    return pairs
理论上,时间复杂度是O(n**2)(其中n是
赔率
的长度),但您说n最多是50,这足够小,以至于理论复杂度可能无关紧要

下面是一个完整的脚本,其中包括一些其他答案(到目前为止):

下面是一个计时比较,使用一个包含50个元素的numpy数组:

In [122]: const = 1.25

In [118]: odds = np.sort(1 + np.random.rand(50))

In [119]: %timeit find_pairs(odds, const)
10000 loops, best of 3: 34.9 µs per loop

In [120]: %timeit list(dursi(odds, const))
10000 loops, best of 3: 150 µs per loop

In [121]: %timeit cyber(odds, const)
1000 loops, best of 3: 541 µs per loop


在这种情况下,
find_pairs
中的矢量化计算与显式python循环相比具有足够的优势,它比其他循环更快。

@TheOne autoadded tag,my bad.remove now。一个示例会有所帮助,因为我第一次读错了。Cyber似乎也制造了一些与您的代码不匹配的东西。您打算做什么之后如何处理这些对?输出应该是什么?您的代码似乎没有给出其他人回答的内容。“将该对存储在数据库中”你确定这不是瓶颈吗?你当前的代码已经按照生成的对数的比例及时运行了。@TheOne autoadded tag,my bad。现在删除。一个例子会有所帮助,因为我第一次读错了。Cyber似乎也做了一些与你的代码不匹配的事情。你打算以后如何处理这些对?什么输出不应该是?您的代码似乎没有给出其他人所回答的内容。“将这一对存储在数据库中”您确定这不是瓶颈吗?您当前的代码已按生成的对数成比例运行。这与示例代码的作用不同。不确定哪一个被破坏,因为我似乎无法推断出所需的结果。@Cyber在筛选时,我是否也可以存储数字I[1]/I[0]?这与示例代码的作用不同。由于我似乎无法推断出所需的结果,因此不确定哪一个被破坏。@在筛选时,我是否还可以存储数字I[1]/I[0]?对于给定的x,你希望所有的y都变大。你可以用另一种方法,选择一个y,然后选择所有较小的x。你也可以在增加x的同时不断缩小你正在搜索的列表……啊,我明白了,你得到的是x,y——不是y,x。是的。看起来正确,不是被0除的问题。+1——这是我试图做的,但没有完全正确在任何情况下,为了完成答案(因为OP也在询问算法),您可能还需要注意,numpy所做的是将数组对分,以找到比线性搜索更有效的元素。(O(logn)而不是O(n)).Whoops,needed
side=='right'
to do>而不是>=。如果你不想要x==0项,你可以继续x==0,但形式上y/0大于任何常数,所以看起来它们应该留在.FWIW如果时间仍然是一个瓶颈,你可以播放
searchsorted
numpy.searchsorted(赔率,常数*赔率)
。实际上,您可以通过