首页 > 解决方案 > 为数百万个条目选择优化循环

问题描述

我有一个 python 匿名机制,它依赖于从现有属性生成假数据。

这些属性可在域 D 中访问,域 D 是 16 个集合的数组,每个集合代表每个属性可能的值。属性是['uid', 'trans_id', 'trans_date', 'trans_type', 'operation', 'amount', 'balance', 'k_symbol', 'bank', 'acct_district_id', 'frequency', 'acct_date', 'disp_type', 'cli_district_id', 'gender', 'zip']

有些属性的值很少(gener 是 M 或 F),有些是唯一的(uid)并且可以有 1260000 个不同的值。

假数据是作为域内随机选择的属性的元组生成的。

我必须生成近200 万个元组。

这个的第一个实现是:

def beta_step(I, V, beta, n, m, D):
    r = approx_binomial(m - n, beta)
    print("r = " + str(r))
    i = 0
    while i < r:
        t = []
        for attribute in D:
            a_j = choice(list(attribute))
            t.append(a_j)
        if t not in V + I:
            V.append(t)
            i += 1

每个元组大约需要 0.5 秒。请注意,I 和 V 是现有列表(初始分别为 1200000 和 800000 个元组)

我已经发现我可以通过一劳永逸地将 D 转换为 2D 数组来加快速度,以免在每次运行时都转换列表中的集合

for attribute in D:
            a_j = choice(attribute)
            t.append(a_j)

这让我按元组降低到 0.2 秒。

我还尝试循环更少的次数并一次生成多个元组,如下所示:

def beta_step(I, V, beta, n, m, D):
    D = [list(attr) for attr in D ] #Convert D in 2D list
    r = approx_binomial(m - n, beta)
    print("r = " + str(r))
    i = 0

    NT = 1000 #Number of tuples generated at a time

    while i < r:
        T = [[] for j in range(NT)]

        for attribute in D:
            a_j = choices(attribute,k=min(NT,r-i))
            for j in range(len(a_j)):
                T[j].append(a_j[j])

        for t in T:
            if t not in V + I:
                V.append(t)
                i += 1

但这对于 1000 个元组大约需要 220 秒,所以它并不比以前快。

我已经对不同的部分进行了计时,它似乎是最后一个占用大部分时间的 for 循环(大约 217 秒)。

有什么办法可以加快速度,以免运行 50 小时?

======================= 编辑:我实施了@Larri的建议:

def beta_step(I, V, beta, n, m, D):
    D = [list(attr) for attr in D ] #Convert D in list of lists
    I = set(tuple(t) for t in I)
    V = set(tuple(t) for t in V)
    r = approx_binomial(m - n, beta)
    print("r = " + str(r))
    i = 0

    print('SIZE I', len(I))
    print('SIZE V', len(V))


    NT = 1000 #Number of tuples to generate at each pass

    while i < r:
        T = [[] for j in range(min(NT,r-i))]

        for attribute in D:
            a_j = choices(attribute,k=min(NT,r-i))
            for j in range(len(a_j)):
                T[j].append(a_j[j])

        new_T = set(tuple(t) for t in T)  - I
        size_V_before = len(V)
        V.update(new_T)
        size_V_after = len(V)
        delta_V = size_V_after-size_V_before
        i += delta_V

    return [list(t) for t in V]

现在将元素添加到 V 大约需要 0 秒

总共添加 1680000 个元组需要 91 秒但是,转换回 2d 数组需要 200 秒,有没有一种方法可以让它更快而不涉及重写整个程序以处理集合?

标签: pythonpython-3.xoptimization

解决方案


至少对于最后一个 for 循环,考虑转换为集合而不是使用数组。这允许您使用set.update()方法而无需检查是否t已包含在V. 这是假设您可以A以某种方式将 合并到逻辑中。从给定的代码中,我看不到任何对A.

因此,您可以将其更改为类似V.update(T). 然后i将是len(V)操作之前和之后的增量。


推荐阅读