Средние строки с одинаковым первым столбцом

Для файла с двумя столбцами:

Id ht 510 69 510 67 510 65 510 62 510 59 601 29 601 26 601 21 601 20 

Мне нужен способ объединить все строки с одинаковым идентификатором в один, который имеет среднюю высоту. В этом случае (69 + 67 + 65 + 62 + 59) / 5 = 64 и (29 + 26 + 21 + 20) / 4 = 24, поэтому выход должен быть:

  • Linux эквивалентен удалению PowerShell «один ко многим»
  • раскол столбца после n-го символа
  • Почему более новые версии awk печатают большие целые числа вместо десятичных знаков?
  • Объединить столбцы с одинаковым значением с awk
  • unix: получить символы от 10 до 80 в файле
  • awk + печатать строки с первой строки до слова соответствия
  •  Id Avg.ht 510 64 601 24 

    Как я могу это сделать с помощью sed / awk / perl?

  • Добавить расширение в список файлов
  • Сравните 2 файла с разделителями табуляции и выходных различий с заголовком столбца
  • переименование каталога и его поддиректоров, не затрагивая их файлы
  • Специальный символ '#' в команде Perl SSH
  • Последствия для безопасности работы perl -ne '...' *
  • Разделить текстовый файл на строки с фиксированным числом слов
  • 4 Solutions collect form web for “Средние строки с одинаковым первым столбцом”

    Использование awk:

    Входной файл

     $ cat FILE Id ht 510 69 510 67 510 65 510 62 510 59 601 29 601 26 601 21 601 20 

    Awk в оболочке:

     $ awk ' NR>1{ arr[$1] += $2 count[$1] += 1 } END{ for (a in arr) { print "id avg " a " = " arr[a] / count[a] } } ' FILE 

    Или с Perl в оболочке:

     $ perl -lane ' END { foreach my $key (keys(%hash)) { print "id avg $key = " . $hash{$key} / $count{$key}; } } if ($. > 1) { $hash{$F[0]} += $F[1]; $count{$F[0]} += 1; } ' FILE 

    Выход:

     id avg 601 = 24 id avg 510 = 64.4 

    И последнее для шутки, Perl темно-обфускации однострочный =)

     perl -lane'END{for(keys(%h)){print"$_:".$h{$_}/$c{$_}}}($.>1)&&do{$h{$F[0]}+=$F[1];$c{$F[0]}++}' FILE 
     #!/usr/bin/perl use strict; use warnings; my %sum_so_far; my %count_so_far; while ( <> ) { # Skip lines that don't start with a digit next if m/^[^\d]/; # Accumulate the sum and the count my @line = split(); $sum_so_far{$line[0]} += $line[1]; $count_so_far{$line[0]} += 1; } # Dump the output print "Id Avg.ht\n"; foreach my $id ( keys %count_so_far ) { my $avg = $sum_so_far{$id}/$count_so_far{$id}; print " $id $avg\n"; } 

    Вывод:

     ire@localhost$ perl make_average.pl input.txt Id Avg.ht 510 64.4 601 24 

    Обратите внимание, что ваш результат выборки неправильный. Вы не можете получить среднее значение из 52, когда каждое значение для этого идентификатора равно 59 или больше.

    Кроме того, у вас есть буква l в одной из ваших колонок, маскировка под номером 1

    Взгляните на то, что делается здесь: http://www.sugihartono.com/programming/group-by-count-and-sorting-using-perl-script/

    Существенной трудной частью является операция «группа за». Связанный скрипт делает это с использованием хэша.

    В этой ссылке они вычисляют сумму, но получение среднего значения не будет сильно отличаться.

    С gnu datamash :

     datamash -H -s -g 1 mean 2 <file 
      GroupBy (Id) означает ()
     510 64,4
     601 24 

    Это указывает и g roups на 1 -ое поле, вычисляя mean значение 2 поля, сохраняя H eaders. Предполагается, что поля разделяются одной вкладкой. Используйте -W, --whitespace если они разделены несколькими пробелами или -t, --field-separator= для определения другого разделителя полей (пробел, запятая и т. Д.). Поскольку datamash требует отсортированного ввода, вывод будет отсортирован по сгруппированному столбцу.

    Linux и Unix - лучшая ОС в мире.