bashの列の一意の値の数を取得する


95

複数の列を持つタブ区切りファイルがあります。フォルダー内のすべてのファイルについて、列内のさまざまな値の出現頻度をカウントし、カウントの降順(最大のカウントが最初)に並べ替えたい。Linuxコマンドライン環境でこれをどのように達成しますか?

awk、perl、pythonなどの一般的なコマンドライン言語を使用できます。

回答:


152

列2の頻度カウントを表示するには(例):

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

68

シェルでこれを行う方法は次のとおりです。

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

これはbashが得意なことです。


22
物事の「ソート」... ar ar ar!:)
John Rix

3
ちょっと独特なもの。:P(-d,コンマまたはその他の区切り文字でフィールドを区切るために使用)。
cprn

4
使用しましたcut -f 1 -d ' '。本当にありがとうございました。:)
Alfonso Nishikawa

8

GNUサイト単語とその周波数の両方を印刷し、この素敵なawkスクリプトを、示唆しています。

可能な変更:

  • あなたはパイプすることができますsort -nr(そしてリバースwordfreq[word])を実行して、降順で結果を確認ます。
  • 特定の列が必要な場合は、forループを省略して単純に書き込むことができます-3をfreq[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]
 }

2
素晴らしいスクリプト例。awkの機能の多くを示しています。
David Mann

このスクリプトは、Excelワークブックのどの行に注意を払う必要があるかを判断するのに役立ちました:)(Excelの内容をテキストファイルにコピーし、awkを使用して、できれば、grep -nのパターンファイルを作成できます) 。
Jubbles

6

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*

説明

最上位のwhileループでは:
*結合された入力ファイルの各行をループします
*行を@Fields配列に分割します
すべての列について、結果のハッシュの配列データ構造をインクリメントします

トップレベルのforループでは、次のようになります。
*結果の配列をループし
ます
* 列番号を出力します
* その列で使用されている値を取得します*出現回数で値を並べ替えます*値に
基づいて二次並べ替えを行います(たとえば、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入力

入力ファイルが.csvの場合は、次のように変更/\s+/します/,/

難読化

醜いコンテストでは、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*

2

ルビー(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

5
これは非常に興味深いものです。私がそれを使用して機能しただけでなく、ルビーがいかに醜いかに驚いただけでも、Perlは悪いと思いました。
ryansstack 2014

ルビーの弁護では、これは本当にニートアップされる可能性があります。たとえばeach_with_object、特にを使用します。要するに、これはややひどく書かれています。
ランバティーノ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.