Re: [問題] 資料的截取與邏輯判斷

作者: rickieyang (Rickie Yang)   2018-06-29 11:31:09
※ 引述《egoweaver (Hiko)》之銘言:
: 啊,打完發現我不是在隔壁版。補個 Linux 點。用 awk 的話其實也滿快的:
: # 計算 A_1 與 A_2 相同的列數 (若它們分別為第一第二欄)
: awk '$1 == $2 {i++}END{print i}' [your raw data]
: # 計算 A_1 與 A_2 都同樣是 ./. 的列數
: awk '$1 == "./." && $2 == "./." {i++}END{print i}' [your raw data]
: # 計算 A_1 與 A_2 不相同的列數
: awk '$1 != $2 {i++}END{print i}' [your raw data]
: # 計算每列中有幾個 "./."
: awk '{for(i = 1; i <= NF; i++) {if($i == "./.") n++}; \
: print n >> "number.txt";}' [your raw data]
: # 如果要把 "./." 的個數當作一欄併回原檔案
: paste [your raw data] number.txt >> newfile.txt
: ※ 引述《k97231 (AL)》之銘言:
: : 基本上的資料格式長這樣
: : ID A_1 A_2 B_1 B_2 ……
: : 1 0/0 0/0
: : ……
: : 依據相同字母的樣本(像是A_1和A_2)
: : 逐列統計四種欄位的數量
: : 1. A_1和A_2相同
: : 2. A_1和A_2都一樣是./.
: : 3. A_1和A_2不一樣
: : 4. 以及任一樣本含有./.的欄位數量
這類型的統計用 awk 還真的滿簡單的.
不過麻煩的是在這一句 「依據相同字母的樣本(像是A_1和A_2)」
也就是 A_1 跟 A_2 統計, B_1 跟 B_2 統計, 是吧?
如果需要統計的欄位很多 (ex: A_1...Z_1), 那就比較煩一點..
考慮單一個資料來說.
無腦的把條件直接寫下來
SCREEN:working rickie$ cat stats.awk
BEGIN{
cnt_match=0;
cnt_dot_match=0;
cnt_dot=0;
cnt_not_match=0;
}
(NR > 1){
if ( $2 == $3 ) {cnt_match++;}
if ( $2 == $3 && $2 == "./." ) {cnt_dot_match++;}
if ( $2 == "./." || $3 == "./." ){cnt_dot++;}
if ( $2 != $3 ) {cnt_not_match++;}
}
END{
printf(" A_1 = A_2 : %d\n",cnt_match);
printf(" A_1 = A_2 = ./. : %d\n",cnt_dot_match);
printf("A_1 or A_2 = ./. : %d\n",cnt_dot);
printf(" A_1 != A_2 : %d\n",cnt_not_match);
}
從你的 raw data 複製了一份 600 萬筆資料的檔案
SCREEN:working rickie$ wc -l temp2.dat
6000001 temp2.dat
試跑一下
SCREEN:working rickie$ time awk -f stats.awk temp2.dat
A_1 = A_2 : 3000000
A_1 = A_2 = ./. : 1000000
A_1 or A_2 = ./. : 2000000
A_1 != A_2 : 3000000
real 0m10.119s
user 0m9.940s
sys 0m0.065s
稍微優化一下
SCREEN:working rickie$ cat stats2.awk
BEGIN{
cnt_match=0;
cnt_dot_match=0;
cnt_dot=0;
cnt_not_match=0;
}
(NR > 1){
if ( $2 == $3 ) {
cnt_match++;
if ($2 == "./." ) {
cnt_dot_match++;
cnt_dot++;
}
} else {
cnt_not_match++;
if ( $2 == "./." || $3 == "./." ){cnt_dot++;}
}
}
END{
printf(" A_1 = A_2 : %d\n",cnt_match);
printf(" A_1 = A_2 = ./. : %d\n",cnt_dot_match);
printf("A_1 or A_2 = ./. : %d\n",cnt_dot);
printf(" A_1 != A_2 : %d\n",cnt_not_match);
}
再跑一次
SCREEN:working rickie$ time awk -f stats2.awk temp2.dat
A_1 = A_2 : 3000000
A_1 = A_2 = ./. : 1000000
A_1 or A_2 = ./. : 2000000
A_1 != A_2 : 3000000
real 0m4.999s
user 0m4.937s
sys 0m0.044s
如果可以不要檔頭, 那 (NR > 1) 這個判斷拿掉, 可以再少一點點時間
SCREEN:working rickie$ time awk -f stats3.awk temp3.dat
A_1 = A_2 : 3000000
A_1 = A_2 = ./. : 1000000
A_1 or A_2 = ./. : 2000000
A_1 != A_2 : 3000000
real 0m4.805s
user 0m4.749s
sys 0m0.039s
大概是醬~
還有 awk 變數其實不用預先宣告, BEGIN 裡其實可以省略
單純只是個人強迫症發作...
作者: liusim (六四母)   2017-02-13 12:03:00
我覺得應該還是念雪藏 你們不覺得念雪藏怪怪的嗎?
作者: ispy03532003 (臭酸肥它)   2017-02-13 12:04:00
原來如此 要唸"藏"阿 之前都一直講"藏"
作者: koster (斯特隆)   2017-02-13 12:06:00
我真的不知道要念雪藏 一直都以為念雪藏是對的 長知識了
作者: pkmu8426 (巴426)   2017-02-13 12:11:00
其實藏和藏都是錯的 只有藏才是對的
作者: Eternity424 (航海王翊)   2017-02-13 12:16:00
幹你娘 你們都打藏誰知道講哪個音
作者: k97231 (AL)   2018-07-02 22:58:00
這個好像執行上似乎會更快一點 來研究一下 awk 感謝

Links booklink

Contact Us: admin [ a t ] ucptt.com