Подтвердить что ты не робот

Получение количества уникальных значений в столбце в bash

У меня есть файлы с разделителями табуляции с несколькими столбцами. Я хочу рассчитать частоту появления разных значений в столбце для всех файлов в папке и отсортировать их в порядке убывания количества (сначала подсчитывать счетчик). Как я могу выполнить это в среде командной строки Linux?

Он может использовать любой обычный язык командной строки, такой как awk, perl, python и т.д.

4b9b3361

Ответ 1

Чтобы увидеть частоту отсчета для столбца два (например):

awk -F '\t' '{print $2}' * | sort | uniq -c | sort -nr

fileA.txt

z    z    a
a    b    c
w    d    e

fileB.txt

t    r    e
z    d    a
a    g    c

fileC.txt

z    r    a
v    d    c
a    m    c

Результат:

  3 d
  2 r
  1 z
  1 m
  1 g
  1 b

Ответ 2

Вот как это сделать в оболочке:

FIELD=2
cut -f $FIELD * | sort| uniq -c |sort -nr

Это что-то вроде bash отлично.

Ответ 3

Сайт GNU предлагает этот приятный awk script, который печатает как слова, так и их частоту.

Возможные изменения:

  • Вы можете пропустить через sort -nr (и наоборот word и freq[word]), чтобы увидеть результат в порядке убывания.
  • Если вам нужен конкретный столбец, вы можете опустить цикл for и просто написать freq[3]++ - заменить 3 номером столбца.

Здесь:

 # wordfreq.awk --- print list of word frequencies

 {
     $0 = tolower($0)    # remove case distinctions
     # remove punctuation
     gsub(/[^[:alnum:]_[:blank:]]/, "", $0)
     for (i = 1; i <= NF; i++)
         freq[$i]++
 }

 END {
     for (word in freq)
         printf "%s\t%d\n", word, freq[word]
 }

Ответ 4

Perl

Этот код вычисляет вхождения всех столбцов и печатает отсортированный отчет для каждого из них:

# columnvalues.pl
while (<>) {
    @Fields = split /\s+/;
    for $i ( 0 .. $#Fields ) {
        $result[$i]{$Fields[$i]}++
    };
}
for $j ( 0 .. $#result ) {
    print "column $j:\n";
    @values = keys %{$result[$j]};
    @sorted = sort { $result[$j]{$b} <=> $result[$j]{$a}  ||  $a cmp $b } @values;
    for $k ( @sorted ) {
        print " $k $result[$j]{$k}\n"
    }
}

Сохраните текст как columnvalues.pl
Запустите его как: perl columnvalues.pl files*

Описание

В цикле верхнего уровня:
 * Цикл по каждой строке комбинированных входных файлов
 * Разделить строку на массив @Fields
 * Для каждого столбца увеличивайте структуру данных массива результатов хеширования

В верхнем уровне для цикла:
 * Петля по массиву результатов
 * Распечатать номер столбца
 * Получить значения, используемые в этом столбце
 * Сортировка значений по количеству вхождений
 * Вторичная сортировка на основе значения (например, b vs g vs m vs z)
 * Итерировать через хэш результата, используя отсортированный список
 * Распечатайте значение и номер каждого события

Результаты, основанные на примерах входных файлов, предоставленных @Dennis

column 0:
 a 3
 z 3
 t 1
 v 1
 w 1
column 1:
 d 3
 r 2
 b 1
 g 1
 m 1
 z 1
column 2:
 c 4
 a 3
 e 2

.csv input

Если ваши входные файлы являются .csv, измените /\s+/ на /,/

Obfuscation

В уродливом конкурсе Perl особенно хорошо оборудован.
Эта однострочная линия делает то же самое:

perl -lane 'for $i (0..$#F){$g[$i]{$F[$i]}++};END{for $j (0..$#g){print "$j:";for $k (sort{$g[$j]{$b}<=>$g[$j]{$a}||$a cmp $b} keys %{$g[$j]}){print " $k $g[$j]{$k}"}}}' files*

Ответ 5

Рубин (1.9 +)

#!/usr/bin/env ruby
Dir["*"].each do |file|
    h=Hash.new(0)
    open(file).each do |row|
        row.chomp.split("\t").each do |w|
            h[ w ] += 1
        end
    end
    h.sort{|a,b| b[1]<=>a[1] }.each{|x,y| print "#{x}:#{y}\n" }
end