And*_*rew 3 perl awk large-files
我必须处理格式为10-20GB的文本文件:field1 field2 field3 field4 field5
我想将每行field2中的数据解析成几个文件中的一个; 推送到的文件是由field4中的值逐行确定的.field2中有25个不同的可能值,因此数据可以被解析为25个不同的文件.
我尝试过使用Perl(慢速)和awk(更快但仍然很慢) - 有没有人对替代方法有任何建议或指示?
仅供参考,这是我试图使用的awk代码; 注意我必须恢复通过大文件25次,因为我无法在awk中同时打开25个文件:
chromosomes=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25)
for chr in ${chromosomes[@]}
do
awk < my_in_file_here -v pat="$chr" '{if ($4 == pat) for (i = $2; i <= $2+52; i++) print i}' >> my_out_file_"$chr".query
done
Run Code Online (Sandbox Code Playgroud)
Gre*_*con 15
使用Perl,在初始化期间打开文件,然后将每行的输出与相应的文件匹配:
#! /usr/bin/perl
use warnings;
use strict;
my @values = (1..25);
my %fh;
foreach my $chr (@values) {
my $path = "my_out_file_$chr.query";
open my $fh, ">", $path
or die "$0: open $path: $!";
$fh{$chr} = $fh;
}
while (<>) {
chomp;
my($a,$b,$c,$d,$e) = split " ", $_, 5;
print { $fh{$d} } "$_\n"
for $b .. $b+52;
}
Run Code Online (Sandbox Code Playgroud)
你知道为什么它慢吗?因为你用外壳for循环处理那个大文件25次.!!
awk '
$4 <=25 {
for (i = $2; i <= $2+52; i++){
print i >> "my_out_file_"$4".query"
}
}' bigfile
Run Code Online (Sandbox Code Playgroud)
这是Python的解决方案.我在一个我编写的小文件上测试了它.我认为即使是大文件,这也是可以接受的,因为大部分工作都是由Python内部的C代码完成的.我认为这是一个令人愉快且易于理解的程序; 我更喜欢Python到Perl.
import sys
s_usage = """\
Usage: csplit <filename>
Splits input file by columns, writes column 2 to file based on chromosome from column 4."""
if len(sys.argv) != 2 or sys.argv[1] in ("-h", "--help", "/?"):
sys.stderr.write(s_usage + "\n")
sys.exit(1)
# replace these with the actual patterns, of course
lst_pat = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y'
]
d = {}
for s_pat in lst_pat:
# build a dictionary mapping each pattern to an open output file
d[s_pat] = open("my_out_file_" + s_pat, "wt")
if False:
# if the patterns are unsuitable for filenames (contain '*', '?', etc.) use this:
for i, s_pat in enumerate(lst_pat):
# build a dictionary mapping each pattern to an output file
d[s_pat] = open("my_out_file_" + str(i), "wt")
for line in open(sys.argv[1]):
# split a line into words, and unpack into variables.
# use '_' for a variable name to indicate data we don't care about.
# s_data is the data we want, and s_pat is the pattern controlling the output
_, s_data, _, s_pat, _ = line.split()
# use s_pat to get to the file handle of the appropriate output file, and write data.
d[s_pat].write(s_data + "\n")
# close all the output file handles.
for key in d:
d[key].close()
Run Code Online (Sandbox Code Playgroud)
编辑:这里有关于这个程序的更多信息,因为它似乎你将使用它.
所有错误处理都是隐含的.如果发生错误,Python将"引发异常",这将终止处理.例如,如果其中一个文件无法打开,该程序将停止执行,Python将打印一个回溯,显示哪行代码导致异常.我可以用"try/except"块包装关键部分,以捕获错误,但对于一个简单的程序,我没有看到任何意义.
它很微妙,但有一个检查,看输入文件的每一行是否正好有五个单词.当这段代码解包一行时,它会分为五个变量.(变量名称"_"是一个合法的变量名称,但是Python社区中有一个约定将它用于您实际上并不关心的变量.)如果不存在五个单词,Python将引发异常.输入行解压缩成五个变量.如果您的输入文件有时可以在一行上有四个单词,或者六行或更多,您可以修改程序以不引发异常; 将主循环更改为:
for line in open(sys.argv[1]):
lst = line.split()
d[lst[3]].write(lst[1] + "\n")
Run Code Online (Sandbox Code Playgroud)
这会将行拆分为单词,然后将整个单词列表分配到单个变量lst中.所以这行代码并不关心行上有多少个单词.然后下一行索引到列表中以获取值.由于Python使用0开始索引列表,因此第二个单词是lst[1],第四个单词是lst[3].只要列表中至少有四个单词,该行代码也不会引发异常.
当然,如果该行的第四个单词不在文件句柄的字典中,Python也会为此引发异常.这将停止处理.下面是一些如何使用"try/except"块来处理这个问题的示例代码:
for line in open(sys.argv[1]):
lst = line.split()
try:
d[lst[3]].write(lst[1] + "\n")
except KeyError:
sys.stderr.write("Warning: illegal line seen: " + line)
Run Code Online (Sandbox Code Playgroud)
祝你的项目好运.
编辑:@larelogio指出此代码与AWK代码不匹配.AWK代码有一个额外的for循环,我不明白.这是Python代码做同样的事情:
for line in open(sys.argv[1]):
lst = line.split()
n = int(lst[1])
for i in range(n, n+53):
d[lst[3]].write(i + "\n")
Run Code Online (Sandbox Code Playgroud)
这是另一种方法.这可能会快一点,但我没有测试过,所以我不确定.
for line in open(sys.argv[1]):
lst = line.split()
n = int(lst[1])
s = "\n".join(str(i) for i in range(n, n+53))
d[lst[3]].write(s + "\n")
Run Code Online (Sandbox Code Playgroud)
这将构建一个包含要写入的所有数字的字符串,然后将它们写入一个块中.与调用.write()53次相比,这可以节省时间.