【问题标题】:Is it better to add elements to a set or to convert list a into a set?将元素添加到集合还是将列表 a 转换为集合更好?
【发布时间】:2021-08-13 12:31:22
【问题描述】:

我正在为执行聚合的大数据管道创建逻辑。我需要计算一个字段的唯一值的数量,所以我决定使用set's。

考虑到条目的数量可能很大,我不知道哪种方法会更好地计算唯一元素的数量。

我想到了两种方法:

1.创建一个空的set 并向其中添加每个条目。

myset = set()
for entry in entries:
    myset.add(entry['key'])
uniques = len(myset)

每次新条目到达时,此选项都必须检查该值是否存在于集合中。如果可能值的数量很少,我认为它可能会更快。

2。创建一个列表,将所有条目附加到其中并将其转换为一个集合

mylist = list()
for entry in entries:
    mylist.append(entry['key'])
uniques = len(set(mylist))

此选项只会搜索一次唯一值,尽管在更大的集合中。如果可能值的数量很大(例如:ID 或电子邮件),我认为它可能会更快。


我的假设是否正确?有没有什么方法可以找到不受条件限制的唯一值?

【问题讨论】:

  • 为什么假设你可以timeit
  • 使用集合理解myset = {entry['key'] for entry in entries},让核心开发人员处理优化。如果他们认为在后台使用其他一些数据结构更快,那很好。否则,请选择第一个选项。为什么要为巨大的内存列表浪费空间。
  • 您能否详细说明“此选项只会搜索唯一值一次,尽管在更大的集合中”?为什么会更快?这是否与某种“管道”/“聚合”有关?

标签: python performance set unique


【解决方案1】:

让我们创建一个函数来制作我们的条目列表。

def make_entries(size):
    return [{'key': random.randint(1, size//2)} for _ in range(size)]

我们将使用它来创建不同大小的列表并测试每种方法的速度。

方法1:创建一个空集并添加到它

def add_to_set(entries):
    myset = set()
    for entry in entries:
        myset.add(entry['key'])
    return len(myset)

方法2:创建一个列表,然后用它来创建一个集合

def create_from_list(entries):
    mylist = list()
    for entry in entries:
        mylist.append(entry['key'])
    return len(set(mylist))

方法 2a:使用列表推导式创建列表,然后创建一个集合

def create_from_list_comprehension(entries):
    return len(set([entry['key'] for entry in entries]))

方法 3:使用集合理解(@schwobaseggl 在他们的 comment 中的建议)

def set_comprehension(entries):
    return len({entry['key'] for entry in entries})

接下来,我们可以针对size 的不同值对这些方法中的每一种进行计时。

sizes = [10, 50, 100, 500, 1_000, 5_000, 10_000, 50_000, 100_000]

times = []

for size in sizes:
    times.append([])
    entries = make_entries(size)
    nrepeat = 1000
    times[-1].append(timeit.timeit('add_to_set(entries)', setup='from __main__ import entries, add_to_set', number=nrepeat) / nrepeat)
    times[-1].append(timeit.timeit('create_from_list(entries)', setup='from __main__ import entries, create_from_list', number=nrepeat) / nrepeat)
    times[-1].append(timeit.timeit('create_from_list_comprehension(entries)', setup='from __main__ import entries, create_from_list_comprehension', number=nrepeat) / nrepeat)
    times[-1].append(timeit.timeit('set_comprehension(entries)', setup='from __main__ import entries, set_comprehension', number=nrepeat) / nrepeat)

我在我的 Win10 笔记本电脑上使用 Python 3.7.7 运行了这个,print(sys.version) 给出了

3.7.7 (tags/v3.7.7:d7c567b08f, Mar 10 2020, 10:41:24) [MSC v.1900 64 bit (AMD64)]

现在,如果我们绘制times,我们会发现使用集合推导始终比所有其他方法更快。

在您提出的两种方法之间,直接添加到集合通常比创建一个列表然后从该列表中创建一个集合要快,但速度并不快:平均大约快 1.2 倍。


如果你有兴趣,这些是我得到的times 的号码。列对应不同的方法,行对应不同的大小。

times = [[1.91180001e-06, 2.25380005e-06, 1.43129996e-06, 7.10900058e-07],
       [4.31230001e-06, 6.94569992e-06, 3.65169998e-06, 2.49419990e-06],
       [1.56470999e-05, 1.50408000e-05, 8.06160003e-06, 5.67660003e-06],
       [6.51685999e-05, 7.41121001e-05, 6.79391000e-05, 4.49675000e-05],
       [1.40047500e-04, 1.70246000e-04, 9.80658000e-05, 6.99476000e-05],
       [8.01188900e-04, 1.00142830e-03, 4.92695100e-04, 5.36500400e-04],
       [1.35429690e-03, 1.53512830e-03, 8.99595700e-04, 8.74221300e-04],
       [8.91747430e-03, 1.10454779e-02, 8.46084390e-03, 7.77944500e-03],
       [1.97166152e-02, 1.95640820e-02, 1.17698472e-02, 1.20813099e-02]]

【讨论】:

    猜你喜欢
    • 2013-09-19
    • 2013-12-16
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多