【问题标题】:Retain top-N elements as we loop across all elements在遍历所有元素时保留前 N 个元素
【发布时间】:2016-02-19 12:31:46
【问题描述】:

这就是我想要做的。数据帧上的计算输出给出了一个数字。我使用该数字对不同的数据帧进行排名,并且我需要保留前 N 个(在下面的示例中,选择了前 10 个)。排名是通过将数字与反向排序列表的最后一个数字进行比较来实现的。如果当前数字较大,则弹出列表并将新条目添加到列表中,然后再次反向排序。以下在结构上与我所拥有的相同,并且可以正常工作,尽管速度很慢。我将不胜感激任何提高其速度、效率或 Pythonicness 的建议。

import random
import pandas as pd

def gen_df():
    return random.uniform(0.0, 1.0), pd.DataFrame()

if __name__ == '__main__':
    mylist = []
    for i in range(1000):
        val, df = gen_df()
        if len(mylist) < 10:
            mylist.append((val, df))
        else:
            mylist.sort(reverse=True)
            if mylist[-1][0] < val:
                mylist.pop()
                mylist.append((val, df))

编辑:根据 zondo 的建议减少了一种。

【问题讨论】:

  • 一方面,我认为您不需要每次都对其进行排序。只需在你说mylist.pop() 之前对其进行排序,并在完成后在循环外对其进行排序。
  • 对此我不确定。我正在将当前值与前 10 名中的最低值进行比较。如果没有排序列表,我将需要更多逻辑。
  • 是的,我可以在 else 之后用一个替换这两种类型:

标签: python sorting data-structures


【解决方案1】:

加快速度的方法是将列表替换为大小为 10 的最小堆。将前 10 帧放入堆中。然后,对于每个项目,如果它大于堆上最小的项目,则弹出最小的项目并推送新的项目。

我不是 Python 程序员,所以我将介绍伪代码。

heap = new min-heap
for each item
    if (heap.length < 10)
        heap.push(item)
    else if (item > heap.peek())
        heap.pop(); // remove smallest item
        heap.push(item); // add new item

当然,这假设您可以使用最小堆实现。我怀疑heapq 会成功。

这将比每次插入新项目时对列表进行排序要快得多。

【讨论】:

    【解决方案2】:

    请记住,在 Python 中,列表实际上只是指向它们所包含的内容的指针。因此,即使列表包含一些非常繁重的数据结构(即您示例中的 DataFrames),某些列表操作也可能非常快。您的方法包括制作一个小列表(10 项长)并不断修改它以使其“正确”,因为更多的 DataFrame 被“考虑”用于前 10 名。这对我来说有点不必要。我会列出所有候选者的一个大列表,排序一次,然后取前 10 个。此外,追加比插入慢,所以最好一次分配所有内存。

    我的猜测是,对于大数据集,我在下面列出的方法会更快一些。但无论如何,我觉得它更具可读性。

    def get_top_10_so():
        mylist = []
        for i in range(1000):
            val, df = gen_df()
            if len(mylist) < 10:
                mylist.append((val, df))
            else:
                mylist.sort(reverse=True)
                if mylist[-1][0] < val:
                    mylist.pop()
                    mylist.append((val, df))
        return mylist
    
    def get_top_10_mine():
        mylist = [None] * 1000
        for i in range(1000):
            mylist[i] = gen_df()
        mylist.sort(key=lambda tup: tup[0], reverse=True)
        return mylist[:10]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-10
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 2023-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多