如何用AWK计算多样本逗号分隔值的对应位置均值(忽略点)
问题描述
我有以下空格分隔的数据:
SampleX=1,1,2,3 SampleY=1,1,2,3 SampleZ=1,1,2,3 SampleX=0,0,0,1 SampleY=.,.,.,. SampleZ=0,1,1,1
需要对每行做汇总,计算所有样本中对应位置值的均值,忽略点(.)。比如第一行有3个样本,每个含4个值,对应位置的期望输出如下:
A B C D 1 1 2 3 0 0.5 0.5 1
我之前用AWK实现过类似的统计,但当时是做事件计数:
计数场景输入数据
SampleX=1/1 SampleY=0/0 SampleZ=1/1 SampleX=0/1 SampleY=./. SampleZ=1/0
计数规则
0/0记为A1/0或0/1记为B1/1记为C
计数结果
A B C 1 0 2 0 2 0
当时使用的AWK命令
echo "SampleA=1/1 SampleB=0/0 SampleC=1/1 SampleA=0/1 SampleB=./. SampleC=1/0" | awk 'BEGIN {OFS="\t"; print "A\tB\tC"} {B=gsub(/0\|1|1\|0|0\/1|1\/0/, ""); A=sub(/1\|1|1\/1/, ""); C=gsub(/0\|0|0\/0/, ""); print A,B,C}'
但我不知道怎么修改这个命令,来处理逗号分隔的值并计算均值。
解决方案
可以用下面的AWK命令实现需求,代码会逐行处理每个样本的逗号分隔值,忽略.并计算对应位置的均值:
echo "SampleX=1,1,2,3 SampleY=1,1,2,3 SampleZ=1,1,2,3 SampleX=0,0,0,1 SampleY=.,.,.,. SampleZ=0,1,1,1" | awk ' BEGIN { OFS=" " # 输出表头 print "A B C D" } { # 初始化每行的总和、计数数组,清空上一行残留数据 split("", sums) split("", counts) # 遍历当前行的每个样本(空格分隔的字段) for (i=1; i<=NF; i++) { # 拆分样本标识和值列表 split($i, kv, "=") # 把值列表拆成单个元素 split(kv[2], vals, ",") # 逐个处理每个位置的值 for (j=1; j<=length(vals); j++) { if (vals[j] != ".") { sums[j] += vals[j] counts[j]++ } } } # 拼接均值结果行 line = "" for (j=1; j<=length(sums); j++) { if (counts[j] > 0) { mean = sums[j] / counts[j] # 整数输出整数,非整数保留一位小数(可按需调整精度) line = line (mean == int(mean) ? int(mean) : mean) " " } else { # 全为.的情况可自定义输出,这里留空 line = line " " } } # 去掉末尾多余空格后输出 sub(/ $/, "", line) print line }'
代码逻辑说明
- 初始化阶段:在
BEGIN块设置输出分隔符为空格,打印表头A B C D。 - 逐行处理:
- 每次处理新行前,重置总和
sums和计数counts数组,避免上一行数据干扰。 - 遍历当前行的每个样本字段,拆分出每个样本的数值列表。
- 对每个位置的数值,若不是
.就累加到对应位置的总和,并增加计数。
- 每次处理新行前,重置总和
- 计算并输出均值:遍历每个位置,用总和除以计数得到均值,处理整数和小数的显示格式,最后拼接成一行输出。
运行该命令后,输出结果与期望完全一致:
A B C D 1 1 2 3 0 0.5 0.5 1
内容的提问来源于stack exchange,提问作者Gabriel G.
相关产品推荐
相关产品推荐

