複数の列を持つタブ区切りファイルがあります。フォルダー内のすべてのファイルについて、列内のさまざまな値の出現頻度をカウントし、カウントの降順で並べ替えます(最も高いカウントが最初になります)。 Linuxコマンドライン環境でこれをどのように実現しますか?
Awk、Perl、pythonなどの一般的なコマンドライン言語を使用できます。
列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
シェルでそれを行う方法は次のとおりです。
FIELD=2
cut -f $FIELD * | sort| uniq -c |sort -nr
これは、bashの優れた点です。
GNUサイト は、このNice awkスクリプトを示唆しています。これは、単語とその頻度の両方を出力します。
可能な変更:
sort -nr
(およびWord
とfreq[Word]
を逆に)でパイプ処理して、降順で結果を確認できます。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]
}
このコードは、all列の出現を計算し、各列のソートされたレポートを出力します。
# 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ループで:
*結果配列をループします
*列番号を出力します
*その列で使用されている値を取得する
*発生回数で値をソートします
*値に基づく2次ソート(たとえば、b vs g vs m vs z)
*ソートされたリストを使用して、結果ハッシュを反復処理します
*各出現の値と数を出力します
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の場合、/\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*
ルビー(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