【问题标题】:AWK: replacing distinct values, with averages, for duplicate entriesAWK:用平均值替换重复条目的不同值
【发布时间】:2016-09-07 06:45:50
【问题描述】:

我有许多数据文件,其中每一列代表一个唯一的样本,每一行对应一个基因名称。这是我的一个较小文件的示例:

MAPK3 9.49707613464767 9.34083460789419 9.12918870414545 
TIE1 5.12900020712651 5.15008091018047 5.15008091018047 
CYP2C19 3.80757247946463 3.80757247946463 3.87721584865861 
CXCR5 6.40745840005515 6.40745840005515 6.40745840005515 
CXCR5 6.04763929379884 6.13038198258514 6.13038198258514 
DUSP1 12.0320377077951 12.7960658385305 12.625340661444 
MMP10 4.1933379022831 4.1933379022831 4.1933379022831 
RXRG 4.33755505408386 4.32903686336417 4.32903686336417 
RXRG 6.91141485189572 6.96893082690402 6.96893082690402

请注意,在第一列中,基因名称CXCR5RXRG 已重复,但每个条目的值不同。我需要的输出文件如下所示:

MAPK3 9.49707613464767 9.34083460789419 9.12918870414545 
TIE1 5.12900020712651 5.15008091018047 5.15008091018047 
CYP2C19 3.80757247946463 3.80757247946463 3.87721584865861 
CXCR5 6.22754884693 6.2689201913201 6.2689201913201
DUSP1 12.0320377077951 12.7960658385305 12.625340661444 
MMP10 4.1933379022831 4.1933379022831 4.1933379022831 
RXRG 5.6244849529898 5.6489838451341 5.6489838451341

重复基因的值被平均并替换每个样本的原始条目。此外,我想保持独特的基因名称和值不变。需要明确的是,对于第 1 列中的每个重复基因名称,我不想要整行的平均值,而是每列的平均值。 我已经尝试使用这里描述的聪明的 awk 单行代码 calculate and print the average value of strings in a column 和这里 Average from different columns in shell script 。但是我无法概括命令来解释我的文件,这些文件可能有多达 100 个样本/列。他们不必要地混淆了我独特的基因名称。

我的新手级编码技能将是我的死亡!有什么建议吗?

谢谢

【问题讨论】:

    标签: bash awk replace average


    【解决方案1】:
    $ cat tst.awk
    NR == 1 { CONVFMT="%."length($2)-index($2,".")"f" }
    $1 != key { prt() }
    {
        key=$1
        for (i=2 ; i<=NF ; i++) {
            sum[i] += $i
        }
        cnt++
    }
    END { prt() }
    
    function prt() {
        if (key != "") {
            printf "%s", key
            for (i=2; i<=NF; i++) {
                printf "%s%s", OFS, sum[i] / cnt
            }
            print ""
        }
        delete sum
        cnt = 0
    }
    
    $ awk -f tst.awk file
    MAPK3 9.49707613464767 9.34083460789419 9.12918870414545
    TIE1 5.12900020712651 5.15008091018047 5.15008091018047
    CYP2C19 3.80757247946463 3.80757247946463 3.87721584865861
    CXCR5 6.22754884692699 6.26892019132015 6.26892019132015
    DUSP1 12.03203770779510 12.79606583853050 12.62534066144400
    MMP10 4.19333790228310 4.19333790228310 4.19333790228310
    RXRG 5.62448495298979 5.64898384513410 5.64898384513410
    

    【讨论】:

    • 我发现这正是我想要的。你能解释一下代码吗?
    • 第一行根据文件中的第一个值计算出您使用的精度,以便随后用于其他所有计算。当键值更改时,第二行调用 prt() 以打印与前一个键关联的值。下一个块(每次当前键与前一个相同时执行)对每个字段的值求和,并记录读取了多少行与该键的值。 END 部分调用 prt() 来打印最后读取的键的值。 prt() 函数打印值。
    【解决方案2】:

    awk 来救援!使用装饰/排序/取消装饰模式来保持行的顺序相同。

    $ awk '{f2[$1]+=$2; f3[$1]+=$3; f4[$1]+=$4; c[$1]++; r[$1]=NR}
        END{for(k in c) print r[k] "\t" k, f2[k]/c[k], f3[k]/c[k], f4[k]/c[k]}' file | 
    sort -n | cut -f2
    
    MAPK3 9.49708 9.34083 9.12919
    TIE1 5.129 5.15008 5.15008
    CYP2C19 3.80757 3.80757 3.87722
    CXCR5 6.22755 6.26892 6.26892
    DUSP1 12.032 12.7961 12.6253
    MMP10 4.19334 4.19334 4.19334
    RXRG 5.62448 5.64898 5.64898
    

    要指定小数位数,您可以使用格式修饰符切换到printf

    【讨论】:

      【解决方案3】:

      我对@9​​87654321@ 很陌生,但这可能会奏效(似乎对我有用)

      #!/bin/awk -f
      
      {
          for(i = 2; i <= 4; ++i)
              id[$1][i] = (id[$1][i] * num[$1] + $i) / (num[$1] + 1);
          ++num[$1]
      }
      
      END {
          for(key in num)
              printf "%s %.15g %.15g %.15g \n", key, id[key][2], id[key][3], id[key][4]
      }
      

      输出:

      $ cat test.txt|test.awk 
      MMP10 4.1933379022831 4.1933379022831 4.1933379022831 
      DUSP1 12.0320377077951 12.7960658385305 12.625340661444 
      CYP2C19 3.80757247946463 3.80757247946463 3.87721584865861 
      TIE1 5.12900020712651 5.15008091018047 5.15008091018047 
      CXCR5 6.22754884692699 6.26892019132015 6.26892019132015 
      RXRG 5.62448495298979 5.6489838451341 5.6489838451341 
      MAPK3 9.49707613464767 9.34083460789419 9.12918870414545 
      

      它创建一个以第一列名称为键的关联数组并保持运行平均值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        • 2013-10-09
        • 2018-05-26
        • 2023-03-26
        • 2013-04-01
        相关资源
        最近更新 更多