我必须处理10-20 of大小的文本文件,格式为: 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发布于 2009-12-21 16:00:08
这是一个Python的解决方案。我已经在我编造的一个小的假文件上进行了测试。我认为这对于即使是大文件来说也是可以接受的,因为大部分工作将由Python中的C代码完成。我认为这是一个令人愉快且易于理解的程序;与Perl相比,我更喜欢Python。
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()编辑:这里有一些关于这个程序的更多信息,因为看起来你会用到它。
所有的错误处理都是隐式的。如果发生错误,Python将“引发异常”,从而终止处理。例如,如果其中一个文件无法打开,则此程序将停止执行,并且Python将打印一个回溯,显示导致异常的代码行。我本可以用"try/except“块包装关键部分,以捕获错误,但对于如此简单的程序,我看不出有任何意义。
这很微妙,但需要检查输入文件的每一行是否恰好有五个单词。当这段代码解压一行时,它将解压成五个变量。(变量名"_“是一个合法的变量名,但是在Python社区中有一个约定,将它用于您实际上并不关心的变量。)如果输入行上恰好没有五个单词要解压到五个变量中,Python将引发异常。如果您的输入文件有时一行包含四个单词,或者六个或更多单词,则可以修改程序以不引发异常;将主循环更改为:
for line in open(sys.argv[1]):
lst = line.split()
d[lst[3]].write(lst[1] + "\n")这会将行拆分为单词,然后将整个单词列表分配到一个变量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)祝你的项目好运。
编辑:@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")这是另一种方法。这可能会快一点,但我没有测试过,所以我不确定。
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")这将构建一个包含所有要写入的数字的字符串,然后将它们写入一个块中。与调用.write() 53次相比,这可能会节省时间。
发布于 2009-12-17 11:05:14
使用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;
}发布于 2009-12-17 10:05:31
你知道为什么它很慢吗?这是因为您正在使用外壳for循环处理那个大文件25次。!!
awk '
$4 <=25 {
for (i = $2; i <= $2+52; i++){
print i >> "my_out_file_"$4".query"
}
}' bigfilehttps://stackoverflow.com/questions/1919026
复制相似问题