如何在终端 Linux 中将列转换为行?但更复杂

How to transform column to row in Terminal Linux? But more complex

如何在终端 Linux 中将列转换为行?但是比较复杂... 下面是我的数据的例子:

SNP_Name        ID_Animal        Allele        Chr        Position
rs01            215               AB            1            100
rs02            215               AA            2            200
rs03            215               BA            3            300
rs04            215               AA            4            400
rs01            300               AB            1            100
rs02            300               BB            2            200
rs03            300               AA            3            300
rs04            300               AB            4            400
rs01            666               BB            1            100
rs02            666               AA            2            200
rs03            666               AB            3            300
rs04            666               AB            4            400

我想将其转换为以下内容:

SNP_Name     Chr     Position   215(ID_animal)  300(ID_Animal) 666(ID_Animal)
rs01         1       100        AB              AB            BB
rs02         2       200        AA              BB            AA
rs03         3       300        BA              AA            AB
rs04         4       400        AA              AB            AB

ID_animal列中的相应等位基因发生变化。我该怎么做? 但我将每 ID_animal 重复 55,000 次。所以,我只想成为 55,000 行和 (animal number+SNP_Name+Chr+Position) 的列。

谢谢。

这里的问题是数据量,我不想给出一个全部读入内存然后输出的方案

为此,我想依次解析和输出每个 SNP(rs 个数字)的数据,而不是依次为每个动物解析和输出数据。但是数据以错误的顺序提供给我们(按动物排序)。

所以我们要做的第一件事就是按照SNP(第一列)对数据进行排序。我还将同时删除 header 行,因为数据转换不需要它。

我假设数据存储在文件 data.in:

$ sed '1d' data.in | sort -o data.tmp

我们现在有:

$ cat data.tmp
rs01            215               AB            1            100
rs01            300               AB            1            100
rs01            666               BB            1            100
rs02            215               AA            2            200
rs02            300               BB            2            200
rs02            666               AA            2            200
rs03            215               BA            3            300
rs03            300               AA            3            300
rs03            666               AB            3            300
rs04            215               AA            4            400
rs04            300               AB            4            400
rs04            666               AB            4            400

然后我运行生成结果如下:

$ awk -f script.awk data.tmp >data.new

awk 脚本很长,所以将它放在自己的脚本文件中而不是作为 "one-liner":

是有意义的
FNR == 1    {
    # at first line of input

    rsid        = ;
    chr         = ;
    pos         = ;

    c           = 0;
    aid[c]      = ; # animal ID
    all[c++]    = ; # allele

    do_header   = 1;  # output header when done parsing this SNP

    next;
}

rsid ==  {
    # still reading animal ID/allele for this SNP
    aid[c]      = ;
    all[c++]    = ;
    next;
}

{
    if (do_header) {
        # output header

        printf("SNP_name\tChr\tPosition\t");
        for (c in aid) {
            printf("%d\t", aid[c]);
        }
        printf("\n");

        do_header = 0;
    }

    # output line with data from previous SNP    
    printf("%s\t%d\t%d\t", rsid, chr, pos);
    for (c in all) {
        printf("%s\t", all[c]);
    }
    printf("\n");

    # store data for this SNP
    rsid        = ;
    chr         = ;
    pos         = ;

    c           = 0;
    aid[c]      = ;
    all[c++]    = ;
}

END {
    # output line for last SNP

    printf("%s\t%d\t%d\t", rsid, chr, pos);
    for (c in all) {
        printf("%s\t", all[c]);
    }
    printf("\n");
}

对于给定的输入,这将生成具有以下内容的 tab-delimited 文件 data.new

SNP_name    Chr Position    215 300 666
rs01    1   100 AB  AB  BB
rs02    2   200 AA  BB  AA
rs03    3   300 BA  AA  AB
rs04    4   400 AA  AB  AB

注意:要求所有动物的基因分型完全相同的 SNP。每个 SNP 都需要出现相同的动物 ID。没有例外。