0

我有用于从文本文件中提取数据的 bash 和 awk 脚本。
但是,对于大型数据集,它太慢并且不能完美运行。我相信可以在一个 awk 命令中编写我所有的 bash 循环,我请人帮助我解决这个问题。

cat dummy_list 
    AAA
    AAAA
    AAAAA

cat dummy_table
    13   19   AAA   69   96   "ID-999"   34
    23   42   AAA   12   19   "ID-999"   64
    53   79   AAA   43   58   "ID-482"   36
    13   43   AAA   12   15   "ID-492"   75
    23   90   AAA   45   87   "ID-492"   34
    12   41   AAAA   76   79   "ID-923"   23
    19   58   AAAA   15   87   "ID-923"   75
    10   40   AAAA   18   82   "ID-482"   23
    11   18   AAAA   18   82   "ID-482"   52
    15   19   AAAA   18   82   "ID-482"   62
    59   69   AAAA   10   18   "ID-482"   83
    78   89   AAAA   32   41   "ID-983"   24
    23   53   AAAAA  78   99   "ID-916"   82

我想从这张桌子上得到什么:

  1. 对于每个 dummy_list 项目(AAAAAAAAAAAA)提取多少次不同的 ID 范围被提及(我的意思是唯一的列 4+5+6(如69 96 "ID-999"))。有重复的 ID(如18 82 "ID-482"),我必须丢弃它们。
    我的脚本如下所示:

    while read a; do  
        awk -v VAR="$a" '($3==VAR) {print $4"\t"$5"\t"$6}' dummy_table |   
        sort -u |   
        cut -f 3 |  
        sort |   
        uniq -c |   
        awk '{print $1}' |   
        tr '\n' ' ' |   
       awk -v VAR="$a" '{print VAR"\t"$0}'   
    done < dummy_list
    
    AAA     1 2 2 
    AAAA    2 2 1 
    AAAAA   1 
    

    它与 相同AAA "ID-482" mentioned once; "ID-492" mentioned twice; "ID-999" mentioned twice

    这是我想要的输出。

  2. 对于每个 dummy_list 项目,获取使用相同 ID 提及它的平均次数。例如AAA,出现两次"ID-999",一次出现,"ID-482"两次出现"ID-492"- 所以它是 (2+1+2)/3=1.66

    我的脚本如下所示:

    while read a ; do  
        ID_TIMES=$(awk -v VAR="$a" '($3==VAR) {print $6}' dummy_table | 
           sort -u | 
            wc -l) && 
        awk -v  VAR="$a" '($3==VAR) {print $6}' dummy_table | 
        sort | 
        uniq -c | 
        awk -v VAR="$ID_TIMES" '{sum+=$1} END {print sum/VAR}' 
    done < dummy_list
    
    AAA   1.666  
    AAAA  2.333
    AAAAA 1
    
  3. 对于每个 dummy_list 项目,提取 ID 范围并计算列之间的比例。例如: 对于这样的输出:
    for AAA's ID-999:
    RANGE1=sum $5-$4(96-69) + $5-$4(19-12)
    RANGE2=sum $7(34+64)
    then RANGE2*100/RANGE1=288

    AAA 288 240 242 
    ....
    AAAAA 390
    

    我无法自己编写这样的脚本,因为我遇到了两个变量 $RANGE1 和 $RANGE2。
    如果可能的话,也可以像18 82 "ID-482"在此步骤中那样丢弃重复的范围。

我相信所有这些操作都可以只用一个awk命令来计算,我对我的脚本感到绝望。我真的希望有人能在这次手术中帮助我。

4

2 回答 2

2

你可以试试这个。

文件 a.awk:

BEGIN {

    # read list of items

    while ( ( getline < "dummy_list" ) > 0 )
    {
        items[$1] = 0    
    }
}

{
    # calculate ammountof uniqur ids

    key = $3 SUBSEP $6

    if ( ! ( key in ids ) && ( $3 in items ) )
    {
        unique_ids[$3] += 1 
    }


    # calculate ammount of duplication

    ids [$3,$6] += 1 


    # calculate range parameters 

    range1 [$3,$6] += $5 - $4
    range2 [$3,$6] += $7 
}

END {

    for ( item in items )
    {
        print "--- item = " item " ---\n"

        for ( key in ids )
        {
            split ( key, s, SUBSEP );

            if ( s[1] != item ) continue;    

            range = range2[key] * 100 / range1[key] 

            average[item] += float ( ids[key] ) / unique_ids[item];

            print "id = " s[2] "\tammount of dup = " ids[key] "  range = " int ( range )
        }    

        print "\naverage = " average[item] "\n"
    }
}

跑:

awk -f a.awk dummy_table

输出:

--- item = AAAA ---

id = "ID-983"   ammount of dup = 1  range = 266
id = "ID-923"   ammount of dup = 2  range = 130
id = "ID-482"   ammount of dup = 4  range = 110

average = 2.33333

--- item = AAAAA ---

id = "ID-916"   ammount of dup = 1  range = 390

average = 1

--- item = AAA ---

id = "ID-999"   ammount of dup = 2  range = 288
id = "ID-482"   ammount of dup = 1  range = 240
id = "ID-492"   ammount of dup = 2  range = 242

average = 1.66667

有一瞬间——我不明白你是如何得到 225 的“ID-482”和问题 3 中的项目 AAA。

RANGE2 * 100 / RANGE1 = 36 * 100 / ( 58 - 43 ) = 240.

您确定您在问题 #3 上的示例是正确的吗?

于 2013-06-12T17:05:15.707 回答
1

只有部分答案,但这里是您的第一个问题的单线解决方案:

  awk -F'   ' '{group[$3]++;ind[$6]++};{count[$3][$6]+=1}; END{for (i in group){for (j in ind) if(count[i][j] > 0) print i, j, count[i][j]}}' dummy_variable.txt 

输出:

AAA "ID-482" 1  
AAA "ID-999" 2  
AAA "ID-492" 2    
AAAA "ID-923" 2  
AAAA "ID-482" 4  
AAAA "ID-983" 1  
AAAAA "ID-916" 1

然后,使用此输出来计算第二个问题的答案相当简单。

于 2013-06-12T18:46:40.040 回答