web-dev-qa-db-ja.com

CSVで繰り返し発生する回数をカウントしますか?

次のような列を持つCSVがあります。

Team    Other Data  More Data   Result  Time
Knicks      A          F         Loss    2p
Celtics     B          E         Win     2p
Lakers      C          D         Loss    3p
Lakers      D          C         Loss    4p
Knicks      E          B         Win     4p
Lakers      F          A         Win     5p

CSVを読み取って各チームの勝敗を出力するにはどうすればよいですか?

たとえば、希望する出力は次のようになります。

1 Loss Knicks
1 Win Knicks
1 Win Celtics
2 Loss Lakers
1 Win Lakers

今、私はこのコードを持っています:

#!/bin/bash
while IFS=, read -r team result
do
  echo $team, $result
done < teams.csv

これにより、次の出力が生成されます。

Team, Result   
Knicks, Loss
Celtics, Win
Lakers, Loss
Lakers, Loss
Knicks, Win

すべてのチームの各結果の発生数をカウントして保存するにはどうすればよいですか?理想的には、このデータをチームごとに並べ替えたいです。

2

awkでの配列の使用

入力ファイルのフィールドが1つ以上の空白文字で区切られている場合は、フィールド区切り文字を宣言する必要はありません。

awk 'NR>1 && NF { league[$1][$4]++ } END { for ( team in league ) for ( results in league[team] ) print league[team][results],results,team }' teams.txt

画面用にフォーマットされた同じコード:

awk 'NR>1 && NF { league[$1][$4]++ }
     END { for ( team in league )
           for ( results in league[team] )
           print league[team][results],results,team }' teams.txt

ここで、league[$1][$4]++は、リーグ(入力ファイル)の各チーム($4、最初のフィールド)の勝ち負けの数($1、4番目のフィールド)をカウントします。

NR>1は、awkがヘッダー(最初の行)を無視することを意味します。

同様に、NFNF>0の省略形)は、awkが少なくとも1つのフィールドを含む行のみを検査することを意味します。つまり、NFは空白行をスキップします。

NR>1 && NFセクションは、入力ファイルを調べて配列を作成します。それが終了すると、ENDセクションは配列を出力します。

入力ファイルのフィールドがカンマで区切られている場合は、BEGIN { FS="," ; OFS=" " }を追加して、入力(FS)と出力(OFS)のフィールド区切り記号を設定します。

awk 'BEGIN { FS="," ; OFS=" " } NR>1 && NF { league[$1][$4]++ } END { for ( team in league ) for ( results in league[team] ) print league[team][results],results,team }' teams.csv

画面用にフォーマットされた同じコード:

awk 'BEGIN { FS="," ; OFS=" " }
         NR>1 && NF { league[$1][$4]++ }
         END { for ( team in league )
               for ( results in league[team] )
               print league[team][results],results,team }' teams.csv

出力:

1 Win Knicks
1 Loss Knicks
1 Win Lakers
2 Loss Lakers
1 Win Celtics

そのコードの最後に| sort -t " " -k 3 -k 2,2を追加して、チームで並べ替えてから、チームごとの結果で並べ替えます。

ソートされた出力:

1 Win Celtics
1 Loss Knicks
1 Win Knicks
2 Loss Lakers
1 Win Lakers
4
Gaultheria

あなたがする必要があるのは、ファイルをソートし、それをuniq -cに渡して、一意の発生をカウントすることです。

sort teams.csv | uniq -c

次のような出力が生成されます。

      1 Celtics,Win
      1 Knicks,Loss
      1 Knicks,Win
      2 Lakers,Loss
2
l0b0

GNU datamash(およびawkを使用すると、必要に応じて列を並べ替えることができます):

$ datamash -W --header-in groupby 1,4 count 4 < teams.csv | awk '{print $3, $2, $1}'
1 Loss Knicks
1 Win Celtics
2 Loss Lakers
1 Win Knicks
1 Win Lakers

しない datamashにソートを要求するため、これはすでに隣接している結果のみをグループ化することに注意してください。

あなたのデータが本当にカンマ分離されている場合は、置き換えてください-Wby-t,

2
steeldriver

sortを使用して、それをuniq -cにパイプすることができますが、これにはTeam, Resultが含まれます。

それを回避するには:

$ awk 'NR>1 {print $4,$1}' team.csv | sort -k2 | uniq -c

各セクションを説明するには:

  • awk 'NR>1 {print $4,$1}'-最初の行よりも大きいすべての行を印刷します。結果は、チームと結果の列4と1で指定されたチームが続きます。
  • sort -k2-awkの運用後、2列目になるようにチームで並べ替えます。
  • uniq -c-一意のオカレンスの数をカウントします

チーム別にソートされた出力:

1 Win Celtics
1 Loss Knicks
1 Win Knicks
2 Loss Lakers
1 Win Lakers
1
Nasir Riley