【Awkでデータ解析のすゝめ】CSVで重複なしのユニークなリストを作る/検索結果から重複を取り除く


2022/08/08
2022/09/30
【Awk&Sed活用講座】CSVファイルから重複データを見つける&重複をカウントする
蛸壺の技術ブログ|CSVで重複なしのユニークなリストを作る/検索結果から重複を取り除く

久々のシェルスクリプトのお話回です。

CSVの行を検索した結果に、要素の重複を含むケースが結構あります。

この重複を含んだままのデータをそのまま気づかすに処理してしまうと、最終的に思わぬ計算結果を得てしまうなど、好ましくないこともあります。

ちょっと前に、CSVデータの中身から重複を
「探す」「カウントする」の2つのテクニックを取り上げたことがありました。

合同会社タコスキングダム|蛸壺の技術ブログ
【Awk&Sed活用講座】CSVファイルから重複データを見つける&重複をカウントする

AwkとSedでCSVファイルからCSVデータの重複を取り扱うテクニックを簡単に載せます。

今回はそのテクニックの応用編として、
CSVデータから重複を削除してユニークな要素だけの行要素にすることと、検索結果に重複がある場合に、その重複を取り除くのテクニックの2つを紹介します。


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

CSVファイルの重複をなくし、ユニークな行データにする

再集計などを必要としないCSVファイルがあれば、元データから重複項目をそのまま無くすことで、他のユーザーからも扱いやすくなります。

例えば以下のデータのように、株式銘柄をリストアップしたデータが並んでいて、そのいくつかの行が重複しています。

            
            1319,日経300F,東証
1390,ETFアジア太平洋株,東証
1391,ETFスイス株,東証
1419,タマホーム,東証P
1419,タマホーム,東証P
1580,日経平均ベア,東証
1674,ETFS白金,東証
1770,藤田エンジ,東証S
1826,佐田建,東証S
1835,東鉄工,東証P
1770,藤田エンジ,東証S
2032,ハンセンベア,東証
2109,三井糖,東証P
2838,米国国債投信(ヘッジなし),東証
2136,ヒップ,東証S
2433,博報堂DY,東証P
2032,ハンセンベア,東証
2109,三井糖,東証P
2648,ブルームバーグ米国債(為替ヘッジあり),東証
2838,米国国債投信(ヘッジなし),東証
2904,一正蒲鉾,東証P
3063,ジェイグループ,東証G
3261,グランディ,東証G
3261,グランディ,東証G
3329,東和フード,東証S
3492,タカラレーペン,東証
3865,北越コーポ,東証P
3492,タカラレーペン,東証
3063,ジェイグループ,東証G
4428,リンク,東証G
4031,チッカリン,東証S
4428,リンク,東証G
4544,HUグループ,東証P
4832,JFEシス,東証S
4928,ノエビアH,東証P
5020,JXホール,東証P
4544,HUグループ,東証P
5194,相模ゴ,東証S
5757,サンエツ,東証P
4544,HUグループ,東証P
6200,インソース,東証P
6474,不二越,東証P
6958,日本CMK,東証P
7226,極東開発,東証P
7559,ジーエフシー,東証S
8093,極東貿易,東証P
8801,三井不,東証P
8093,極東貿易,東証P
6200,インソース,東証P
9240,デリバリーコンサル,東証G
9533,邦ガス,東証P
9735,セコム,東証P
9533,邦ガス,東証P
9984,ソフトバンク,東証P
        
このようなデータは、未整理のままではデータとしての価値が低いので、まずは重複を取り除き、銘柄コード順にソートして、より解析しやすい状態にしたほうが後々使いやすくなるでしょう。

先程のデータをローカルにCSVファイルとして、作業フォルダに保存してから、以下のコマンドを試してみましょう。

            
            $ awk -F"," '!col[$1]++{ print $0 }' stocks.csv | \
sort -k 1 -t ','
#👇出力結果
1319,日経300F,東証
1390,ETFアジア太平洋株,東証
1391,ETFスイス株,東証
1419,タマホーム,東証P
1580,日経平均ベア,東証
1674,ETFS白金,東証
1770,藤田エンジ,東証S
1826,佐田建,東証S
1835,東鉄工,東証P
2032,ハンセンベア,東証
2109,三井糖,東証P
2136,ヒップ,東証S
2433,博報堂DY,東証P
2648,ブルームバーグ米国債(為替ヘッジあり),東証
2838,米国国債投信(ヘッジなし),東証
2904,一正蒲鉾,東証P
3063,ジェイグループ,東証G
3261,グランディ,東証G
3329,東和フード,東証S
3492,タカラレーペン,東証
3865,北越コーポ,東証P
4031,チッカリン,東証S
4428,リンク,東証G
4544,HUグループ,東証P
4832,JFEシス,東証S
4928,ノエビアH,東証P
5020,JXホール,東証P
5194,相模ゴ,東証S
5757,サンエツ,東証P
6200,インソース,東証P
6474,不二越,東証P
6958,日本CMK,東証P
7226,極東開発,東証P
7559,ジーエフシー,東証S
8093,極東貿易,東証P
8801,三井不,東証P
9240,デリバリーコンサル,東証G
9533,邦ガス,東証P
9735,セコム,東証P
9984,ソフトバンク,東証P
        
確かに簡単なAwkスクリプトで、重複した行もなく、ユニークなリストとして整理できました。

なお、この重複を弾くテクニックの中身の解説としては、前回詳しく説明していましたので、こちらの記事では省略させていただきます。

合同会社タコスキングダム|蛸壺の技術ブログ
【Awkでデータ解析のすゝめ】重複している要素を見つける&重複している要素のカウントする

csvファイル内のデータが重複しているときの操作をAwkでどう見つける/処理するのかをじっくり考察していきます。


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

CSVデータの行検索の結果から重複を取り除く

先ほどのように、CSVファイルのデータそのものの重複を取り除くのではなく、行検索から得られた結果のみに、重複を取り除く操作を行いたい場合に便利なテクニックです。

以前の記事で、似たような「CSVの中身を検索するスクリプト」を作ったことがありました。

合同会社タコスキングダム|蛸壺の技術ブログ
【実践!CSVデータ検索スクリプト作成編】条件を与えて検索結果をCSVデータで出力するスクリプト

読み込んだCSVデータから特定の1列を検索キーでヒットした行要素を、CSV形式でピックアップして表示するシェルスクリプトを作成してみます。

そちらの記事でから流用したシェルスクリプトを一部改良して、行要素を検索するツールに仕立て直して、検索キーとして銘柄コードの一部でコマンドオプションから与える使い方をやってみます。

            
            #!/bin/bash

usage_exit() {
    echo "USAGE: $(basename $0) [-k key] [-h help] [input_file]" 1>&2
    exit 1
}

noarg_err() {
    echo "ERROR: must provide key!" 1>&2
    exit 1
}

noinputfile_err() {
    echo "ERROR: not allowed input file to be empty!" 1>&2
    exit 1
}

while getopts k: OPT; do
    case $OPT in
        k ) KEY="$OPTARG"
            ;;
        \? ) usage_exit
            ;;
    esac
done

shift $((OPTIND - 1))

if [ -z "$KEY" ]; then
    noarg_err
fi

if [ -z "$1" ]; then
    noinputfile_err
fi

echo "FILE: $1, KEY: ${KEY}"

awk -F"," '
    $1~/'"${KEY}"'/ && !col[$1]++ { print $0 }
' $1
        
これで例えば、CSVデータから銘柄コードに44を含む行を重複なしに抽出できるか試してみましょう。

            
            $ chmod +x stock_finder.sh
$ ./stock_finder.sh -k 44 stocks.csv
#👇以下、重複なしの検索結果を表示
FILE: stocks.csv, KEY: 44
4428,リンク,東証G
4544,HUグループ,東証P
        
どうやらちゃんと検索結果から重複が消えて、見やすいリスト表示が可能となっているようです。

このスクリプトのポイントは、Awkスクリプト部分の、
$1~/'"${KEY}"'/ && !col[$1]++になります。

最初の条件で、銘柄コードのある一列目に
KEY値が含まれているかを正規表現からフィルタリングし、二番目の条件で、重複が発生した行を弾くようにしています。

Awkなら、このような簡単なスクリプトの記述だけで、いとも簡単に重複なしのリストを得ることができるので、このテクニックを理解しておくと、色々と応用が効くと思います。

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

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

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