合并文件数据,在染色体上排序,彼此相邻的位置 - 柱虎钳

合并文件数据,在染色体上排序,彼此相邻的位置 - 柱虎钳

我有多个格式为:chr 位置值的文件。

我想将它们以格式“chr”,“position”,“samp1”,“samp2”,“samp3”,“samp4”,......

例如:

样本1:

chr position value
1   3774318 1
1   3774319 1
1   3775200 2
1   3775201 7
1   3775202 70
1   3775203 7
1   3775204 270
1   3775205 3
1   3775206 5

样本 2:

chr position value
1   3775200 1
1   3775201 1
1   3775202 10
1   3775203 1
1   3775204 12
1   3775205 1
1   3775206 13
1   3775207 1
1   3775208 1
1   3775209 18

(等等 ...)

所需的输出文件:/我在输出文件中放入随机值

chr, position, value-samp1, value-samp2, value-samp3, value-samp4 
1 50204 2 17 5 2
1 50205 2 17 5 2
1 50206 2 18 5 2
1 50207 2 19 5 3
1 50208 3 19 5 3
1 50209 3 19 5 3

我尝试了 join、merge、cat,但它没有按我的预期工作。我是初学者。您有什么想法可以做到吗?

(编者注:这是使用您提供的实际数据描述的操作示例。)

chr position    samp1   samp2
1   3774318     1       0
1   3774319     1       0
1   3775200     2       1
1   3775201     0       1
1   3775202     70      10
1   3775203     7       1
1   3775204     270     12
1   3775205     3       1
1   3775206     5       13
1   3775207     7       1
1   3775208     0       1
1   3775209     0       18

答案1

另一种awk方法。NA对于输入文件之一中不存在特定变体的情况,将打印此文件:

awk '{ if(FNR==1){files[fnum++]=FILENAME}else{var[$1"\t"$2][FILENAME]=$3}} END{ for(v in var){for(file in files){if(! var[v][files[file]]){var[v][files[file]]="NA"}}}printf "chr\tposition "; for(i=1;i<=fnum;i++){printf "value-samp%s\t",i;} print "";for(v in var){ printf "%s ",v; for(file in var[v]){if(file in var[v]); else{var[v][file]="NA";}  printf "%s\t", var[v][file] } print ""}}' s1 s2

或者,如果你不太喜欢简洁的话:

awk '{ 
        if(FNR==1){
            files[fnum++]=FILENAME
        }
        else{
            var[$1"\t"$2][FILENAME]=$3
        }
      } 
      END{ 
        for(v in var){
            for(file in files){
                if(! var[v][files[file]]){
                    var[v][files[file]]="NA"
                }
            }
        }
        printf "chr\tposition "; 
        for(i=1;i<=fnum;i++){
            printf "value-samp%s\t",i;
        } 
        print "";
        for(v in var){ 
            printf "%s ",v; 
            for(file in var[v]){
                if(file in var[v]); 
                else{
                    var[v][file]="NA";
                }
            printf "%s\t", var[v][file];
        } 
    print "";
    }
}' s1 s2

s1将和更改s2为您正在使用的实际文件名。在示例输入上运行上述命令将返回:

chr position value-samp1    value-samp2 
1   3774318 1   NA  
1   3775200 2   1   
1   3774319 1   NA  
1   3775201 7   1   
1   3775202 70  10  
1   3775203 7   1   
1   3775204 270 12  
1   3775205 3   1   
1   3775206 5   13  
1   3775207 NA  1   
1   3775208 NA  1   
1   3775209 NA  18  

答案2

服用这个解决方案对于与基础类似的问题,我们需要对其进行微调以获得您想要的结果。这不是答案,只是一个大纲,并使用了一些伪代码(原文如此?)概述必须做什么。

Linux 的回顾加入命令和它的能力对于成功的解决方案至关重要。请注意,在加入之前,必须按特定字段(此处使用染色体编号,字段 2)对每个输入文件进行排序。

因为 join 只能连接两个文件,所以我们需要多次单步执行 join,因此需要一些编程结构和控制机制。我们还需要修改数据本身,因为您指定的空白(空)值应替换为 0。

1)将第一个数据文件复制到不同的名称,也许样本_0

2)检查每一行样本_0 字段 3 的值。如果为 null,则替换为 0 。

3)初始化值X以匹配数据文件的编号。

4) 创建一个 for/next 循环来连续使用每个数据文件。您有多少个数据文件?那么,为了使这项工作无需每次运行脚本时都对其进行编辑,请使用 for/next 循环运行脚本,直到用完数据文件为止。

5) 在 for/next 循环中,做两件事。

5A) 检查下一个文件的每一行中字段 3 的值。如果为 null,则替换为 0 。

5B) 执行加入包括不可配对的线路(与-A选项)在文件的染色体编号(字段 2)上样本_0和文件样本_x 具有自动格式化功能(使用选项-o 自动)所以它合并所有染色体的数据行,而不仅仅是那些在两个文件中都有数据的染色体样本_0和文件样本_x。将输出写入文件样本_0

6) 如果还有另一个数据文件,则增加X然后返回并再次执行3)。如果所有数据文件都已连接,请退出 for/next 循环,因为您已完成。

答案3

chr我暂时忽略了它,因为如果它始终为 1,那么就可以安全地忽略它,否则 OP 需要解释它是如何适应的。

awk 'BEGIN {printf "position " }
        FNR>1{ 
        if (FNR==2) {nof+=1; printf ("%s%s " ,"Sam", nof )};
        pos[$2]=$2; data[$2, nof]=$3}
    END { printf "\n"; for (p in pos) {printf ("%s ", pos[p]); 
        for (d=1;d<=nof;d++) printf ("%s ", data[p,d]+0); print "\n"}
    }' file1 file2 | column -t

输出

position  Sam1  Sam2
3774318   1     0
3774319   1     0
3775200   2     1
3775201   7     1
3775202   70    10
3775203   7     1
3775204   270   12
3775205   3     1
3775206   5     13
3775207   0     1
3775208   0     1
3775209   0     18

演练

开始时打印第一个列标题

awk 'BEGIN {printf "position " }

忽略所有第一行作为标题

FNR>1{ 

在每个文件的第二行增加文件数并打印标题

if (FNR==2) {nof+=1; printf ("%s%s " ,"Sam", nof )};

对于标题之后的每一行,将位置放入数组中pos;设置另一个数组data,其中包含由文件(样本)编号sam索引的值pos

pos[$2]=$2; data[$2, nof]=$3}

读入所有文件后,newline在标题上打印 a,然后迭代pos打印每个位置

END { printf "\n"; for (p in pos ) {printf ("%s ", pos[p]); 

然后迭代datapsam/file 编号索引的数组,将 0 添加到任何空data值,这样即使没有数据也会打印一些内容;然后打印一个newline

for (d=1;d<=nof;d++) printf ("%s ", data[p,d]+0); print "\n"}

只需输入文件并通过管道输出column即可使其看起来不错

}' file1 file2 | column -t

添加了字符假设它是另一个索引

awk 'BEGIN {printf "chr position " }
        FNR>1{
        if (FNR==2) {nof+=1; printf ("%s%s " ,"Sam", nof )};
        chr[$1]=$1; pos[$2]=$2; data[$1, $2, nof]=$3}
    END { printf "\n"; for (c in chr) {for (p in pos ) {printf ("%s %s ", chr[c], pos[p]); 
        for (d=1;d<=nof;d++) printf ("%s ", data[c, p, d]+0); print "\n"}
    }}' file1 file2 | column -t

答案4

使用米勒(https://github.com/johnkerl/miller)你可以运行

mlr --c2p --ifs ' '  --repifs \
sort -f chr,position,value \
then nest --implode --values --across-records -f value \
then nest --explode --across-fields --values -f value \
then unsparsify then clean-whitespace input0*.csv >output.csv

并获得

chr position value_1 value_2
1   3774318  1       -
1   3774319  1       -
1   3775200  1       2
1   3775201  1       7
1   3775202  10      70
1   3775203  1       7
1   3775204  12      270
1   3775205  1       3
1   3775206  13      5
1   3775207  1       -
1   3775208  1       -
1   3775209  18      -

笔记:

  • 您必须使命令适应输入文件的名称。在我的例子中我使用了input0*.csv
  • 如果您想要真正的 CSV 输出,请更改--c2p--csv.

相关内容