各行の重複を無視し、.csvファイルで最も一般的な単語を見つける方法は?

各行の重複を無視し、.csvファイルで最も一般的な単語を見つける方法は?

.csvファイルで最も一般的な10の単語を見つける必要があります。ファイルは、各行にカンマ区切りの単語が含まれるように構成されています。同じ行に同じ単語が複数回繰り返されると、1と計算されます。したがって、次の例では次のようになります。

green,blue,blue,yellow,red,yellow
red,blue,green,green,green,brown

緑、青、赤は2と計算し、黄色と茶色は1と計算します。

同様の質問が以前に要求されたことがわかり、1つの解決策は次のとおりです。

<file.csv tr -c '[:alnum:]' '[\n*]' | sort|uniq -c|sort -nr|head  -10

ただし、次のように、単語が同じ行に表示される回数を計算します。

  4 green
  3 blue
  2 yellow
  2 red
  1 brown

これは実際に私に必要なものではありません。助けが必要ですか?また、コマンドの簡単な説明と同様の質問で見つけたコマンドが必要なタスクを実行しない理由に感謝します。

答え1

GNUgrepまたは互換製品を使用してください。

$ grep -nEo '\w+' file.csv|sort -u|cut -d: -f2-|sort|uniq -c|sort -k1rn|head
      2 blue
      2 green
      2 red
      1 brown
      1 yellow

答え2

パールを選ぶかもしれない

  • uniqモジュールの内容を使用して、List::Util各行の重複エントリを削除します。
  • ハッシュを使用して結果の発生回数を計算します。

例えば

perl -MList::Util=uniq -F, -lnE '
  map { $h{$_}++ } uniq @F 
  }{ 
  foreach $k (sort { $h{$b} <=> $h{$a} } keys %h) {say "$h{$k}: $k"}
' file.csv
2: red
2: green
2: blue
1: yellow
1: brown

sortcoreutilsを使用するしかない場合は、uniqシェルループを追加して同様のアルゴリズムを実装できます。

while IFS=, read -a words; do 
  printf '%s\n' "${words[@]}" | sort -u
done < file.csv | sort | uniq -c | sort -rn
  2 red
  2 green
  2 blue
  1 yellow
  1 brown

しかし、参考にしてくださいシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?

答え3

awk連想配列と簡単な論理チェックを使用できます。

awk -F, '
  {split("", c); for (i=1; i<=NF; i++) 
      if (!c[$i]){c[$i]++;wds[$i]++}}
  END{for (wd in wds) print wds[wd], wd}' file

出力

1 brown
2 red
1 yellow
2 blue
2 green

フィールド区切り記号を次のように設定します。,

awk -F, '

1行に複数の単語が表示されることを確認するために計算するか、またはcを使用して各行の先頭の単語数が空であることを確認し、フィールドをdelete c;繰り返しsplit("", c)ます。

      {split("", c); for (i=1; i<=NF; i++) 

または

      {delete c; for (i=1; i<=NF; i++) 

$iこの行の単語がまだ表示されていない場合は、!c[$i]その単語のカウンタをc[$i]++1に増やします(単語が同じ行に再び表示されると、条件付きテストは失敗します)。その後、wds[$i]++ テストが失敗しない場合は、総数を増やします。言葉の

      if (!c[$i]){c[$i]++;wds[$i]++}}

ファイルが完成したら、配列を繰り返してwdswds[wd]と単語を印刷します。wd

      END{for (wd in wds) print wds[wd], wd}' file

楽しく

awk連想配列ビットなしのハッキング

awk -F, '{for (i=1; i<=NF; i++) print NR, $i}' file | 
    sort | uniq | awk '{print $2}'| sort | uniq -c | sort -nr

awk行番号が前になるようにフィールドを削除し、行の重複をsort | uniq失い、awk番号をもう一度失い、元のコードに戻します。

答え4

awkには重要な必須タスクを実行するスクリプトがあります。

awk -F, '
{ 
       i = split( "" , seen ) ;
       while( ++i <= NF ) if( ++seen[$i] == 1 ) count[$i]++; 
}END{
       for( word in count ) print count[word] , word
}'     file | sort -rn | head

仕組みは次のとおりです。

  • 入力ファイルの各行に対して、次の操作を行います。
  • i0に再初期化し、seen新しい行ごとに配列を消去しますi=split("",seen)
  • seen各フィールドの配列の作成++seen[$i]
  • この行では、aフィールドが最初に表示されたときにそのフィールドの数を計算します。 (count[$i]++)。
  • すべての行が処理されるとEND
  • for( word in count )計算された各単語について
  • すべての単語とその数を印刷しますprint count[word] , word
  • 最後に、awkは出力を生成した後に数値でソートします。sort -rn
  • 最初の10行を選択しますhead

私たちはこれをもう少し不思議な行で書くことができます:

awk -F, '{i=split("",a);while(++i<=NF)a[$i]++||c[$i]++}END{for(i in c)print c[i],i}' file|sort -rn|head

関連情報