【问题标题】:How to improve the speed of my selection process, python如何提高我的选择过程的速度,python
【发布时间】:2015-04-28 18:29:11
【问题描述】:

编辑:由于我的代码中的错误,我用我最旧但工作的代码进行了更新

我从数据库中获取了速度记录列表,我想在该列表中找到最大速度。听起来很简单,但我对任何最大速度都有一些要求:

如果最大速度超过一定水平,它必须有超过一定数量的记录才能被识别为最大速度。这种逻辑的原因是我想要正常条件下的最大速度,而不仅仅是一个错误或一次发生。出于同样的原因,我还有一个限制,即速度必须超过一定的限制才能被计算在内。

这是速度数组的示例:

v = [8.0, 1.3, 0.7, 0.8, 0.9, 1.1, 14.9, 14.0, 14.1, 14.2, 14.3, 13.8, 13.9, 13.7, 13.6, 13.5, 13.4, 15.7, 15.8, 15.0, 15.3, 15.4, 15.5, 15.6, 15.2, 12.8, 12.7, 12.6, 8.7, 8.8, 8.6, 9.0, 8.5, 8.4, 8.3, 0.1, 0.0, 16.4, 16.5, 16.7, 16.8, 17.0, 17.1, 17.8, 17.7, 17.6, 17.4, 17.5, 17.3, 17.9, 18.2, 18.3, 18.1, 18.0, 18.4, 18.5, 18.6, 19.0, 19.1, 18.9, 19.2, 19.3, 19.9, 20.1, 19.8, 20.0, 19.7, 19.6, 19.5, 20.2, 20.3, 18.7, 18.8, 17.2, 16.9, 11.5, 11.2, 11.3, 11.4, 7.1, 12.9, 14.4, 13.1, 13.2, 12.5, 12.1, 12.2, 13.0, 0.2, 3.6, 7.4, 4.6, 4.5, 4.3, 4.0, 9.4, 9.6, 9.7, 5.8, 5.7, 7.3, 2.1, 0.4, 0.3, 16.1, 11.9, 12.0, 11.7, 11.8, 10.0, 10.1, 9.8, 15.1, 14.7, 14.8, 10.2, 10.3, 1.2, 9.9, 1.9, 3.4, 14.6, 0.6, 5.1, 5.2, 7.5, 19.4, 10.7, 10.8, 10.9, 0.5, 16.3, 16.2, 16.0, 16.6, 12.4, 11.0, 1.7, 1.6, 2.4, 11.6, 3.9, 3.8, 14.5, 11.1]

这是我找到我定义为真正最大速度的代码:

from collections import Counter
while max(speeds)>30:
    speeds.remove(max(speeds))
nwsp = []
for s in speeds:
    nwsp.append(np.floor(s))
count = Counter(nwsp)
while speeds and max(speeds)>14 and count[np.floor(max(speeds))]<10:
    speeds.remove(max(speeds))
while speeds and max(speeds)<5:
    speeds.remove(max(speeds))
if speeds:
    print max(speeds)
    return max(speeds)
else:
    return False

v 的结果如图所示:19.9

我制作 nwsp 的原因是,如果 f.ex 19.6 只被找到 9 次,对我来说并不重要 - 如果同一个整数内的任何数字,f.ex 19.7 也被找到 3 次,那么19.6 将有效。

如何重写/优化此代码以加快选择过程?我已经删除了 max(speeds),而是对列表进行了排序,并使用速度 [-1] 引用了最大的元素。

很抱歉没有在我的速度中添加任何单位。

【问题讨论】:

  • '虽然速度是列表',这行不正确。假设您正在测试速度是否仍然有成员,正确的方法是“同时速度”。 'speeds is list' 将始终返回 False。
  • 另外,'speeds.remove(len(speeds)-1)' 将从速度中删除任何 len(speeds)-1 的值,而不是在速度 [len(速度)-1]。对不起,如果你知道。
  • 您提供的正确答案是什么? speeds.remove(len(speeds)-1) 也不是 speeds[len(speeds)-1]。将使用您当前的代码
  • @bjornasm,是的,这就是我在本地使用的,您的列表 v 的正确答案是什么?
  • @bjornasm 在你的交互式 python 解释器中,尝试输入 '[1,2,3,4,5] is list' 看看会发生什么,你会得到 False。这种情况仍然需要去

标签: python performance optimization


【解决方案1】:

您的代码很慢,因为您一遍又一遍地调用maxremove,并且每次调用所花费的时间都与列表的长度成正比。任何合理的解决方案都会快得多。

如果您知道False 不可能发生,那么这就足够了:

speeds = [8.0, 1.3, 0.7, 0.8, 0.9, 1.1, 14.9, 14.0, 14.1, 14.2, 14.3, 13.8, 13.9, 13.7, 13.6, 13.5, 13.4, 15.7, 15.8, 15.0, 15.3, 15.4, 15.5, 15.6, 15.2, 12.8, 12.7, 12.6, 8.7, 8.8, 8.6, 9.0, 8.5, 8.4, 8.3, 0.1, 0.0, 16.4, 16.5, 16.7, 16.8, 17.0, 17.1, 17.8, 17.7, 17.6, 17.4, 17.5, 17.3, 17.9, 18.2, 18.3, 18.1, 18.0, 18.4, 18.5, 18.6, 19.0, 19.1, 18.9, 19.2, 19.3, 19.9, 20.1, 19.8, 20.0, 19.7, 19.6, 19.5, 20.2, 20.3, 18.7, 18.8, 17.2, 16.9, 11.5, 11.2, 11.3, 11.4, 7.1, 12.9, 14.4, 13.1, 13.2, 12.5, 12.1, 12.2, 13.0, 0.2, 3.6, 7.4, 4.6, 4.5, 4.3, 4.0, 9.4, 9.6, 9.7, 5.8, 5.7, 7.3, 2.1, 0.4, 0.3, 16.1, 11.9, 12.0, 11.7, 11.8, 10.0, 10.1, 9.8, 15.1, 14.7, 14.8, 10.2, 10.3, 1.2, 9.9, 1.9, 3.4, 14.6, 0.6, 5.1, 5.2, 7.5, 19.4, 10.7, 10.8, 10.9, 0.5, 16.3, 16.2, 16.0, 16.6, 12.4, 11.0, 1.7, 1.6, 2.4, 11.6, 3.9, 3.8, 14.5, 11.1]

from collections import Counter
count = Counter(map(int, speeds))
print max(s for s in speeds
          if 5 <= s <= 30 and (s <= 14 or count[int(s)] >= 10))

如果False 的情况可能发生,这将是一种方法:

speeds = [8.0, 1.3, 0.7, 0.8, 0.9, 1.1, 14.9, 14.0, 14.1, 14.2, 14.3, 13.8, 13.9, 13.7, 13.6, 13.5, 13.4, 15.7, 15.8, 15.0, 15.3, 15.4, 15.5, 15.6, 15.2, 12.8, 12.7, 12.6, 8.7, 8.8, 8.6, 9.0, 8.5, 8.4, 8.3, 0.1, 0.0, 16.4, 16.5, 16.7, 16.8, 17.0, 17.1, 17.8, 17.7, 17.6, 17.4, 17.5, 17.3, 17.9, 18.2, 18.3, 18.1, 18.0, 18.4, 18.5, 18.6, 19.0, 19.1, 18.9, 19.2, 19.3, 19.9, 20.1, 19.8, 20.0, 19.7, 19.6, 19.5, 20.2, 20.3, 18.7, 18.8, 17.2, 16.9, 11.5, 11.2, 11.3, 11.4, 7.1, 12.9, 14.4, 13.1, 13.2, 12.5, 12.1, 12.2, 13.0, 0.2, 3.6, 7.4, 4.6, 4.5, 4.3, 4.0, 9.4, 9.6, 9.7, 5.8, 5.7, 7.3, 2.1, 0.4, 0.3, 16.1, 11.9, 12.0, 11.7, 11.8, 10.0, 10.1, 9.8, 15.1, 14.7, 14.8, 10.2, 10.3, 1.2, 9.9, 1.9, 3.4, 14.6, 0.6, 5.1, 5.2, 7.5, 19.4, 10.7, 10.8, 10.9, 0.5, 16.3, 16.2, 16.0, 16.6, 12.4, 11.0, 1.7, 1.6, 2.4, 11.6, 3.9, 3.8, 14.5, 11.1]

from collections import Counter
count = Counter(map(int, speeds))
valids = [s for s in speeds
         if 5 <= s <= 30 and (s <= 14 or count[int(s)] >= 10)]
print max(valids) if valids else False

或者排序使用next,可以默认你的False

speeds = [8.0, 1.3, 0.7, 0.8, 0.9, 1.1, 14.9, 14.0, 14.1, 14.2, 14.3, 13.8, 13.9, 13.7, 13.6, 13.5, 13.4, 15.7, 15.8, 15.0, 15.3, 15.4, 15.5, 15.6, 15.2, 12.8, 12.7, 12.6, 8.7, 8.8, 8.6, 9.0, 8.5, 8.4, 8.3, 0.1, 0.0, 16.4, 16.5, 16.7, 16.8, 17.0, 17.1, 17.8, 17.7, 17.6, 17.4, 17.5, 17.3, 17.9, 18.2, 18.3, 18.1, 18.0, 18.4, 18.5, 18.6, 19.0, 19.1, 18.9, 19.2, 19.3, 19.9, 20.1, 19.8, 20.0, 19.7, 19.6, 19.5, 20.2, 20.3, 18.7, 18.8, 17.2, 16.9, 11.5, 11.2, 11.3, 11.4, 7.1, 12.9, 14.4, 13.1, 13.2, 12.5, 12.1, 12.2, 13.0, 0.2, 3.6, 7.4, 4.6, 4.5, 4.3, 4.0, 9.4, 9.6, 9.7, 5.8, 5.7, 7.3, 2.1, 0.4, 0.3, 16.1, 11.9, 12.0, 11.7, 11.8, 10.0, 10.1, 9.8, 15.1, 14.7, 14.8, 10.2, 10.3, 1.2, 9.9, 1.9, 3.4, 14.6, 0.6, 5.1, 5.2, 7.5, 19.4, 10.7, 10.8, 10.9, 0.5, 16.3, 16.2, 16.0, 16.6, 12.4, 11.0, 1.7, 1.6, 2.4, 11.6, 3.9, 3.8, 14.5, 11.1]

count = Counter(map(int, speeds))
print next((s for s in reversed(sorted(speeds))
            if 5 <= s <= 30 and (s <= 14 or count[int(s)] >= 10)),
           False)

您也可以使用groupby,而不是Counter

speeds = [8.0, 1.3, 0.7, 0.8, 0.9, 1.1, 14.9, 14.0, 14.1, 14.2, 14.3, 13.8, 13.9, 13.7, 13.6, 13.5, 13.4, 15.7, 15.8, 15.0, 15.3, 15.4, 15.5, 15.6, 15.2, 12.8, 12.7, 12.6, 8.7, 8.8, 8.6, 9.0, 8.5, 8.4, 8.3, 0.1, 0.0, 16.4, 16.5, 16.7, 16.8, 17.0, 17.1, 17.8, 17.7, 17.6, 17.4, 17.5, 17.3, 17.9, 18.2, 18.3, 18.1, 18.0, 18.4, 18.5, 18.6, 19.0, 19.1, 18.9, 19.2, 19.3, 19.9, 20.1, 19.8, 20.0, 19.7, 19.6, 19.5, 20.2, 20.3, 18.7, 18.8, 17.2, 16.9, 11.5, 11.2, 11.3, 11.4, 7.1, 12.9, 14.4, 13.1, 13.2, 12.5, 12.1, 12.2, 13.0, 0.2, 3.6, 7.4, 4.6, 4.5, 4.3, 4.0, 9.4, 9.6, 9.7, 5.8, 5.7, 7.3, 2.1, 0.4, 0.3, 16.1, 11.9, 12.0, 11.7, 11.8, 10.0, 10.1, 9.8, 15.1, 14.7, 14.8, 10.2, 10.3, 1.2, 9.9, 1.9, 3.4, 14.6, 0.6, 5.1, 5.2, 7.5, 19.4, 10.7, 10.8, 10.9, 0.5, 16.3, 16.2, 16.0, 16.6, 12.4, 11.0, 1.7, 1.6, 2.4, 11.6, 3.9, 3.8, 14.5, 11.1]

from itertools import *
groups = (list(group) for _, group in groupby(reversed(sorted(speeds)), int))
print next((s[0] for s in groups
            if 5 <= s[0] <= 30 and (s[0] <= 14 or len(s) >= 10)),
           False)

以防万一所有这些对您来说都很奇怪,这里有一个与您的原件相近的。只需查看从最快到最慢的速度并返回符合要求的第一个:

def f(speeds):
    count = Counter(map(int, speeds))
    for speed in reversed(sorted(speeds)):
        if 5 <= speed <= 30 and (speed <= 14 or count[int(speed)] >= 10):
            return speed
    return False

顺便说一句,你对“真正的最大速度”的定义对我来说似乎很奇怪。只看某个百分位数怎么样?可能是这样的:

print sorted(speeds)[len(speeds) * 9 // 10]

【讨论】:

    【解决方案2】:

    我不确定这是否更快,但它更短,我认为它可以满足您的要求。它使用Counter

    from collections import Counter
    import math
    
    def valid(item):
      speed,count = item
      return speed <= 30 and (speed <= 13 or count >= 10)
    
    speeds = [4,3,1,3,4,5,6,7,14,16,18,19,20,34,5,4,3,2,12,58,14,14,14]
    
    speeds = map(math.floor,speeds)
    counts = Counter(speeds)
    max_valid_speed = max(filter(valid,counts.items()))
    

    结果:max_valid_speed == (12,1)

    【讨论】:

    • 谢谢,还不知道 Counter。
    • 感谢您@Marein 的回答,很抱歉没有为您提供更多信息 - 如果 f.ex 12.3 记录了 9 次,而 12.5 记录了 1 次,我仍然认为 12.5 是最大值速度。
    • 我现在添加了地板来解决这个问题。
    • 我同意你的第一点(返回原始值),但我觉得我的条件是正确的。上面说,一个物品,速度小于等于30才有效,超过13则计数要大于10,这不是要求吗?
    • 除了公认的地板问题外,他们的回报都是一样的。
    【解决方案3】:

    使用您的排序想法,我们可以从列表末尾的小于 30 的数字开始,返回第一个符合条件的数字或返回 False:

    from collections import Counter
    
    def f(speeds):
        # get speeds that satisfy the range
        rev = [speed for speed in speeds if 5 <= speed < 30]
        rev.sort(reverse=True)
        c = Counter((int(v) for v in rev))
        for speed in rev:
            # will hit highest numbers first
            # so return first that matches
            if speed > 14 and c[int(speed)] > 9 or speed < 15:
                return speed
        # we did not find any speed that matched our requirement
        return False
    

    列表 v 的输出:

    In [70]: f(v)
    Out[70]: 19.9
    

    如果不进行排序,您可以使用 dict,这取决于您的数据将决定哪个是最好的,它适用于所有情况,包括空列表:

     def f_dict(speeds):
        d = defaultdict(lambda: defaultdict(lambda: 0, {}))
        for speed in speeds:
            key = int(speed)
            d[key]["count"] += 1
            if speed > d[key]["speed"]:
                d[key]["speed"] = speed
        filt = max(filter(lambda x: (15 <= x[0] < 30 and
                                     x[1]["count"] > 9 or x[0] < 15), d.items()), default=False)
        return filt[1]["speed"] if filt else False
    

    输出:

    In [95]: f_dict(v)
    Out[95]: 19.9
    

    【讨论】:

      猜你喜欢
      • 2016-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      • 2018-05-17
      相关资源
      最近更新 更多