alv*_*vas 6 python csv performance dictionary memory-efficient
从如何从两个制表符分隔的文件中获取枢轴线?,有一种使用 unix 命令从两个文件中透视行的快速方法。
如果我们有两对文件:
f1a
和 f1b
f2a
和 f2b
目标是提供一个 3 列制表符分隔的文件,其中包括:
f1a / f2a
文件中同时出现在f1a
和中的行在哪里f1b
:
我尝试了以下可行的方法,但如果文件非常大,则将需要大量内存来存储f1
和f2
字典。例如具有数十亿行的文件。
import sys
from tqdm import tqdm
f1a, f1b, f2a, f2b = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
# Read first pair of file into memory.
with open(f1a) as fin_f1a, open(f1a) as fin_f1b:
f1 = {s.strip().replace('\t', ' ') :t.strip().replace('\t', ' ') for s, t in tqdm(zip(fin_f1a, fin_f1b))}
with open(s2) as fin_f2a, open(t2) as fin_f2b:
f2 = {s.strip().replace('\t', ' ') :t.strip().replace('\t', ' ') for s, t in tqdm(zip(fin_f2a, fin_f2b))}
with open('pivoted.tsv', 'w') as fout:
for s in tqdm(f1.keys() & f2.keys()):
print('\t'.join([s, f1[s], f2[s]]), end='\n', file=fout)
Run Code Online (Sandbox Code Playgroud)
有没有更快/更好/更容易的方法来在 Python 中实现相同的 3 列制表符分隔文件?是否有库可以对大文件有效地执行此类操作?
使用turicreate.SFrame
,我还可以这样做:
from turicreate import SFrame
f1a, f1b, f2a, f2b = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
sf1a = SFrame.read_csv(f1a, delimited='\0', header=False)
sf1b = SFrame.read_csv(f1b, delimited='\0', header=False)
sf2a = SFrame.read_csv(f2a, delimited='\0', header=False)
sf2b = SFrame.read_csv(f2b, delimited='\0', header=False)
sf1 = sf1a.join(sf1b)
sf2 = sf2a.join(sf2b)
sf = sf1.join(sf2, on='X1', how='left')
sf.save('pivoted')
Run Code Online (Sandbox Code Playgroud)
该ZIP功能无法存储iterables的整个副本。所以我们可以安全地使用它。
假设您有两个按第一列升序排序的可迭代对象,您可以按如下方式连接两个表。
def merge(t1, t2):
end = object()
end_ = end, None
a1, b1 = next(t1, end_)
a2, b2 = next(t2, end_)
while a1 is not end and a2 is not end:
if a1 < a2:
a1, b1 = next(t1, end_)
elif a1 > a2:
a2, b2 = next(t2, end_)
else:
yield a1, b1, b2
a1, b1 = next(t1, end_)
a2, b2 = next(t2, end_)
Run Code Online (Sandbox Code Playgroud)
Merge 使用两个迭代器调用并生成第三个迭代器,并且每次只需要存储每个迭代器的一个元素。
def merge(t1, t2):
end = object()
end_ = end, None
a1, b1 = next(t1, end_)
a2, b2 = next(t2, end_)
while a1 is not end and a2 is not end:
if a1 < a2:
a1, b1 = next(t1, end_)
elif a1 > a2:
a2, b2 = next(t2, end_)
else:
yield a1, b1, b2
a1, b1 = next(t1, end_)
a2, b2 = next(t2, end_)
Run Code Online (Sandbox Code Playgroud)
[(0, 1, 'a'), (1, 1, 'b'), (3, 2, 'd')]
Run Code Online (Sandbox Code Playgroud)
为了防止整个文件被存储,我有一个扫描方法,该方法将一次读取yield
每个文件的一行。
list(merge(iter([(0, 1), (1, 1), (3, 2)]),
iter([(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')])))
Run Code Online (Sandbox Code Playgroud)
然后你可以用这种方式解决你的问题(未经测试,我没有你的文件)
with open('pivoted.tsv', 'w') as fout:
t1 = scan_by_name(f1a, f1b)
t2 = scan_by_name(f2a, f2b)
for row in merge(t1, t2):
print('\t'.join(row), end='\n', file=fout)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
291 次 |
最近记录: |