You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改Bash脚本补0至指定行数以修正统计偏差

问题描述

我有一段用于计算平均值、标准差、中位数、最小值和最大值的命令行代码:

cut -f3 $file | sort -n | awk 'BEGIN {c = 0; sum = 0;} $1 ~ /^(\-)?[0-9]*(\.[0-9]*)?$/ {a[c++] = $1; sum += $1; sumsq+=$1*$1} END {ave = sum / c; if( (c % 2) == 1 ) { median = a[ int(c/2) ]; } else {median = ( a[c/2] + a[c/2-1] ) / 2; } OFS="\t"; sd = sqrt(sumsq/c - (sum/c)**2); print ave, sd, median, a[0], a[c-1]; }' >> $output

每个文件应包含772474283行,但很多文件不满足该条件,导致统计结果出现偏差。因此我需要在提取第三列后补充0值,使总行数达到指定数量,让0参与平均值、标准差等统计计算。我考虑先通过wc -l计算文件行数,再补充X个0(X=772474283-现有行数),请问该如何实现?或者有没有更优雅的方法?


解决方案

方案一:按分步思路实现

先提取第三列并过滤有效数字行,统计行数后补充对应数量的0,再执行统计:

# 定义目标总行数
TARGET=772474283

# 临时文件存储有效数字行
tmp_file=$(mktemp)
cut -f3 "$file" | awk '$1 ~ /^(\-)?[0-9]*(\.[0-9]*)?$/' > "$tmp_file"

# 计算当前有效行数和需要补充的0的数量
current_lines=$(wc -l < "$tmp_file")
add_lines=$((TARGET - current_lines))

# 补充0并执行统计流程
cat "$tmp_file" \
  | awk -v n="$add_lines" 'BEGIN{for(i=0;i<n;i++) print 0} {print}' \
  | sort -n \
  | awk 'BEGIN {c = 0; sum = 0; sumsq=0} 
         {a[c++] = $1; sum += $1; sumsq+=$1*$1} 
         END {
             ave = sum / c; 
             if( (c % 2) == 1 ) { 
                 median = a[ int(c/2) ]; 
             } else {
                 median = ( a[c/2] + a[c/2-1] ) / 2; 
             } 
             OFS="\t"; 
             sd = sqrt(sumsq/c - (sum/c)**2); 
             print ave, sd, median, a[0], a[c-1]; 
         }' >> "$output"

# 清理临时文件
rm "$tmp_file"

注意:这里先过滤非数字行再统计行数,确保补充的0是基于有效数据的数量计算,和原逻辑保持一致。

方案二:一站式awk处理(更高效优雅)

将提取第三列、过滤数字、补充0、统计逻辑合并到一个awk脚本中,仅扫描文件一次,大幅提升大文件处理效率:

TARGET=772474283

awk -v target="$TARGET" -F'\t' '
BEGIN {c = 0; sum = 0; sumsq=0}
# 处理第三列的有效数字行
$3 ~ /^(\-)?[0-9]*(\.[0-9]*)?$/ {
    a[c++] = $3; 
    sum += $3; 
    sumsq += $3*$3;
}
END {
    # 计算需要补充的0的数量
    add = target - c;
    # 把0纳入统计总和
    sum += add * 0;
    sumsq += add * 0*0;
    total = c + add;
    
    # 合并原有数据和补充的0并排序
    for(i=0;i<add;i++) {
        a[c+i] = 0;
    }
    n = asort(a);
    
    # 计算中位数
    if(n % 2 == 1) {
        median = a[int(n/2)];
    } else {
        median = (a[n/2] + a[n/2 - 1])/2;
    }
    
    # 计算平均值和标准差
    ave = sum / total;
    sd = sqrt(sumsq/total - (sum/total)**2);
    
    # 输出结果
    OFS="\t";
    print ave, sd, median, a[0], a[n-1];
}' "$file" >> "$output"

该方案优势:

  • 仅扫描文件一次,避免多次IO操作,大文件处理速度更快
  • 无需临时文件,逻辑紧凑
  • 减少管道调用开销,性能更优

内容的提问来源于stack exchange,提问作者user236152

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 19:39:52