2013-06-12 51 views
0

我有bash和awk腳本,用於從文本文件中提取數據。
但是,對於大型數據集來說太慢了,並且不能很好地工作。我相信有可能在一個awk命令中寫下我所有的bash循環,並且請求有人幫助我解決這個問題。awk腳本循環和執行數學運算

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命令來計算,我感到絕望關於我的腳本。我真的希望有人能幫助我做這個手術。

+0

您是否考慮過使用關係數據庫? – 2013-06-12 18:55:35

+0

這就是爲什麼我需要所有這些數據提取。 – PoGibas

回答

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中的示例正確嗎?

+0

我的錯誤 - 必須手動計算百分比,我編輯了我的問題。 – PoGibas

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 

它是那麼公平地使用trivil這個輸出算出答案到你的第二個問題。

+0

'while read a; (NUMBER)= $(grep -w $ a OUTPUT | awk'{print $ 2}'| sort -u | wc -l)&& awk -v ID =「$ a」-v NUMBER =「$ NUMBER」'($ 1 = = ID){sum + = $ 3} END {print sum/NUMBER}'OUTPUT;完成 PoGibas