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