根据现有表的特定参数创建新表

根据现有表的特定参数创建新表

我想从一个表创建多个单独的 CSV 文件。这是一个示例表:

gene   REF_S1_host  REF_S1_FL  S1_host1  S1_host2  S1_FL  REF_S2_host  REF_S2_FL  S2_host1  S2_host2  S2_FL
gene1  1            0          0         0         0      0            0          0         0         0
gene2  1            1          1         1         0      0            0          0         0         0
gene3  0            1          0         0         1      0            0          0         0         0
gene4  1            0          0         0         0      1            0          0         0         0
gene5  0            0          0         0         0      1            0          1         0         0
gene6  1            0          0         0         0      0            0          0         1         1
gene7  0            1          0         0         0      0            0          0         0         1

我想创建一个 CSV(或其他制表符分隔文件):

  1. 提取包含“S1”的列标题下包含“1”的所有数据,但对于同一基因,包含“S2”的所有标题的值为“0”。例如:

    gene   REF_S1_host  REF_S1_FL  S1_host1  S1_host2  S1_FL  REF_S2_host  REF_S2_FL  S2_host1  S2_host2  S2_FL
    gene1  1            0          0         0         0      0            0          0         0         0
    gene2  1            1          1         1         0      0            0          0         0         0
    gene3  0            1          0         0         1      0            0          0         0         0
    
  2. 仅拉出其中任何 REF 文件(S1 或 S2)的值为“1”的行,但所有其他字段(即不包含“REF”的行标题)仅拉出“0”的行。例如:

    gene   REF_S1_host  REF_S1_FL  S1_host1  S1_host2  S1_FL  REF_S2_host  REF_S2_FL  S2_host1  S2_host2  S2_FL
    gene1  1            0          0         0         0      0            0          0         0         0
    gene4  1            0          0         0         0      1            0          0         0         0
    
  3. 其中 REF_S1* 包含“1”+ 其中全部其他(即非 REF)S1 样本为“0”+ 其中全部REF_S2* 为“0”+,但任何其他 S2 样本(非 REF)为“1”。例如:

    gene   REF_S1_host  REF_S1_FL  S1_host1  S1_host2  S1_FL  REF_S2_host  REF_S2_FL  S2_host1  S2_host2  S2_FL
    gene6  1            0          0         0         0      0            0          0         1         1
    gene7  0            1          0         0         0      0            0          0         0         1
    
  4. 最后,其中任何 *FL 为“1”,所有 *host 为“0”。例如:

    gene   REF_S1_host  REF_S1_FL  S1_host1  S1_host2  S1_FL  REF_S2_host  REF_S2_FL  S2_host1  S2_host2  S2_FL
    gene3  0            1          0         0         1      0            0          0         0         0
    gene7  0            1          0         0         0      0            0          0         0         1
    

但我不知道如何去做这件事。欢迎任何建议。

答案1

我假设

  • 正如您(某种程度上)所示,您的数据由空格分隔。
  • 您的表始终有十一列(但大概可以有任意数量的行)。
  • 单元格值从不包含空格。 (特别是,除了第 1 行(标题)和第 1 列(基因)之外的所有内容都是0或 1。)

这很容易与awk.

  1. ...在包含“S1”的列标题下包含“1”的所有数据,但对于同一基因,包含“S2”的所有标题的值为“0”。

    换句话说,

      (第 2 列为 1 OR 第 3 列为 1 OR 第 4 列为 1 OR 第 5 列为 1 OR 第 6 列为 1)
        AND
       第 7 列为 0
        AND
       第 8 列为 0
        AND
       第 9 列为 0
        AND
      第 10 列为 0
        AND
      第 11 列为 0
    所以,

    awk -v OFS=',' '
            NR==1 { next }
            ($2==1 || $3==1 || $4==1 || $5==1 || $6==1)  &&
                    $7==0 && $8==0 && $9==0 && $10==0 && $11==0 { $1=$1; print }
        '
    
    • OFS是“输出字段分隔符”。  -v OFS=','告诉awk用逗号分隔字段写入数据,即使输入是制表符分隔或空格分隔。
    • 告诉跳过第一行(标题行)NR==1 { next }awk如果要打印标题行,请将其更改为NR==1 { $1=$1; print; next }
    • 接下来的两行对上面阐述的 AND/OR 逻辑进行编码。
    • { $1=$1; print }打印该行(如果满足条件)。该 $1=$1方法将第一个字段设置为等于其自身。这听起来似乎没有什么作用。事实上,强制awk使用新的(用户指定的)输出字段分隔符(我们将其指定为逗号)重建行是一个技巧。如果您改变主意并希望完全按照输入中显示的方式输出行,请删除 -v OFS=','和 $1=$1;
  2. ...仅那些对于任何 REF 文件(S1 或 S2)都有“1”值,但对于所有其他字段只有“0”值的行...

    awk -v OFS=',' '
            NR==1 { next }
            ($2==1 || $3==1 || $7==1 || $8==1)  &&
                    $4==0 && $5==0 && $6==0 && $9==0 && $10==0 && $11==0 { $1=$1; print }
        '
    
  3. 其中 REF_S1* 包含“1” + 所有其他(即非 REF)S1 样本为“0” + 所有 REF_S2* 为“0”但任何其他 S2 样本(非 REF)为“1” 。

    awk -v OFS=',' '
            NR==1 { next }
            ($2==1 || $3==1) && $4==0 && $5==0 && $6==0  &&
                    $7==0 && $8==0 && ($9==1 || $10==1 || $11==1) { $1=$1; print }
        '
    
  4. ...其中任何 *FL 为“1”,所有 *host 为“0”。

    awk -v OFS=',' '
            NR==1 { next }
            ($3==1 || $6==1 || $8==1 || $11==1)  &&
                    $2==0 && $4==0 && $5==0 && $7==0 && $9==0 && $10==0 { $1=$1; print }
        '
    

答案2

这个问题的解决方法是使用珀尔分三步进行。

  • 编写一个子例程,在给定选择标准正则表达式的情况下,吐出满足标准的字段编号。
  • 使用子例程,在读取第一行或标题行时为每个列出的条件生成字段索引。
  • 最后,借助这些不同的数组,我们使用从 List::MoreUtils 模块导入的函数执行布尔选择标准。
  • 注意:以one-hot方式分别运行四种情况。否则输出将交错。
perl -MList::MoreUtils=any,all -lane '
  BEGIN {
    sub mkAry {
      my $re = shift;
      grep { $_ }
      map { $h{$_} }
      grep { /$re/ } keys %h
    }
  }
  if ($. == 1) {
    print;
    @h{@F} = (0..$#F);
    @S1 = mkAry qr/S1/;
    @S2 = mkAry qr/S2/;
    @REF = mkAry qr/REF/;
    @notREF = mkAry qr/^(?!.*REF)/;
    @REF_S1 = mkAry qr/REF_S1/;
    @REF_S2 = mkAry qr/REF_S2/;
    @notREF_S1 = mkAry qr/^(?!.*REF)(?=.*S1)/;
    @notREF_S2 = mkAry qr/^(?!.*REF)(?=.*S2)/;
    @FL = mkAry qr/FL/;
    @host = mkAry qr/host/;
    next;
  }

  ##_1_:
  print if
    any { $_ == 1 } @F[@S1] and
    all { $_ == 0 } @F[@S2]
  ;

  ##_2_:
  print if
    any { $_ == 1 } @F[@REF] and
    all { $_ == 0 } @F[@notREF]
  ;

  ##_3_:
  print if
    any { $_ == 1 } @F[@REF_S1] and
    all { $_ == 0 } @F[@notREF_S1] and
    all { $_ == 0 } @F[@REF_S2] and
    any { $_ == 1 } @F[@notREF_S2]
  ;

  ##_4_:
  print if
    any { $_ == 1 } @F[@FL] and
    all { $_ == 0 } @F[@host]
  ;
' file | column -t

相关内容