bash - 转置大型制表符分隔文件 (2.1TB) @ 8.5Kx39M 的有效方法

标签 bash transpose

我有一些巨大的制表符分隔文件,每个文件大约 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/

相关文章:

linux - 查找一行并替换一个字符串

linux - 如何在 bash 中将给定文本拆分为 3 个变量并发送到端口主机?

git - 如果测试失败,则从预提交 GIT Hook 返回失败代码

Ruby 哈希转置

linux - Bash 提供编号的结果供用户选择

bash - bash 是否可以通过 stdin/stdout 交替读取和写入子进程 "interactively"?

python - Linux 将长格式转换为宽格式

julia - 在 Julia 中,转置运算符

python - 将列 reshape 为数据框 Pandas 中的行

python - 如何在 python 中将列转置为多行以获得列值?