Как рассчитать среднее значение строки из CSV-файла из n-го столбца? - PullRequest
0 голосов
/ 22 октября 2018

Это может выглядеть как дубликат, но я не могу решить проблему, с которой я сталкиваюсь.

Я пытаюсь найти среднее значение каждого столбца из файла 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

output.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

Я попробовал предложение от здесь

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

помогите решить проблему, чтобы вычислить среднее значение по строке

Ответы [ 5 ]

0 голосов
/ 22 октября 2018

Использование 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
>
0 голосов
/ 22 октября 2018
$ 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
0 голосов
/ 22 октября 2018

Это будет работать так, как ожидалось:

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
0 голосов
/ 22 октября 2018

Ссылка на ваш код:

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 

С вашим вторым кодом нелегко работать, много подоболочек (backtic) и цикла оболочки, но больше всего, я думаю, он создан для работы с целочисленными значениямии для полной строки значения (не 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), если в строке меньше значения и пустоне считая

0 голосов
/ 22 октября 2018

Вы можете использовать этот скрипт 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-го элемента.

Второй блок печатает строку заголовкаа среднее значение.

column -t отображает результат в столбце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...