计算第二列和第三列的值,其中第一列的值是常数/相同

计算第二列和第三列的值,其中第一列的值是常数/相同

我想计算 tab delim txt 文件第二列和第三列中的值/单词出现次数,其中第一列值相同

输入文件:

GeneA Pathogenic snp
GeneA Pathogenic snp
GeneA Benign indel
GeneA Likely_pathogenic snp
GeneA Pathogenic    indel
GeneB Benign    snp
GeneB Pathogenic    snp
GeneB Benign    indel
GeneC  Benign   snp
GeneC  Likely_pathogenic    snp

预期输出:(表格格式)

| Pathogenic | Benign | Likely_Pathogenic | snp | indel |
 ------------|--------|-------------------|-----|-------|
|GeneA|     3|       1|                  1|    3|      2|
|GeneB|     1|       2|                  0|    2|      1|
|GeneC|     0|       1|                  1|    2|      0|

答案1

如下所示的脚本awk将从给定文件中收集数据,并计算每个“名称”(第一列)中每个“类型”(第二列及以上)出现的次数。它输出一个简单的类似 CSV 的格式,假设所有输入数据均不包含嵌入的逗号,则该格式可以导入到其他程序中。

{
        genes[$1] = 1
        for (i = 2; i <= NF; ++i) {
                types[$i] = 1
                counts[$1,$i]++
        }
}

END {
        OFS = ","

        $0 = "name"
        for (t in types)
                $(NF+1) = header[++n] = t
        print

        for (g in genes) {
                $0 = g
                for (i = 1; i <= n; ++i)
                        $(NF+1) = counts[g,header[i]]+0
                print
        }
}

genes和数组types是包含名称和类型作为键的关联数组。该counts数组计算特定名称和类型在输入中作为对出现的次数。

END块创建并输出标题,然后迭代所有基因名称并输出每种类型收集的计数。

测试这个:

$ awk -f script file
name,indel,Benign,Likely_pathogenic,snp,Pathogenic
GeneA,2,1,1,3,3
GeneB,1,2,0,2,1
GeneC,0,1,1,2,0
$ awk -f script file | column -t -s,
name   indel  Benign  Likely_pathogenic  snp  Pathogenic
GeneA  2      1       1                  3    3
GeneB  1      2       0                  2    1
GeneC  0      1       1                  2    0
$ awk -f script file | csvlook
| name  | indel | Benign | Likely_pathogenic | snp | Pathogenic |
| ----- | ----- | ------ | ----------------- | --- | ---------- |
| GeneA |     2 |      1 |              True |   3 |          3 |
| GeneB |     1 |      2 |             False |   2 |          1 |
| GeneC |     0 |      1 |              True |   2 |          0 |

(如果你不想csvlook要从数据推断类型,请使用它及其-I选项。)

答案2

正如评论框中所说,Ruby 是允许的,我有一个独立的解决方案,它不需要管道不同的程序:

程序

data = <<~'EOF'
    GeneA Pathogenic snp
    GeneA Pathogenic snp
    GeneA Benign indel
    GeneA Likely_pathogenic snp
    GeneA Pathogenic    indel
    GeneB Benign    snp
    GeneB Pathogenic    snp
    GeneB Benign    indel
    GeneC  Benign   snp
    GeneC  Likely_pathogenic    snp
EOF

hash, header1, header2 = {}, [], []

data.each_line { |x|
    fields = x.split("\s")
    field = hash[fields[0].to_sym] ||= [{}, {}]

    field[0].merge!(fields[1] => 1) { |key, val1, val2| val1 + val2 }
    field[1].merge!(fields[2] => 1) { |key, val1, val2| val1 + val2 }
    header1 << fields[1]
    header2 << fields[2]
}

headers = header1.tap(&:uniq!).concat(header2.tap(&:uniq!))
header = '| ' + headers.join(' | ') + ' | '

puts header, ?- * header.length

hash.each { |k, v|
    v0, v1 = v[0], v[1]

    print "| #{k} |"
    headers.each_with_index { |x, i|
        out = "#{(v0[x] || v1[x]).to_i} |"
        print i == 0 ? out.rjust(5) : out.rjust(x.length + 3)
    }
    puts
}

执行:

$ ruby thisFile.rb

输出:

| Pathogenic | Benign | Likely_pathogenic | snp | indel | 
----------------------------------------------------------
| GeneA |  3 |      1 |                 1 |   3 |     2 |
| GeneB |  1 |      2 |                 0 |   2 |     1 |
| GeneC |  0 |      1 |                 1 |   2 |     0 |

您可能会对这些大喊大叫rjust(5)rjust(x.length + 3)因为它们是硬编码的。实际上这些是针对 的' | ',它们也是硬编码的。如果再添加一个空格,则数字会加一。如果数据发生变化,它不会中断。

data <<~EOF...您可以使用 来读取包含数据的文件,而不是使用data = (ARGV[0] && File.readable?(ARGV[0])) ? IO.read(ARGV[0]) : ''- 这里的数据是从作为参数传递的文件名中读取的。应该适用于每个数据,但对齐是根据标题完成的。对该代码进行小的修改可以根据最大字段对齐数据。但现在我认为这会完成你的工作。

相关内容