python - 为数百万个条目选择优化循环
问题描述
我有一个 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 秒,有没有一种方法可以让它更快而不涉及重写整个程序以处理集合?
解决方案
至少对于最后一个 for 循环,考虑转换为集合而不是使用数组。这允许您使用set.update()
方法而无需检查是否t
已包含在V
. 这是假设您可以A
以某种方式将 合并到逻辑中。从给定的代码中,我看不到任何对A
.
因此,您可以将其更改为类似V.update(T)
. 然后i
将是len(V)
操作之前和之后的增量。
推荐阅读
- python - 在 Python 中制作可单独迭代的二维数组列表
- javascript - 倒数计时器,setDate 有问题
- string - 用标记值替换 Python 字符串
- angular - 在量角器 - 下拉列表中查找元素
- javascript - 更改导航栏高度时下推页面的内容
- kubernetes - 增加 Kubernetes 内部负载均衡器/入口的 TCP 超时
- mysql - MySQL:如何在同一台服务器上保留一些表的同步副本
- sql - Elasticsearch 无法查询 WKT
- jquery - 在一个打开时关闭所有其他 DIV - 使用单独的关闭按钮
- modal-dialog - AngularDart检测组件内的Keyup事件