python - 使用基本库优化 python 代码
问题描述
我正在尝试在具有 170 万行和 4 个变量的表上使用基本 python 进行非 equi 自连接。数据如下所示:
product position_min position_max count_pos
A.16 167804 167870 20
A.18 167804 167838 15
A.15 167896 167768 18
A.20 238359 238361 33
A.35 167835 167837 8
这是我使用的代码:
import csv
from collections import defaultdict
import sys
import os
list_csv=[]
l=[]
with open(r'product.csv', 'r') as file1:
my_reader1 = csv.reader(file1, delimiter=';')
for row in my_reader1:
list_csv.append(row)
with open(r'product.csv', 'r') as file2:
my_reader2 = csv.reader(file2, delimiter=';')
with open('product_p.csv', "w") as csvfile_write:
ecriture = csv.writer(csvfile_write, delimiter=';',
quotechar='"', quoting=csv.QUOTE_ALL)
for row in my_reader2:
res = defaultdict(list)
for k in range(len(list_csv)):
comp= list_csv[k]
try:
if int(row[1]) >= int(comp[1]) and int(row[2]) <= int(comp[2]) and row[0] != comp[0]:
res[row[0]].append([comp[0],comp[3]])
except:
pass
if bool(res):
for key, value in res.items():
sublists = defaultdict(list)
for sublist in value:
l=[]
sublists[sublist[0]].append(int(sublist[1]))
l.append(str(key) + ";"+ str(min(sublists.keys(), key=(lambda k: sublists[k]))))
ecriture.writerow(l)
我应该在“product_p.csv”文件中得到这个:
'A.18'; 'A.16'
'A.15'; 'A.18'
'A.35'; 'A.18'
代码所做的是两次读取同一个文件,第一次完全读取,并将其转换为列表,第二次逐行读取,即为每个产品(第一个变量)查找它所属的所有产品根据 position_min 和 position_max 的条件,然后通过保留具有最小值的产品只选择一个 count_pos 。
我在原始数据样本上进行了尝试,它可以工作,但是有 170 万行,它运行了几个小时而没有给出任何结果。有没有办法用我们的或更少的循环来做到这一点?任何人都可以帮助使用基本的 python 库来优化它吗?
先感谢您
解决方案
我认为这里需要一种不同的方法,因为将每个产品相互比较总是会给出 O(n^2) 的时间复杂度。
我通过升序position_min
(和降序position_max
,以防万一)对产品列表进行排序,并从上面的答案中反转检查:而不是查看comp
“包含”ref
我做了相反的事情。这样就可以只检查每个产品与更高的产品position_min
,也可以在comp
找到position_min
高于position_max
的产品时立即停止搜索ref
。
为了测试这个解决方案,我生成了一个包含 100 种产品的随机列表,并运行从上面的答案复制的一个函数和一个基于我的建议的函数。后者执行大约 1000 次比较而不是 10000 次,据此,timeit
尽管初始排序会产生开销,但它的速度大约快 4 倍。
代码如下:
##reference function
def f1(basedata):
outd={}
for ref in basedata:
for comp in basedata:
if ref == comp:
continue
elif ref[1] >= comp[1] and ref[2] <= comp[2]:
if not outd.get(ref[0], False) or comp[3] < outd[ref[0]][1]:
outd[ref[0]] = (comp[0], comp[3])
return outd
##optimized(?) function
def f2(basedata):
outd={}
sorteddata = sorted(basedata, key=lambda x:(x[1],-x[2]))
runs = 0
for i,ref in enumerate(sorteddata):
toohigh=False
j=i
while j < len(sorteddata)-1 and not toohigh:
j+=1
runs+=1
comp=sorteddata[j]
if comp[1] > ref[2]:
toohigh=True
elif comp[2] <= ref[2]:
if not outd.get(comp[0], False) or ref[3] < outd[comp[0]][1]:
outd[comp[0]] = (ref[0], ref[3])
print(runs)
return outd
推荐阅读
- google-bigquery - BigQuery:发生内部错误,请求无法完成
- javascript - JavaScript/jQuery 插件:对齐网格
- excel - 如何使用VB在Excel中的图表上绘制花括号
- firebase - 使用 Google Cloud App Engine + Firebase + Cloud Functions 提供 HTML 缓存是一个好习惯吗?
- ios - “pod init”失败并显示“无法找到 Gemfile 或 .bundle/ 目录
- python - 如何使用事件发生时测量的数据迭代地构建过去事件的面板数据集?
- json - 在我获取的 json 数据中,我怎样才能分离出余额?
- r - R中的平方到“对角线”矩阵
- java - IN 表达式中的 JPQL LOWER 函数
- vue.js - Vue Routes 在生产环境中无法正常工作