Python 在数千个表中合并行的可扩展方式
我有大约50k个类似csv的文件,每个文件之间用空格隔开,每个文件大约有几千万行。第一列总是不带空格的字符串,第二列总是正整数,并且没有丢失的数据。在这个问题上,我只对第一列感兴趣,所以请忽略第二列。下面是两个这样的csv文件的玩具示例Python 在数千个表中合并行的可扩展方式,python,csv,pandas,union,Python,Csv,Pandas,Union,我有大约50k个类似csv的文件,每个文件之间用空格隔开,每个文件大约有几千万行。第一列总是不带空格的字符串,第二列总是正整数,并且没有丢失的数据。在这个问题上,我只对第一列感兴趣,所以请忽略第二列。下面是两个这样的csv文件的玩具示例 example1.csv f1 x f2 x f5 x f7 x ... f1 x f2 x f3 x f4 x f6 x ... example2.csv f1 x f2 x f5 x f7 x ... f1 x f2 x f3 x f4 x f6 x
example1.csv
f1 x
f2 x
f5 x
f7 x
...
f1 x
f2 x
f3 x
f4 x
f6 x
...
example2.csv
f1 x
f2 x
f5 x
f7 x
...
f1 x
f2 x
f3 x
f4 x
f6 x
...
如您所见,两个文件中的要素集有重叠,但不相同。我想做的是合并来自所有50k csv文件的数据,并将其转换为以下形式
file_name f1 f2 f3 f4 f5 f6 f7 ....
example1.csv 1 1 0 0 1 0 1 ...
example2.csv 1 1 1 1 0 1 0 ...
...
所以基本上是构造一个文件名
x特征id
的矩阵,如果特征id
存在于文件中,则为1,否则为0。这里的解析相对简单,重点是可伸缩性,在未来的项目中,行数可能会达到数十亿。我可以访问最多有一到两TB内存和100个内核的机器。因此,我想内存约束不太重要,但我下面所示的简单实现在玩具示例上效果很好,但对于真正的示例来说速度太慢了,并且在第一个文件中达到310000行时似乎挂起,我不知道为什么。(你知道为什么吗?我的直觉说它可能与defaultdict有关,不确定它是如何实现的,而且使用起来可能会很昂贵。)我希望解决方案能够相当快。解决方案最好是使用Python,但其他语言也可以
import os
import gzip
from collections import defaultdict
import pandas as pd
# collect paths to all csv-like files
with open('file_list.txt') as inf:
inputs = [_.split() for _ in inf.readlines]
inputs_map = dict(zip(inputs, range(len(inputs))))
res = defaultdict(lambda :[0] * len(inputs))
for k, infile in enumerate(inputs):
print(k, infile)
source_file = os.path.abspath(infile)
source_file_id = inputs_map[source_file]
# starting parsing the csv-like file
with gzip.open(source_file, 'rt') as inf:
for kl, line in enumerate(inf):
feature_id = line.split()[0]
res[feature_id][source_file_id] = 1
if (kl + 1) % 10000 == 0:
print('File {0}'.format(k), 'Line {0}'.format(kl + 1), source_file)
df = pd.DataFrame(res)
df.index = inputs
print('starting writing to disk...')
df.T.to_csv('output.csv')
对于两个文件,您可以使用
cat example1.csv example2.csv | cut-d”“-f1 | sort-u获取行名
。AFAIKsort
非常快速高效,如果内存不足,它会使用磁盘。重复将此过程应用于成对的文件可能是一个好方法。您的意思是首先获得所有行的并集,然后循环遍历每个文件吗?我仍然需要哪个文件包含哪个功能的信息。你能使用hdfs+spark吗?就可伸缩性而言,它似乎是很好的工具?如果你有所有的行名称并对输入文件进行排序,那么就很容易编写程序以线性时间和恒定内存生成矩阵。如果你的问题是伸缩性,我想他们会更糟;)关于你的问题有一个很好的页面:你确定这会扩大吗<代码>[在fs中读取f的ex(f)]对我来说很棘手。我不确定,我会尝试一下。首先尝试使用几个文件。它可能无法工作,因为[read_ex(f)for f in fs]
读取了太多的冗余信息,并会破坏内存。我做了一个粗略的计算,列表理解可能会消耗3TB的内存,需要19个小时。。。如果我想到其他事情,我会更新帖子。