【问题标题】:Calculate mean of each column ignoring missing data with awk使用 awk 计算忽略缺失数据的每列的平均值
【发布时间】:2016-02-28 12:14:26
【问题描述】:

我有一个以制表符分隔的大型数据表,其中包含数千行和数十列,并且缺少标记为“na”的数据。例如,

na  0.93    na  0   na  0.51
1   1   na  1   na  1
1   1   na  0.97    na  1
0.92    1   na  1   0.01    0.34

我想计算每列的平均值,但要确保在计算中忽略缺失的数据。例如,第 1 列的平均值应为 0.97。我相信我可以使用awk,但我不确定如何构建命令来为所有列执行此操作并解决丢失的数据。

我所知道的只是计算单个列的平均值,但它将丢失的数据视为 0,而不是将其排除在计算之外。

awk '{sum+=$1} END {print sum/NR}' filename

【问题讨论】:

  • 有趣!请edit 显示您到目前为止所做的尝试。我想这已经被类似地问过很多次了。
  • ... 并在给定输入的情况下添加预期输出。
  • 我为一列添加了我知道的代码,但是例如,当在第 1 列上使用时,如果正确忽略丢失的数据,结果应该是 0.97,结果是 0.73
  • 而不是除以 NR,而是构建第二个数组(每个字段一个项目,仅在值可用时递增)。
  • 我该怎么做?我是awk的初学者。

标签: linux bash awk mean missing-data


【解决方案1】:

这很晦涩,但适用于您的示例

awk '{for(i=1; i<=NF; i++){sum[i] += $i; if($i != "na"){count[i]+=1}}} END {for(i=1; i<=NF; i++){if(count[i]!=0){v = sum[i]/count[i]}else{v = 0}; if(i<NF){printf "%f\t",v}else{print v}}}' input.txt

编辑: 工作原理如下:

awk '{for(i=1; i<=NF; i++){ #for each column
        sum[i] += $i;       #add the sum to the "sum" array
        if($i != "na"){     #if value is not "na"
           count[i]+=1}     #increment the column "count"
        }                   #endif
     }                      #endfor
    END {                    #at the end
     for(i=1; i<=NF; i++){  #for each column
        if(count[i]!=0){        #if the column count is not 0
            v = sum[i]/count[i] #then calculate the column mean (here represented with "v")
        }else{                  #else (if column count is 0)
            v = 0               #then let mean be 0 (note: you can set this to be "na")
        };                      #endif col count is not 0
        if(i<NF){               #if the column is before the last column
            printf "%f\t",v     #print mean + TAB
        }else{                  #else (if it is the last column)
            print v}            #print mean + NEWLINE
        };                      #endif
     }' input.txt               #endfor (note: input.txt is the input file)

```

【讨论】:

  • 哦,哇,比我想象的要复杂得多,但看起来效果不错。谢谢!
  • @user2250055 - 这可能是解决这个问题的“蛮力”方法......但我添加了一个解释来解释它是如何工作的
  • 再次感谢...分解对于尝试了解其工作原理以及下次我自己即兴创作更多内容非常有帮助。
【解决方案2】:

一个可能的解决方案:

awk -F"\t" '{for(i=1; i <= NF; i++)
                {if($i == $i+0){sum[i]+=$i; denom[i] += 1;}}}
            END{for(i=1; i<= NF; i++){line=line""sum[i]/(denom[i]?denom[i]:1)FS} 
                print line}' inputFile

给定数据的输出:

0.973333    0.9825  0   0.7425  0.01    0.7125

请注意,第三列仅包含“na”,输出为0。如果您希望输出为na,则将END{...}-block 更改为:

END{for(i=1; i<= NF; i++){line=line""(denom[i] ? sum[i]/denom[i]:"na")FS} print line}'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-19
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    相关资源
    最近更新 更多