【Awkでデータ解析のすゝめ】CSVデータで重複しているセル要素を見つける/カウントする


※ 当ページには【広告/PR】を含む場合があります。
2021/02/19
2022/09/30
【Awkでデータ解析のすゝめ】Awkのみで2つのファイルを効率的に結合させる方法
【Awk&Sed活用講座】CSVファイルから重複データを見つける&重複をカウントする

csvファイル内に存在しているセルのデータが重複しているときに、Awkで何かしらの処理させたいときがあります。

Awkでデータの重複している・していないの判別は簡単なスクリプトを使って取り出せるので、一度覚えておけば、もしかしたときのCSVデータ取扱も怖くなくなります。

今回は、Awkによる重複の見つけ方/カウントのやり方を考察していきます。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】シェルスクリプトをこれから学びたい人のためのオススメ書籍&教材特集

AwkをつかってCsvでやりたかったこと

例えば、何かの集合を表している配列・[1,2,3,4,5,6,7,8]があるとします。

この要素を使って、二次元の重みデータで構成される4x4マスのcsvファイルが、例えば以下のように記録してあるとしましょう。

            
            2,2,2,3
1,3,3,6
4,2,8,4
3,1,2,2
        
二次元数値データの代表的な例は、画像データの数値配列などが挙げられます。

このような二次元データを構成するセル要素は、基本に重複しても良いですし、しない要素もあります。

上のようなCSVデータの程度なら人間の眼で見ても重複している要素は判別可能ですが、これが何MBのテキストデータともなってくるとコンピュータによる処理で重複を判断させるしかありません。

どの要素がCSVデータ全体として、何回出ているかを解析したい...そういう集計がやりたい場合にもAwkが便利です。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】シェルスクリプトをこれから学びたい人のためのオススメ書籍&教材特集

重複有り・無しを判別させる

まずは重複回数をカウントしないで、重複しているかしていないかをチェックするだけのAwkスクリプトを試します。

先程のデータセットを使い回すため変数
RAW_DATASETに仕込んでおきます。

            
            $ RAW_DATASET=$(cat <<EOF
2,2,2,3
1,3,3,6
4,2,8,4
3,1,2,2
EOF
)
        
重複を判定する上で、もっとも基礎的なAwk内の配列の働きを簡単なスクリプトで確認します。

以下のスクリプトを実行してみましょう。

            
            $ echo "$RAW_DATASET" | awk -F"," '
{
    for (i=1; i<=NF; i++) {
        print !label[$i]++;
    }
}
'
#👇出力
1
0
0
1
1
0
0
1
1
0
1
0
0
0
0
0
        
ちなみに組込変数NFは各行の列数を取り出すものです。forループの部分で$1, $2, ..., $NFで一行ごとに全ての列の要素を取り出しています。

そのi列目に着目すると、
$iの要素をキー値とした、label[$i]という連想配列を使っていることがポイントで、$iという要素を発見する度に、初期値(この場合ではゼロ)がインクリメント(++)されて、値がカウントされます。

この連想配列に否定演算子
!に作用させることで、始めて出現した要素は1が返り、既に出た要素がある場合には0が返ります。

ということで、この仕組みを踏まえると、1回以上データセット無いに出現していた要素を取り出す場合には以下のように書けます。

            
            $ echo "$RAW_DATASET" | awk -F"," '{
    for (i=1; i<=NF; i++) {
        if (!label[$i]++) {print $i;}
    }
}'
#👇出力
2
3
1
6
4
8
        
という要素がセル内で重複していることがわかります。

なお、要素の順番は出現した順番ですが、キー値の並び替えを行いたい場合には、以前の記事の方で特集しましたテクニックをご参考ください。

合同会社タコスキングダム|蛸壺の技術ブログ
【Awkでデータ解析のすゝめ】gawk(GNU AWK)でカスタムソートを使ってみる

ビッグデータ解析の分野で利用できるAwkの高速カスタムソート術をご紹介します。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】シェルスクリプトをこれから学びたい人のためのオススメ書籍&教材特集

重複要素のカウント

もはや先程の説明でこのお題は解けてはいますが、念の為に解説しておきます。

            
            $ echo "$RAW_DATASET" | awk -F"," '
{
    for (i=1; i<=NF; i++) { label[$i]++; }
}
END {
    for(j in label) {
        print j "は" label[j] "回でました";
    }
}
'
#👇出力
1は2回でました
2は6回でました
3は4回でました
4は2回でました
6は1回でました
8は1回でました
        
ここでのポイントとしては、要素の値をキーに持つ連想配列labelが要素の出現回数でカウントされることが前節で説明しましたが、最終的なカウント結果はENDセクションで集計的に処理を行わせていることです。

なお、
for ... inループはデフォルトで回すキー値の昇順で自動ソートされます。

また配列
[1,2,3,4,5,6,7,8]の内で出なかった要素を抽出する場合は、

            
            $ echo "$RAW_DATASET" | awk -F"," '
{
    for (i=1; i<=NF; i++) { label[$i]++; }
}
END {
    for(j=1; j<=8 ;j++) {
        if(!label[j]) {
            print j "は出ませんでした...";
        }
    }
}
'
#👇出力
5は出ませんでした...
7は出ませんでした...
        
と出来ます。

探したい配列が整数であれば通常のforループのインデックスが、そのまま検索される連想配列のキーとして使えるので簡単に使えましたが、キーとしては何でも利用できます。

より柔軟なキー値使いたいのであれば、検索用の配列をBEGINかENDセクションで定義しておくようなひと手間を掛けておく必要があると思います。


合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】シェルスクリプトをこれから学びたい人のためのオススメ書籍&教材特集

まとめ

以上、Awkでの重複要素を操作するテクニックを簡潔に解説しました。

なお重複を取り出したい、カウントしたいなどの操作は、sortコマンドでも可能ですが、高度な集計を行いたいのであればawkスクリプトで一本化するのも良いでしょう。
記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。

合同会社タコスキングダム|蛸壺の技術ブログ【効果的学習法レポート】シェルスクリプトをこれから学びたい人のためのオススメ書籍&教材特集