генерация таблицы частот из файла

Учитывая входной файл, содержащий одно единственное число в строке, как я могу подсчитать, сколько раз элемент встречается в этом файле?

cat input.txt
1
2
1
3
1
0

желаемый результат (=>[1,3,1,1]):

cat output.txt
0 1
1 3
2 1
3 1

Было бы здорово, если бы решение можно было расширить и для чисел с плавающей запятой.


person Javier    schedule 18.05.2011    source источник


Ответы (7)


Вы имеете в виду, что хотите подсчитать, сколько раз элемент появляется во входном файле? Сначала отсортируйте его (используя -n, если входные данные всегда являются числами, как в вашем примере), затем подсчитайте уникальные результаты.

sort -n input.txt | uniq -c
person Caleb    schedule 18.05.2011
comment
Я не знал о команде uniq. Я изменил его на cat input.txt | sort -n | uniq -c | awk '{print $2 " " $1}', теперь я получаю желаемый результат. - person Javier; 18.05.2011
comment
Вы используете awk для получения порядка, но вам не нужно использовать cat там. Вы должны узнать об операторе < для ввода файлов в программы и даже о таких вещах, как конструкции циклов. Для юмора см. бесполезное использование кошачьих наград - person Caleb; 18.05.2011

Другой вариант:

awk '{n[$1]++} END {for (i in n) print i,n[i]}' input.txt | sort -n > output.txt
person glenn jackman    schedule 18.05.2011
comment
@Javier, массив 'n' просто ведет подсчет строк, которые он видит во входном файле. Это может быть int, float или любая произвольная строка. Да, часть 'END' выполняется после того, как входной файл будет полностью прочитан. Вам не нужно инициализировать переменные в awk: неинициализированная переменная считается нулевой или пустой строкой (зависит от контекста). В этом случае «i» — это переменная цикла. Я думаю, что поведение «сортировки» по умолчанию заключается в рассмотрении всей строки. Это решение будет работать для всего во входном файле: массивы awk являются ассоциативными массивами. - person glenn jackman; 18.05.2011
comment
спасибо за иллюстрацию решения awk-based. Насколько я понял, в первой части вы сохраняете histogram в массив n с учетом элементов в столбце $1. Часть END означает, что будет сделано after гистограмма построена, верно? Не нужно ли инициализировать переменную i для циклов в awk? Тогда sort -n будет применяться только в первом столбце вывода: i, n[i], верно? то есть не на n[i]? Кроме того, это решение будет работать только для integer чисел (из-за индексации массива)? - person Javier; 18.05.2011
comment
Решение awk имеет явное преимущество, поскольку не требует sort! Чтобы получить отсортированный вывод, просто следите за видимыми максимальными и минимальными значениями и перебирайте их, проверяя, есть ли они в массиве. (Однако это будет работать только для целых чисел, а не для чисел с плавающей запятой.) - person William Pursell; 26.09.2012
comment
Со струнами тоже отлично работает! Просто нужно изменить $1, первое слово, на $0, всю строку: awk '{n[$0]++} END {for (i in n) print i,n[i]}' позволяет легко находить и подсчитывать повторяющиеся строки во вводе. Потрясающий. - person Ahmed Fasih; 04.11.2014
comment
Я только что удалил комментарий, в котором я сказал, что столкнулся с ошибкой в ​​​​решении на основе awk. На самом деле это была ошибка в моем коде. Поскольку другие тоже могут это сделать, я подумал, что было бы полезно поделиться здесь своим опытом: моя проблема заключалась в том, что, вероятно, под влиянием синтаксиса оболочки для цикла for, я добавил ; между for и print в конце команды awk. В результате цикл for ничего не делал, а действие печати использовало только последнее значение i. - person bli; 01.03.2016

Использование maphimbu из пакета Debian stda:

# use 'jot' to generate 100 random numbers between 1 and 5
# and 'maphimbu' to print sorted "histogram":
jot -r 100 1 5 | maphimbu -s 1

Выход:

             1                20
             2                21
             3                20
             4                21
             5                18

maphimbu также работает с плавающей запятой:

jot -r 100.0 10 15 | numprocess /%10/ | maphimbu -s 1

Выход:

             1                21
           1.1                17
           1.2                14
           1.3                18
           1.4                11
           1.5                19
person agc    schedule 31.12.2016

По крайней мере, что-то из этого можно сделать с помощью

sort output.txt | uniq -c

Но порядок number count обратный. Это решит эту проблему.

sort test.dat | uniq -c | awk '{print $2, $1}'
person pavium    schedule 18.05.2011
comment
Если элементы в первом столбце имеют разную длину, это немного испортит выравнивание, поэтому вы можете использовать табуляцию вместо пробела по умолчанию при изменении порядка столбцов:sort test.dat | uniq -c | awk '{print $2"\t"$1}' - person PeterVermont; 05.12.2013


perl -lne '$h{$_}++; END{for $n (sort keys %h) {print "$n\t$h{$n}"}}' input.txt

Зациклить каждую строку с помощью -n
Каждое число $_ увеличивает хэш %h
Как только будет достигнуто END из input.txt,
sort {$a <=> $b} хэш численно
Выведите число $n и частоту $h{$n}

Аналогичный код, который работает с плавающей запятой:

perl -lne '$h{int($_)}++; END{for $n (sort {$a <=> $b} keys %h) {print "$n\t$h{$n}"}}' float.txt

поплавок.txt

1.732
2.236
1.442
3.162
1.260
0.707

выход:

0       1
1       3
2       1
3       1
person Chris Koknat    schedule 22.09.2015
comment
sort keys %h использует лексикографическую сортировку; он не сортируется численно. - person melpomene; 04.09.2018

У меня была аналогичная проблема, как описано, но через гигабайты файлов журнала gzip. Поскольку многие из этих решений требовали ожидания, пока все данные не будут проанализированы, я решил написать rare для быстрого анализа и агрегировать данные на основе регулярного выражения.

В приведенном выше случае это так же просто, как передать данные в функцию гистограммы:

rare histo input.txt
# OR
cat input.txt | rare histo

# Outputs:
1                   3         
0                   1         
2                   1         
3                   1

Но он также может обрабатывать более сложные случаи с помощью регулярных выражений/выражений, например:

rare histo --match "(\d+)" --extract "{1}" input.txt
person zix99    schedule 31.05.2021