我有一个很大的tsv文件:1.5 GB。我想解析这个文件。我正在使用以下功能:
def readEvalFileAsDictInverse(evalFile):
eval = open(evalFile, "r")
evalIDs = {}
for row in eval:
ids = row.split("\t")
if ids[0] not in evalIDs.keys():
evalIDs[ids[0]] = []
evalIDs[ids[0]].append(ids[1])
eval.close()
return evalIDs
这需要10多个小时,并且仍在工作。我不知道如何加快这一步,以及是否还有其他方法可以解析,例如文件
答案 0 :(得分:3)
这里有几个问题:
if ids[0] not in evalIDs.keys()
测试密钥需要永远,因为keys()
是list
。 .keys()
很少有用。更好的方法是if ids[0] not in evalIDs
,但是,但是... collections.defaultdict
呢?csv
模块?eval
(嗯,看到它有多危险并不是一个真正的问题)我的建议:
import csv, collections
def readEvalFileAsDictInverse(evalFile):
with open(evalFile, "r") as handle:
evalIDs = collections.defaultdict(list)
cr = csv.reader(handle,delimiter='\t')
for ids in cr:
evalIDs[ids[0]].append(ids[1]]
魔术evalIDs[ids[0]].append(ids[1]]
创建一个list
(如果尚不存在)。无论python版本如何,它都可移植且非常快速,并保存了if
我认为使用默认库可能不会更快,但是熊猫解决方案可能会更快。
答案 1 :(得分:2)
一些建议:
使用defaultdict(list)
来代替自己创建内部列表,或者使用dict.setdefault()
来。
dict.setfdefault()
每次都会创建defautvalue,这就是时间燃烧器-defautldict(list)
不会-已优化:
from collections import defaultdict
def readEvalFileAsDictInverse(evalFile):
eval = open(evalFile, "r")
evalIDs = defaultdict(list)
for row in eval:
ids = row.split("\t")
evalIDs[ids[0]].append(ids[1])
eval.close()
如果密钥是有效的文件名,则可能需要调查awk
以获得更高的性能,然后在python中进行此操作。
类似
awk -F $'\t' '{print > $1}' file1
将更快地创建拆分文件,您只需使用以下代码的后半部分从每个文件中读取(假设您的密钥是有效的文件名)即可构建列表。 (属性:here)-您需要使用os.walk
或类似方法来抓取创建的文件。文件中的每一行仍将以制表符分隔,并在前面包含ID
如果键本身不是文件名,请考虑将不同的行存储到不同的文件中,并且仅保留key,filename
的字典。
分割数据后,再次将文件加载为列表:
创建测试文件:
with open ("file.txt","w") as w:
w.write("""
1\ttata\ti
2\tyipp\ti
3\turks\ti
1\tTTtata\ti
2\tYYyipp\ti
3\tUUurks\ti
1\ttttttttata\ti
2\tyyyyyyyipp\ti
3\tuuuuuuurks\ti
""")
代码:
# f.e. https://stackoverflow.com/questions/295135/turn-a-string-into-a-valid-filename
def make_filename(k):
"""In case your keys contain non-filename-characters, make it a valid name"""
return k # assuming k is a valid file name else modify it
evalFile = "file.txt"
files = {}
with open(evalFile, "r") as eval_file:
for line in eval_file:
if not line.strip():
continue
key,value, *rest = line.split("\t") # omit ,*rest if you only have 2 values
fn = files.setdefault(key, make_filename(key))
# this wil open and close files _a lot_ you might want to keep file handles
# instead in your dict - but that depends on the key/data/lines ratio in
# your data - if you have few keys, file handles ought to be better, if
# have many it does not matter
with open(fn,"a") as f:
f.write(value+"\n")
# create your list data from your files:
data = {}
for key,fn in files.items():
with open(fn) as r:
data[key] = [x.strip() for x in r]
print(data)
输出:
# for my data: loaded from files called '1', '2' and '3'
{'1': ['tata', 'TTtata', 'tttttttata'],
'2': ['yipp', 'YYyipp', 'yyyyyyyipp'],
'3': ['urks', 'UUurks', 'uuuuuuurks']}
答案 2 :(得分:1)
evalIDs
更改为collections.defaultdict(list)
。您可以避免使用if
检查其中是否有钥匙。 split(1)
在外部拆分文件,甚至使用读取偏移量在python内部拆分文件。然后使用multiprocessing.pool
并行化加载。 答案 3 :(得分:0)
也许您可以使其更快一些;更改它:
if ids[0] not in evalIDs.keys():
evalIDs[ids[0]] = []
evalIDs[ids[0]].append(ids[1])
到
evalIDs.setdefault(ids[0],[]).append(ids[1])
第一种解决方案在“ evalID”词典中搜索了3次。