【问题标题】:How to extract specific columns from different files and output in one file?如何从不同文件中提取特定列并输出到一个文件中?
【发布时间】:2015-09-24 21:30:16
【问题描述】:

我在一个目录中有 12 个文件,每个文件有 4 列。第一列是基因名称,其余 3 列是计数列。所有文件都在同一个目录中。我想为每个文件提取 1,4 列(总共 12 个文件)并将它们粘贴到一个输出文件中,因为每个文件的第一列都是相同的,所以输出文件应该只有一个第一列,其余的将是其次是每个文件的第 4 列。每个文件的第一列是相同的。我不想在这里使用 R。我是 awk 的忠实粉丝。所以我尝试了类似下面的方法,但没有成功

我的输入文件看起来像 输入文件1

ZYG11B  8267    16.5021 2743.51
ZYG11A  4396    0.28755 25.4208
ZXDA    5329    2.08348 223.281
ZWINT   1976    41.7037 1523.34
ZSCAN5B 1751    0.0375582   1.32254
ZSCAN30 4471    4.71253 407.923
ZSCAN23 3286    0.347228    22.9457
ZSCAN20 4343    3.89701 340.361
ZSCAN2  3872    3.13983 159.604
ZSCAN16-AS1 2311    1.1994  50.9903

输入文件2

ZYG11B  8267    18.2739 2994.35
ZYG11A  4396    0.227859    19.854
ZXDA    5329    2.44019 257.746
ZWINT   1976    8.80185 312.072
ZSCAN5B 1751    0   0
ZSCAN30 4471    9.13324 768.278
ZSCAN23 3286    1.03543 67.4392
ZSCAN20 4343    3.70209 318.683
ZSCAN2  3872    5.46773 307.038
ZSCAN16-AS1 2311    3.18739 133.556

输入文件 3

ZYG11B  8267    20.7202 3593.85
ZYG11A  4396    0.323899    29.8735
ZXDA    5329    1.26338 141.254
ZWINT   1976    56.6215 2156.05
ZSCAN5B 1751    0.0364084   1.33754
ZSCAN30 4471    6.61786 596.161
ZSCAN23 3286    0.79125 54.5507
ZSCAN20 4343    3.9199  357.177
ZSCAN2  3872    5.89459 267.58
ZSCAN16-AS1 2311    2.43055 107.803

上面的期望输出

ZYG11B  2743.51 2994.35 3593.85
    ZYG11A  25.4208 19.854  29.8735
    ZXDA    223.281 257.746 141.254
    ZWINT   1523.34 312.072 2156.05
    ZSCAN5B 1.32254 0   1.33754
    ZSCAN30 407.923 768.278 596.161
    ZSCAN23 22.9457 67.4392 54.5507
    ZSCAN20 340.361 318.683 357.177
    ZSCAN2  159.604 307.038 267.58
    ZSCAN16-AS1 50.9903 133.556 107.803

在这里,您可以在每个文件的第一列和 4 列上方看到,因为每个文件的第一列是相同的,所以我只想保留它一次,其余的输出将具有每个文件的第 4 列。我刚刚展示了 3 个文件。它应该同时适用于目录中的所有文件,因为所有文件都有类似的命名约定,例如 file1_quant.genes.sf file2_quant.genes.sf , file3_quant.genes.sf

每个文件的第一列相同,但其余列中的计数不同。我的想法是创建一个输出文件,该文件应该包含所有文件的第一列和第四列。

awk '{print $1,$2,$4}' *_quant.genes.sf > genes.estreads

有什么注意事项吗?

【问题讨论】:

  • 给定输入的期望输出是什么?
  • @Sobrique 我已经修改了查询
  • 您对文件名或输出有任何排序限制吗? (例如,文件应该按字母顺序完成,还是任何顺序都可以?结果值是否应该按数字排序?)
  • 如果您不想使用它,为什么要用 [r] 标记您的问题?
  • 啊抱歉打错了,但现在我看到标签被删除了,谢谢

标签: perl awk sed


【解决方案1】:

如果我理解正确,您正在寻找的是每个键一行,从多个文件中整理而来。

完成这项工作所需的工具是关联数组。我认为awk 可以,但我不是 100% 确定。不过,我可能会在 perl 中解决它:

#!/usr/bin/perl
use strict;
use warnings;

# an associative array, or hash as perl calls it
my %data;

#iterate the input files (sort might be irrelevant here) 
foreach my $file ( sort glob("*_quant.genes.sf") ) {
    #open the file for reading. 
    open( my $input, '<', $file ) or die $!;
    #iterate line by line. 
    while (<$input>) {
        #extract the data - splitting on any whitespace. 
        my ( $key, @values ) = split; 
        #add'column 4' to the hash (of arrays)
        push( @{$data{$key}}, $values[2] );  
    }
    close($input);
}

#start output 
open( my $output, '>', 'genes.estreads' ) or die;
#sort, because hashes are explicitly unordered. 
foreach my $key ( sort keys %data ) { 
    #print they key and all the elements collected. 
    print {$output} join( "\t", $key, @{ $data{$key} } ), "\n";
}
close($output);

使用如上指定的数据,这会产生:

ZSCAN16-AS1 50.9903 133.556 107.803
ZSCAN2  159.604 307.038 267.58
ZSCAN20 340.361 318.683 357.177
ZSCAN23 22.9457 67.4392 54.5507
ZSCAN30 407.923 768.278 596.161
ZSCAN5B 1.32254 0   1.33754
ZWINT   1523.34 312.072 2156.05
ZXDA    223.281 257.746 141.254
ZYG11A  25.4208 19.854  29.8735
ZYG11B  2743.51 2994.35 3593.85

【讨论】:

  • 对不起,如果我理解正确,那么我应该用 {perl prog.pl} 运行这个程序,因为我没有看到文件参数。但是当我运行时,我在第 17 行得到错误
  • 是的,将它保存为something.pl 然后它会运行 - 它会在当前目录中查找*_quant_genes_sf 并处理它们。我可以将它压缩成一个命令行,但老实说,我认为这个任务比它应得的要复杂一些。
  • 收到错误 perl:warning: Falling back to the standard locale ("C"). Not an ARRAY reference at count.pl line 17, &lt;$input&gt; line 1.
  • 稍作修改,抱歉。
  • 是的。我们将 4 列拆分为一个键和一个 3 元素 @values - 编号从 02
【解决方案2】:

以下是你在awk中的做法:

awk 'BEGIN{FS = " "};{print $1, $4}' *|awk 'BEGIN{FS = " "};{temp = x[$1];x[$1] = temp  " "  $2;};END {for(xx in x) print xx,x[xx]}'

虽然看起来很神秘,但我只是在使用关联数组。


这是分解的解决方案:
  1. 只需打印键和值,每行一个。

    print $1, $2

  2. 将数据存储在关联数组中,不断更新

    temp = x[$1];x[$1] = temp " " $2;}

  3. 显示它:

    for(xx in x) print xx,x[xx]

示例运行:

[cloudera@quickstart test]$ cat f1
A k1
B k2

[cloudera@quickstart test]$ cat f2
A k3
B k4
C k1

[cloudera@quickstart test]$ awk 'BEGIN{FS = " "};{print $1, $2}' *|awk 'BEGIN{FS = " "};{temp = x[$1];x[$1] = temp  " "  $2;};END {for(xx in x) print xx,x[xx]}'
A  k1 k3
B  k2 k4
C  k1

附带说明,该方法应该让人想起 Map Reduce 范例。

【讨论】:

  • 啊,是的。认为awk 可以做关联数组,但不完全确定。
【解决方案3】:
awk '{E[$1]=E[$1] "\t" $4}END{for(K in E)print K E[K]}' *_quant.genes.sf > genes.estreads

顺序是读取文件时出现的顺序(通常基于 1 个读取的文件)

【讨论】:

  • 如果没记错的话应该有一个选项卡..上面的命令中缺少这个选项卡
  • 你的意思是你的输出样本中每行的起始标签在第 1 行之后?
  • 输出不是制表符分隔的,这就是我的意思
【解决方案4】:

如果所有文件的第一列都相同,则可以使用paste

paste <(tabify f1 | cut -f1,4) \
      <(tabify f2 | cut -f4)   \
      <(tabify f3 | cut -f4)

tabify 将连续空格更改为制表符:

sed 's/ \+/\t/g' "$@"

f1、f2、f3 是输入文件的名称。

【讨论】:

    【解决方案5】:

    这是在 Perl 中执行此操作的另一种方法:

     perl -lane '$data{$F[0]} .= " $F[3]"; END { print "$_ $data{$_}" for keys %data }' input_file_1 input_file_2 input_file_3
    

    【讨论】:

      【解决方案6】:

      这是使用 awk 的另一种方法。并且支持使用多个文件。

      awk 'FNR==1{f++}{a[f,FNR]=$1}{b[f,FNR]=$4}END { for(x=1;x<=FNR;x++){printf("%s ",a[1,x]);for(y=0;y<=ARGC;y++)printf("%s ",b[y,x]);print ""}}' input1.txt input2.txt input3.txt 
      

      那行代码,给出如下输出

      ZYG11B  2743.51 2994.35 3593.85  
      ZYG11A  25.4208 19.854 29.8735  
      ZXDA  223.281 257.746 141.254  
      ZWINT  1523.34 312.072 2156.05  
      ZSCAN5B  1.32254 0 1.33754  
      ZSCAN30  407.923 768.278 596.161  
      ZSCAN23  22.9457 67.4392 54.5507  
      ZSCAN20  340.361 318.683 357.177  
      ZSCAN2  159.604 307.038 267.58  
      ZSCAN16-AS1  50.9903 133.556 107.803 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多