我有一些巨大的制表符分隔文件,每个文件大约 2.1 TB,大约 8.5 K 行,大约 39.3M 列。第一列都是变长的字符串(ID),其余都是零以外三位非负固定精度小数(即ID后面的每一列都是5个字符长0.000)。
在具有 256GB RAM 的 Linux 计算机中转置文件的最有效方法是什么?最终,在转置之后,我想将文件分成每个 500K 行,以便我可以开始处理它。硬盘没问题,还有70TB可用空间。
这是我能想到的(每个文件大约需要 2.5 天)。问题在于每个文件的行数和列数略有不同。我不想在每次运行时修改脚本。或者,我可以编写一个专门的 C 程序来执行此操作,但我不愿意这样做。
#!/bin/bash
i=$1
mkdir temp-$i
cd temp-$i
echo "Splitting $i"
split -dl 1 -a 4 ../$i
echo "Transposing all lines"
for a in x???? ; do
cat $a | sed 's/\t/\n/g' > $a.txt
mv $a.txt $a
done
echo "Joining all columns"
# Here's where it gets really ugly:
paste x0000 x0001 ... x0999 > a.txt
paste x1000 x1001 ... x1999 > b.txt
paste x2000 x2001 ... x2999 > c.txt
paste x3000 x3001 ... x3999 > d.txt
paste x4000 x4001 ... x4999 > e.txt
paste x5000 x5001 ... x5999 > f.txt
paste x6000 x6001 ... x6999 > g.txt
paste x7000 x7001 ... x7999 > h.txt
paste x8000 x8001 ... x8499 > i.txt
paste ../colinfo-$i.txt a.txt b.txt c.txt d.txt e.txt f.txt g.txt h.txt i.txt > ../tr-$i.txt
cd ../
rm -Rf temp-$i
最佳答案
粘贴操作会降低你的性能。如何只创建与列一样多的文件,然后使用一次遍历输入文件,将数据写入列文件。即:
输入文件:
ID data1 data2 data3 .... data5000
94239 0.001 0.002 0.003 .... 5.000
43244 0.011 0.012 0.013 .... 5.010
输出文件:
col0:
ID 94239 43244
第 1 列:
data1 0.001 0.011
...这里还有 4999 个文件...
col5000:
data5000 5.000 5.010
可以使用这个 perl 程序来拆分列:
#!perl -n
use strict;
use warnings;
use File::Path 'make_path';
$INPUT_RECORD_SEPARATOR = "\t";
my $colno = 0;
my $maxcol = 0;
while(my $col = <STDIN>) {
$colno = 0 if $col =~ s/\n//;
$colno++;
my $path = join '/', $colno =~ /(\d{3})/g;
if($colno > $maxcol) {
make_path $path;
$maxcol = $colno;
}
open my $OUT, '>>', "$path/col.tsv";
print $OUT "$col\t";
close $OUT;
}
(未经测试!)
最后将文件连接在一起:
cat col0 col1 ... col5000 > newfile.tsv
(可能需要xargs
。)
关于bash - 转置大型制表符分隔文件 (2.1TB) @ 8.5Kx39M 的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15796628/