【问题标题】:How to calculate the mean of row from csv file from nth column?如何从第 n 列计算 csv 文件中行的平均值?
【发布时间】:2019-03-26 14:04:41
【问题描述】:

这可能看起来像重复,但我无法解决我遇到的问题。

我正在尝试从 CSV/TSV 文件中查找每列的平均值,数据如下所示:

input.tsv

ID  source  random  text val1 val2 val3 val4 val330
1   atttt   eeeee   test 0.9  0.5  0.2  0.54 0.89
2   afdg    adfgrg  tf   0.6  0.23 0.5  0.4  0.29

输出.tsv

ID  source  random  text Avg
1   atttt   eeeee   test 0.606
2   afdg    adfgrg  tf   0.404

或至少

ID  Avg
1   0.606
2   0.404

我尝试了here的建议

awk 'NR==1{next}
{printf("%s\t", $1
printf("%.2f\n", ($5 + $6 + $7)/3}' input.tsv 

这引发了错误。

awk '{ s = 4; for (i = 5; i <= NF; i++) s += $i; print $1, (NF > 1) ? s / (NF - 1) : 0; }' input.tsv

下面的代码也抛出了语法错误

for i in `cat input.tsv` do; VALUES=`echo $i | tr '\t' '\t'`;COUNT=0;SUM=0;typeset -i j;IFS=' ';for j in $VALUES; do;SUM=`expr $SUM + $j`;COUNT=`expr $COUNT + 1`;done;AVG=`expr $SUM / $COUNT`;echo $AVG;done

帮我解决计算行平均值的问题

【问题讨论】:

    标签: shell perl unix awk text-processing


    【解决方案1】:

    使用 Perl 单行代码

    > perl -lane '{ $s=0;foreach(@F[4..8]){$s+=$_} $F[4]=$s==0?"Avg":$s/5;print "$F[0]\t$F[1]\t$F[2]\t$F[3]\t$F[4]" } ' input.tsv 
    ID      source  random  text    Avg
    1       atttt   eeeee   test    0.606
    2       afdg    adfgrg  tf      0.404
    >
    

    【讨论】:

    • 为什么不在 perl 中直接打印制表符而不是逗号?
    【解决方案2】:

    你可以使用这个awk 脚本:

     awk 'NR>1{
            for(i=5;i<=NF;i++)
              sum+=$i
          }
          {
            print $1,$2,$3,$4,(NF>4&&sum!=""?sum/(NF-4):(NR==1?"Avg":""))
            sum=0
          }' file | column -t
    

    第一个块获取从第 5 个元素开始的所有 id 的总和。

    第二个块,打印标题行和平均值。

    column -t 在列中显示结果。

    【讨论】:

    • 似乎我在尝试运行命令时出错:awk: cmd. line:5: (FILENAME=only_t.tsv FNR=20) fatal: 除零尝试
    • @PradyumnaSagar 这发生在没有价值的行上。请查看我的更新答案。
    【解决方案3】:
    $ cat tst.awk
    NR == 1 { avg = "Avg" }
    NR > 1 {
        sum = cnt = 0
        for (i=5; i<=NF; i++) {
            sum += $i
            cnt++
        }
        avg = (cnt ? sum / cnt : 0)
    }
    { print $1, $2, $3, $4, avg }
    
    $ awk -f tst.awk file
    ID source random text Avg
    1 atttt eeeee test 0.606
    2 afdg adfgrg tf 0.404
    

    【讨论】:

      【解决方案4】:

      这将按预期工作:

      awk 'BEGIN{OFS="\t"}
           (NR==1){ print $1,$2,$3,$4,"Avg:"; next }
           { s=0; for(i=5;i<=NF;++i) s+=$i }
           { print $1,$2,$3,$4, (NF>4 ? s/(NF-4) : s) }' input.tsv
      

      或者只是为了好玩,如果你想让 for 循环混淆:

      awk 'BEGIN{OFS="\t"}
           (NR==1){ print $1,$2,$3,$4,"Avg:"; next }
           { for(s=!(i=5);i<=NF;s+=$(i++)) {} }
           { print $1,$2,$3,$4, (NF>4 ? s/(NF-4) : s) }' input.tsv
      

      【讨论】:

      • 您好,代码在我采用的示例文件上工作,但在原始文件上它给出了非法除零,对此有什么想法吗?原始文件有 189532 列。
      • awk:cmd。 line:3: (FILENAME=only_t.tsv FNR=20) fatal: 除零尝试。
      • 如何增加FNR
      • (NF ? NF : 1)更改最后一个NF
      • awk:cmd。 line:3: { 打印 $1,$2,$3,$4,NF>4? s/((NF ? NF : 1)-4):s } awk: cmd. line:3: ^ 语法错误
      【解决方案5】:

      来自您的代码参考:

      awk 'NR==1{next}
         {
         # missing the last ). This print the 1st column
         #printf("%s\t", $1
          printf("%s\t", $1 )
      
         # missing the last ) and average of 3 colum only
         #printf("%.2f\n", ($5 + $6 + $7)/3
          printf("%.2f\n", ($5 + $6 + $7 + $8 + $9) / 5 )
         }' input.tsv 
      

      您的第二个代码不容易使用,有很多子shell(backtic)和shell循环,但最重要的是,我认为它是为处理整数值和整行值(不是5-> 9)而设计的。除非在这种情况下您不想要 awk,否则请忘记它。

      为了好玩

      awk 'NR==1{
              # Header
              print $0 OFS "Avg"
              Count = NF - 5
              next
              }
              {
              # print each element of the line + sum after col 4
              for( i=Avg=0;i<=NF;i++) {
                 if( i >=5 ) Avg+= $i
                 printf( "%s ", $i)
                 }
              # print average
               printf( "%.2f\n", Avg/Count )
              }
         ' input.tsv
      

      这里假设它总是计算整个堆栈的值,我们可以将计数更改为(NF - 4),如果行上的值较少并且不计算空值

      【讨论】:

      • 我喜欢你 for(i=Avg=0; ...) 的做法。如果您执行 for(Avg=!(i=5); ...),则可以在 for 循环中删除 if 语句
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-04
      • 2014-05-30
      • 2015-01-08
      • 2021-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多