如何转置一个包含1,743,680列和2890行的巨大txt文件

时间:2013-11-07 17:53:52

标签: perl awk

我有2890个人的遗传标记文件。我想转置这个文件。我的数据格式如下:(我这里只显示了6个标记)

ID rs4477212 kgp15297216 rs3131972 kgp6703048 kgp15557302 kgp12112772 ..... 
BV04976 0 0 1 0 0 0 
BV76296 0 0 1 0 0 0 
BV02803 0 0 0 0 0 0 
BV09710 0 0 1 0 0 0 
BV17599 0 0 0 0 0 0 
BV29503 0 0 1 1 0 1 
BV52203 0 0 0 0 0 0 
BV61727 0 0 1 0 0 0 
BV05952 0 0 0 0 0 0 

事实上,我的文本文件中有1,743,680列和2890行。如何转置它? 我想输出应该是这样的:

ID BV04976 BV76296 BV02803 BV09710 BV17599 BV29503 BV52203 BV61727 BV05952  
rs4477212 0 0 0 0 0 0 0 0 0 
kgp15297216 0 0 0 0 0 0 0 0 0 
rs3131972 1 1 0 1 0 1 0 1 0 
kgp6703048 0 0 0 0 0 1 0 0 0 
kgp15557302 0 0 0 0 0 0 0 0 0 
kgp12112772 0 0 0 0 0 1 0 0 0

2 个答案:

答案 0 :(得分:3)

我会对文件进行多次传递,可能是100次,每次传递获得1743680 / pass列,在每次传递结束时将它们写出(作为行)。

将数据汇编到数组中的字符串中,而不是数组数组,以降低内存使用量并减少传递次数。 在每次传递开始时为每个字符串预分配空间(例如$new_row[13] = ' ' x 6000; $new_row[13] = '';)可能会有所帮助。也可能没用。

答案 1 :(得分:0)

(参见:An efficient way to transpose a file in Bash

你试过吗

awk -f tr.awk input.txt > out.txt

其中tr.awk

{ 
    for (i=1; i<=NF; i++) a[NR,i]=$i
}
END {
    for (i=1; i<=NF; i++) {
        for (j=1; j<=NR; j++) {
            printf "%s", a[j,i]
            if (j<NR) printf "%s", OFS
        }
        printf "%s",ORS
    }
}

对于上述程序,您的文件可能太大了。 然后你可以尝试先拆分它。例如:

#! /bin/bash
numrows=2890
echo "Splitting file.."
split -d -a4 -l1 input.txt
arg=""
outfile="out.txt"
tempfile="temp.txt"
if [ -e $outfile ] ; then
    rm -i $outfile
fi
for (( i=0; i<$numrows; i++ )) ; do
    echo "Processing file: "$(expr $i + 1)"/"$numrows
    file=$(printf "x%04d\n" $i)
    tfile=${file}.tr
    cat $file | tr -s ' ' '\n' > $tfile
    rm $file
    if [ $i -gt 0 ] ; then
        paste -d' ' $outfile $tfile > $tempfile
        rm $outfile
        mv $tempfile $outfile
        rm $tfile
    else
        mv $tfile $outfile
    fi
done

请注意split将生成2890个临时文件(!)