关联数组:Python vs Perl vs Awk Perform

2024-04-19 12:33:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在处理大约4亿行和3列的文件。前两列是字母数字字符串,最后一列是数字字符串。像这样:

NM_001011874.1,NM_011441.4,-0.131672299779153

我有多个这样的文件,行数和列数大致相同。这些不一定根据3列中的任何一列进行排序。我试图根据前两列的组合来组合这些文件。例如:

^{pr2}$

我要做的是通过使用前两列中的值的组合来创建一个键,然后从第三列中为该对检索相应的值。我得到的最终结果是:

Output2 

NM_001011874.1,XR_104537.1,-0.11254525414,-0.929524370261122,-0.41254525414
NM_001011874.1,NM_005040.1,-0.20509876488,,-0.60509876488

我使用awk来执行上述操作:

awk -F',' 'NR==FNR{a[$1,$2]=$3;next}{$4=a[$1,$2];print}' OFS=',' file1.txt file2.txt

我为这个任务分配了256GB。使用上面的命令,通过合并两个文件(每个文件有大约4亿行和3列)生成输出,大约需要90分钟。输出文件同样有大约4亿行,但有4列。生成输出文件所需的时间随着每添加一列而增加。在

我是按顺序执行的,即合并file1和file2以生成包含4列的output1。然后合并file3和output1生成包含5列的output2,然后合并file4和output2生成包含6列的output3,依此类推,直到得到包含22列的最终输出。在

我想知道,在速度和自动化方面,用Python或Perl来做是否更有效?我有大约20个这样的文件,每个文件有3列,尽管行数从1亿到4亿不等。如果您认为我最好使用Python或Perl来实现这一点,那么您可以分享一个示例来说明awk脚本如何转换为Python或Perl。在

编辑: 添加了文件3以及之后基于注释的最终输出。在


Tags: 文件字符串txt排序字母数字file1perl
1条回答
网友
1楼 · 发布于 2024-04-19 12:33:27

如果您有大量的数据文件,并且希望高效地使用它们,那么最好将它们放入SQLite数据库中,对它们进行索引,然后进行查询。更多信息请参见my answer about CSV vs SQLite performance。在

为数据创建一个表(stuff是一个糟糕的名字,但是我不知道这个数据是什么,所以它是“stuff”)。在

create table stuff (
    key1 text,
    key2 text,
    value real
);

使用SQLite外壳将CSV导入表中。在

^{pr2}$

为键创建索引。在

^{3}$

问心无愧。在

select value
from stuff
where key1 = "NM_001011874.1" and
      key2 = "XR_104537.1"

-0.929524370261122
-0.11254525414
-0.41254525414

导入和索引完成后,数据的大小就不重要了。不需要更新CSV并重新导入所有CSV,您可以只导入带有新字段的小CSV文件。或者您可以跳过csv直接插入它们。在

insert into stuff (key1, key2, value)
values ("NM_204958293.2", "XR_29238498.3", -239.2),
       ("NM_2904892.3", "XR_3093.0", 9482.39);

我测试了它的性能,因为我已经提倡过很多次了,但是还没有测试过。在

首先我清理了一堆磁盘空间,因为这些文件会变大。我在一台2011年最先进的MacBookPro i7上做这个。幸运的是,它有一个售后市场SSD,所以I/O性能非常出色。它不是无精打采的,但也不是一流的服务器。关键是,您不需要花哨的硬件来获得良好的性能。在

然后我写了一个Perl program to generate 400 million rows of data,当它运行时,我写了a C program to do it faster。在一个罕见的例子中,对于一个一次性脚本来说,程序时间比程序员时间更重要,C程序首先以两个大致相同的14G文件结束。他们有点不同,但这对我们的目的来说无关紧要。在

然后我创建了表并开始导入。最初的导入时间并不十分重要,因为我不必坐在这里盯着它看,也不必娇生惯养。我知道它会成功的,我知道我只需要做一次,所以我可以同时处理任何数量的事情(比如编辑这篇文章)。不幸的是,SQLite没有并行工作,它似乎只使用一个核心。它使用的内存不会超过3兆。在

导入一个4亿行文件需要20分钟。由此产生的SQLite数据库大约是17gig,因此数据没有很大的扩展。剩下的我就不做了,因为它很快就变得多余了。在

现在我正在创建索引。再说一次,我不必坐在那里看。。。但我这么做是因为它使用了1G的虚拟内存,而SQLite文件现在是30 gig。所以。。。更多文件删除。建立索引大约花了30分钟。在

使用30 Gig磁盘导入和索引需要50分钟,大约是原始数据的两倍。无需编程。在

相关问题 更多 >