bashスクリプトで「データサイエンス100本ノック（構造化データ加工編）

## はじめに

普段はデータパイプライン構築運用を行っていますが、クラウドサーバーへ置かれるローデータをスクリプトでさっと見たい時があります。

そこで、勉強がてら昔やったことのある[データサイエンス100本ノック（構造化データ加工編）](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess)をbashスクリプトで行ってみました。

主にはgawkの勉強の為です。

「さっと見たい」が目的の為、Bashで効率が悪い問題(複雑な計算・JOIN)の問題までは行わず、Q27まで行いました。


## 問題&解説

https://github.com/nijigen-plot/bash-100knocks?tab=readme-ov-file

ディレクトリ構造は以下のようになっています。

```
src
├── data
│   ├── category.csv
│   ├── customer.csv
│   ├── geocode.csv
│   ├── product.csv
│   ├── receipt.csv
│   └── store.csv
├── q1.sh
├── q2.sh
︙
└── s27.sh
```


また、解説は自身の振り返りの為ですので、間違いのある可能性があります。
その際はご指摘いただけますと嬉しいです。

### Q1

**レシート明細テーブル（df_receipt）から全項目の先頭10件を表示し、どのようなデータを保有しているか目視で確認せよ。**


```bash
#!/bin/bash

# headコマンド + -nオプション(指定しなくてもデフォルト10)
head -n 10 ./data/receipt.csv
```

```
sales_ymd,sales_epoch,store_cd,receipt_no,receipt_sub_no,customer_id,product_cd,quantity,amount
20181103,1257206400,S14006,112,1,CS006214000001,P070305012,1,158
20181118,1258502400,S13008,1132,2,CS008415000097,P070701017,1,81
20170712,1215820800,S14028,1102,1,CS028414000014,P060101005,1,170
20190205,1265328000,S14042,1132,1,ZZ000000000000,P050301001,1,25
20180821,1250812800,S14025,1102,2,CS025415000050,P060102007,1,90
20190605,1275696000,S13003,1112,1,CS003515000195,P050102002,1,138
20181205,1259971200,S14024,1102,2,CS024514000042,P080101005,1,30
20190922,1285113600,S14040,1102,1,CS040415000178,P070501004,1,128
20170504,1209859200,S13020,1112,2,ZZ000000000000,P071302010,1,770
```



### Q2

**レシート明細のテーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、10件表示させよ。**


```bash
#!/bin/bash

# cutコマンドでファイルを読み取り、カンマ区切り+列指定で表示される列を入れ替え
cut -d ',' -f 1,6,7,9 ./data/receipt.csv | head -n 10
```

```
sales_ymd,customer_id,product_cd,amount
20181103,CS006214000001,P070305012,158
20181118,CS008415000097,P070701017,81
20170712,CS028414000014,P060101005,170
20190205,ZZ000000000000,P050301001,25
20180821,CS025415000050,P060102007,90
20190605,CS003515000195,P050102002,138
20181205,CS024514000042,P080101005,30
20190922,CS040415000178,P070501004,128
20170504,ZZ000000000000,P071302010,770
```

### Q3

**レシート明細のテーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、10件表示させよ。ただし、sales_ymdはsales_dateに項目名を変更しながら抽出すること。**

```bash
#!/bin/bash

# Q2の出力+sedコマンドで1行目の対象文字列を置換
cut -d ',' -f 1,6,7,9 ./data/receipt.csv | sed '1s/sales_ymd/sales_date/' | head -n 10
```

```
sales_date,customer_id,product_cd,amount
20181103,CS006214000001,P070305012,158
20181118,CS008415000097,P070701017,81
20170712,CS028414000014,P060101005,170
20190205,ZZ000000000000,P050301001,25
20180821,CS025415000050,P060102007,90
20190605,CS003515000195,P050102002,138
20181205,CS024514000042,P080101005,30
20190922,CS040415000178,P070501004,128
20170504,ZZ000000000000,P071302010,770
```

### Q4

**レシート明細のテーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。**

- 顧客ID（customer_id）が"CS018205000001"


```bash
#!/bin/bash

# Q2の出力+awkで2行目以降の2列目の文字列を指定
cut -d ',' -f 1,6,7,9 ./data/receipt.csv | awk -F, 'NR==1; NR > 1 && $2 == "CS018205000001"'
```

```
sales_ymd,customer_id,product_cd,amount
20180911,CS018205000001,P071401012,2200
20180414,CS018205000001,P060104007,600
20170614,CS018205000001,P050206001,990
20170614,CS018205000001,P060702015,108
20190216,CS018205000001,P071005024,102
20180414,CS018205000001,P071101002,278
20190226,CS018205000001,P070902035,168
20190924,CS018205000001,P060805001,495
20190226,CS018205000001,P071401020,2200
20180911,CS018205000001,P071401005,1100
20190216,CS018205000001,P040101002,218
20190924,CS018205000001,P091503001,280
```

### Q5

**レシート明細のテーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。**

- 顧客ID（customer_id）が"CS018205000001"
- 売上金額（amount）が1,000以上

```bash
#!/bin/bash

# Q4の出力+awkの条件を追加
cut -d ',' -f 1,6,7,9 ./data/receipt.csv | awk -F, 'NR==1; NR > 1 && $2 == "CS018205000001" && $4 >= 1000'
```


```
sales_ymd,customer_id,product_cd,amount
20180911,CS018205000001,P071401012,2200
20190226,CS018205000001,P071401020,2200
20180911,CS018205000001,P071401005,1100
```

### Q6

**レシート明細テーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上数量（quantity）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。**

- 顧客ID（customer_id）が"CS018205000001"
- 売上金額（amount）が1,000以上または売上数量（quantity）が5以上

```bash
#!/bin/bash

# Q5のOR条件版
cut -d ',' -f 1,6,7,8,9 ./data/receipt.csv | awk -F, 'NR==1; NR > 1 && $2 == "CS018205000001" && ($5 >= 1000 || $4 >= 5)'
```

```
sales_ymd,customer_id,product_cd,quantity,amount
20180911,CS018205000001,P071401012,1,2200
20180414,CS018205000001,P060104007,6,600
20170614,CS018205000001,P050206001,5,990
20190226,CS018205000001,P071401020,1,2200
20180911,CS018205000001,P071401005,1,1100
```

### Q7

**レシート明細のテーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。**

- 顧客ID（customer_id）が"CS018205000001"
- 売上金額（amount）が1,000以上2,000以下


```bash
#!/bin/bash

# Q5にAND条件追加しただけ
cut -d ',' -f 1,6,7,9 ./data/receipt.csv | awk -F, 'NR==1; NR > 1 && $2 == "CS018205000001" && $4 >= 1000 && $4 <= 2000'
```

```
sales_ymd,customer_id,product_cd,amount
20180911,CS018205000001,P071401005,1100
```


### Q8

**レシート明細テーブル（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ**


- 顧客ID（customer_id）が"CS018205000001"
- 商品コード（product_cd）が"P071401019"以外

```bash
#!/bin/bash

# 否定条件版なだけ
cut -d ',' -f 1,6,7,9 ./data/receipt.csv | awk -F, 'NR==1; NR > 1 && $2 == "CS018205000001" && $3 != "P071401019"'
```

```
sales_ymd,customer_id,product_cd,amount
20180911,CS018205000001,P071401012,2200
20180414,CS018205000001,P060104007,600
20170614,CS018205000001,P050206001,990
20170614,CS018205000001,P060702015,108
20190216,CS018205000001,P071005024,102
20180414,CS018205000001,P071101002,278
20190226,CS018205000001,P070902035,168
20190924,CS018205000001,P060805001,495
20190226,CS018205000001,P071401020,2200
20180911,CS018205000001,P071401005,1100
20190216,CS018205000001,P040101002,218
20190924,CS018205000001,P091503001,280
```

### Q9

**以下の処理において、出力結果を変えずにORをANDに書き換えよ。**

`not(prefecture_cd = '13' or 900 < floor_area)`

```bash
#!/bin/bash

# ベン図の問題
cat ./data/store.csv | awk -F, 'NR==1; NR >1 && $3 != 13 && $10 <= 900'
```

```
store_cd,store_name,prefecture_cd,prefecture,address,address_kana,tel_no,longitude,latitude,floor_area
S14046,北山田店,14,神奈川県,神奈川県横浜市都筑区北山田一丁目,カナガワケンヨコハマシツヅキクキタヤマタイッチョウメ,045-123-4049,139.5916,35.56189,831.0
S14011,日吉本町店,14,神奈川県,神奈川県横浜市港北区日吉本町四丁目,カナガワケンヨコハマシコウホククヒヨシホンチョウヨンチョウメ,045-123-4033,139.6316,35.54655,890.0
S12013,習志野店,12,千葉県,千葉県習志野市芝園一丁目,チバケンナラシノシシバゾノイッチョウメ,047-123-4002,140.022,35.66122,808.0
```


### Q10

**店舗テーブル（df_store）から、店舗コード（store_cd）が"S14"で始まるものだけ全項目抽出し、10件だけ表示せよ。**

```bash
#!/bin/bash

# awkでS14から始まる のあいまい検索
cat ./data/store.csv | awk -F, 'NR==1; NR >1 && $1 ~ /^S14/' | head -n 10
```

```
store_cd,store_name,prefecture_cd,prefecture,address,address_kana,tel_no,longitude,latitude,floor_area
S14010,菊名店,14,神奈川県,神奈川県横浜市港北区菊名一丁目,カナガワケンヨコハマシコウホククキクナイッチョウメ,045-123-4032,139.6326,35.50049,1732.0
S14033,阿久和店,14,神奈川県,神奈川県横浜市瀬谷区阿久和西一丁目,カナガワケンヨコハマシセヤクアクワニシイッチョウメ,045-123-4043,139.4961,35.45918,1495.0
S14036,相模原中央店,14,神奈川県,神奈川県相模原市中央二丁目,カナガワケンサガミハラシチュウオウニチョウメ,042-123-4045,139.3716,35.57327,1679.0
S14040,長津田店,14,神奈川県,神奈川県横浜市緑区長津田みなみ台五丁目,カナガワケンヨコハマシミドリクナガツタミナミダイゴチョウメ,045-123-4046,139.4994,35.52398,1548.0
S14050,阿久和西店,14,神奈川県,神奈川県横浜市瀬谷区阿久和西一丁目,カナガワケンヨコハマシセヤクアクワニシイッチョウメ,045-123-4053,139.4961,35.45918,1830.0
S14028,二ツ橋店,14,神奈川県,神奈川県横浜市瀬谷区二ツ橋町,カナガワケンヨコハマシセヤクフタツバシチョウ,045-123-4042,139.4963,35.46304,1574.0
S14012,本牧和田店,14,神奈川県,神奈川県横浜市中区本牧和田,カナガワケンヨコハマシナカクホンモクワダ,045-123-4034,139.6582,35.42156,1341.0
S14046,北山田店,14,神奈川県,神奈川県横浜市都筑区北山田一丁目,カナガワケンヨコハマシツヅキクキタヤマタイッチョウメ,045-123-4049,139.5916,35.56189,831.0
S14022,逗子店,14,神奈川県,神奈川県逗子市逗子一丁目,カナガワケンズシシズシイッチョウメ,046-123-4036,139.5789,35.29642,1838.0
```

### Q11

**顧客テーブル（df_customer）から顧客ID（customer_id）の末尾が1のものだけ全項目抽出し、10件だけ表示せよ。**

```bash
#!/bin/bash

# Q10の後方一致検索版
cat ./data/customer.csv | awk -F, 'NR==1; NR > 1 && $1 ~ /1$/' | head -n 10
```

```
customer_id,customer_name,gender_cd,gender,birth_day,age,postal_cd,address,application_store_cd,application_date,status_cd
CS037613000071,六角 雅彦,9,不明,1952-04-01,66,136-0076,東京都江東区南砂**********,S13037,20150414,0-00000000-0
CS028811000001,堀井 かおり,1,女性,1933-03-27,86,245-0016,神奈川県横浜市泉区和泉町**********,S14028,20160115,0-00000000-0
CS040412000191,川井 郁恵,1,女性,1977-01-05,42,226-0021,神奈川県横浜市緑区北八朔町**********,S14040,20151101,1-20091025-4
CS028314000011,小菅 あおい,1,女性,1983-11-26,35,246-0038,神奈川県横浜市瀬谷区宮沢**********,S14028,20151123,1-20080426-5
CS039212000051,藤島 恵梨香,1,女性,1997-02-03,22,166-0001,東京都杉並区阿佐谷北**********,S13039,20171121,1-20100215-4
CS015412000111,松居 奈月,1,女性,1972-10-04,46,136-0071,東京都江東区亀戸**********,S13015,20150629,0-00000000-0
CS004702000041,野島 洋,0,男性,1943-08-24,75,176-0022,東京都練馬区向山**********,S13004,20170218,0-00000000-0
CS041515000001,栗田 千夏,1,女性,1967-01-02,52,206-0001,東京都多摩市和田**********,S13041,20160422,E-20100803-F
CS029313000221,北条 ひかり,1,女性,1987-06-19,31,279-0011,千葉県浦安市美浜**********,S12029,20180810,0-00000000-0
```

### Q12

**店舗テーブル（df_store）から横浜市の店舗だけ全項目表示せよ。**

```bash
#!/bin/bash

# Q10の部分一致版
cat ./data/store.csv | awk -F, 'NR==1; NR > 1 && $5 ~ /横浜/'
```

```
store_cd,store_name,prefecture_cd,prefecture,address,address_kana,tel_no,longitude,latitude,floor_area
S14010,菊名店,14,神奈川県,神奈川県横浜市港北区菊名一丁目,カナガワケンヨコハマシコウホククキクナイッチョウメ,045-123-4032,139.6326,35.50049,1732.0
S14033,阿久和店,14,神奈川県,神奈川県横浜市瀬谷区阿久和西一丁目,カナガワケンヨコハマシセヤクアクワニシイッチョウメ,045-123-4043,139.4961,35.45918,1495.0
S14040,長津田店,14,神奈川県,神奈川県横浜市緑区長津田みなみ台五丁目,カナガワケンヨコハマシミドリクナガツタミナミダイゴチョウメ,045-123-4046,139.4994,35.52398,1548.0
S14050,阿久和西店,14,神奈川県,神奈川県横浜市瀬谷区阿久和西一丁目,カナガワケンヨコハマシセヤクアクワニシイッチョウメ,045-123-4053,139.4961,35.45918,1830.0
S14028,二ツ橋店,14,神奈川県,神奈川県横浜市瀬谷区二ツ橋町,カナガワケンヨコハマシセヤクフタツバシチョウ,045-123-4042,139.4963,35.46304,1574.0
S14012,本牧和田店,14,神奈川県,神奈川県横浜市中区本牧和田,カナガワケンヨコハマシナカクホンモクワダ,045-123-4034,139.6582,35.42156,1341.0
S14046,北山田店,14,神奈川県,神奈川県横浜市都筑区北山田一丁目,カナガワケンヨコハマシツヅキクキタヤマタイッチョウメ,045-123-4049,139.5916,35.56189,831.0
S14011,日吉本町店,14,神奈川県,神奈川県横浜市港北区日吉本町四丁目,カナガワケンヨコハマシコウホククヒヨシホンチョウヨンチョウメ,045-123-4033,139.6316,35.54655,890.0
S14048,中川中央店,14,神奈川県,神奈川県横浜市都筑区中川中央二丁目,カナガワケンヨコハマシツヅキクナカガワチュウオウニチョウメ,045-123-4051,139.5758,35.54912,1657.0
S14042,新山下店,14,神奈川県,神奈川県横浜市中区新山下二丁目,カナガワケンヨコハマシナカクシンヤマシタニチョウメ,045-123-4047,139.6593,35.43894,1044.0
S14006,葛が谷店,14,神奈川県,神奈川県横浜市都筑区葛が谷,カナガワケンヨコハマシツヅキククズガヤ,045-123-4031,139.5633,35.53573,1886.0
```

### Q13

**顧客テーブル（df_customer）から、ステータスコード（status_cd）の先頭がアルファベットのA～Fで始まるデータを全項目抽出し、10件だけ表示せよ。**

```bash
#!/bin/bash

# Q10の正規表現前方一致版
cat ./data/customer.csv | awk -F, 'NR==1; NR > 1 && $11 ~ /^[A-F]/' | head -n 10
```

```
customer_id,customer_name,gender_cd,gender,birth_day,age,postal_cd,address,application_store_cd,application_date,status_cd
CS031415000172,宇多田 貴美子,1,女性,1976-10-04,42,151-0053,東京都渋谷区代々木**********,S13031,20150529,D-20100325-C
CS015414000103,奥野 陽子,1,女性,1977-08-09,41,136-0073,東京都江東区北砂**********,S13015,20150722,B-20100609-B
CS011215000048,芦田 沙耶,1,女性,1992-02-01,27,223-0062,神奈川県横浜市港北区日吉本町**********,S14011,20150228,C-20100421-9
CS029415000023,梅田 里穂,1,女性,1976-01-17,43,279-0043,千葉県浦安市富士見**********,S12029,20150610,D-20100918-E
CS035415000029,寺沢 真希,9,不明,1977-09-27,41,158-0096,東京都世田谷区玉川台**********,S13035,20141220,F-20101029-F
CS031415000106,宇野 由美子,1,女性,1970-02-26,49,151-0053,東京都渋谷区代々木**********,S13031,20150201,F-20100511-E
CS029215000025,石倉 美帆,1,女性,1993-09-28,25,279-0022,千葉県浦安市今川**********,S12029,20150708,B-20100820-C
CS033605000005,猪股 雄太,0,男性,1955-12-05,63,246-0031,神奈川県横浜市瀬谷区瀬谷**********,S14033,20150425,F-20100917-E
CS033415000229,板垣 菜々美,1,女性,1977-11-07,41,246-0021,神奈川県横浜市瀬谷区二ツ橋町**********,S14033,20150712,F-20100326-E
```

### Q14

**顧客テーブル（df_customer）から、ステータスコード（status_cd）の末尾が数字の1～9で終わるデータを全項目抽出し、10件だけ表示せよ。**


```bash
#!/bin/bash

# 正規表現後方一致版
cat ./data/customer.csv | awk -F, 'NR==1; NR > 1 && $11 ~ /[1-9]$/' | head -n 10
```

```
customer_id,customer_name,gender_cd,gender,birth_day,age,postal_cd,address,application_store_cd,application_date,status_cd
CS001215000145,田崎 美紀,1,女性,1995-03-29,24,144-0055,東京都大田区仲六郷**********,S13001,20170605,6-20090929-2
CS033513000180,安斎 遥,1,女性,1962-07-11,56,241-0823,神奈川県横浜市旭区善部町**********,S14033,20150728,6-20080506-5
CS011215000048,芦田 沙耶,1,女性,1992-02-01,27,223-0062,神奈川県横浜市港北区日吉本町**********,S14011,20150228,C-20100421-9
CS040412000191,川井 郁恵,1,女性,1977-01-05,42,226-0021,神奈川県横浜市緑区北八朔町**********,S14040,20151101,1-20091025-4
CS009315000023,皆川 文世,1,女性,1980-04-15,38,154-0012,東京都世田谷区駒沢**********,S13009,20150319,5-20080322-1
CS015315000033,福士 璃奈子,1,女性,1983-03-17,36,135-0043,東京都江東区塩浜**********,S13015,20141024,4-20080219-3
CS023513000066,神戸 そら,1,女性,1961-12-17,57,210-0005,神奈川県川崎市川崎区東田町**********,S14023,20150915,5-20100524-9
CS035513000134,市川 美帆,1,女性,1960-03-27,59,156-0053,東京都世田谷区桜**********,S13035,20150227,8-20100711-9
CS001515000263,高松 夏空,1,女性,1962-11-09,56,144-0051,東京都大田区西蒲田**********,S13001,20160812,1-20100804-1
```

### Q15

**顧客テーブル（df_customer）から、ステータスコード（status_cd）の先頭がアルファベットのA～Fで始まり、末尾が数字の1～9で終わるデータを全項目抽出し、10件だけ表示せよ。**

```bash
#!/bin/bash

# AND条件でQ13,Q14を書く
cat ./data/customer.csv | awk -F, 'NR==1; NR > 1 && $11 ~ /[1-9]$/ && $11 ~ /^[A-F]/' | head -n 10
```

```
customer_id,customer_name,gender_cd,gender,birth_day,age,postal_cd,address,application_store_cd,application_date,status_cd
CS011215000048,芦田 沙耶,1,女性,1992-02-01,27,223-0062,神奈川県横浜市港北区日吉本町**********,S14011,20150228,C-20100421-9
CS022513000105,島村 貴美子,1,女性,1962-03-12,57,249-0002,神奈川県逗子市山の根**********,S14022,20150320,A-20091115-7
CS001515000096,水野 陽子,9,不明,1960-11-29,58,144-0053,東京都大田区蒲田本町**********,S13001,20150614,A-20100724-7
CS013615000053,西脇 季衣,1,女性,1953-10-18,65,261-0026,千葉県千葉市美浜区幕張西**********,S12013,20150128,B-20100329-6
CS020412000161,小宮 薫,1,女性,1974-05-21,44,174-0042,東京都板橋区東坂下**********,S13020,20150822,B-20081021-3
CS001215000097,竹中 あさみ,1,女性,1990-07-25,28,146-0095,東京都大田区多摩川**********,S13001,20170315,A-20100211-2
CS035212000007,内村 恵梨香,1,女性,1990-12-04,28,152-0023,東京都目黒区八雲**********,S13035,20151013,B-20101018-6
CS002515000386,野田 コウ,1,女性,1963-05-30,55,185-0013,東京都国分寺市西恋ケ窪**********,S13002,20160410,C-20100127-8
CS001615000372,稲垣 寿々花,1,女性,1956-10-29,62,144-0035,東京都大田区南蒲田**********,S13001,20170403,A-20100104-1
```

### Q16

**店舗テーブル（df_store）から、電話番号（tel_no）が3桁-3桁-4桁のデータを全項目表示せよ。**

```bash
#!/bin/bash

cat ./data/store.csv | awk -F, 'NR == 1; NR > 1 && $7 ~ /[0-9]{3}-[0-9]{3}-[0-9]{4}/'
```

```
store_cd,store_name,prefecture_cd,prefecture,address,address_kana,tel_no,longitude,latitude,floor_area
S12014,千草台店,12,千葉県,千葉県千葉市稲毛区千草台一丁目,チバケンチバシイナゲクチグサダイイッチョウメ,043-123-4003,140.118,35.63559,1698.0
S13002,国分寺店,13,東京都,東京都国分寺市本多二丁目,トウキョウトコクブンジシホンダニチョウメ,042-123-4008,139.4802,35.70566,1735.0
S14010,菊名店,14,神奈川県,神奈川県横浜市港北区菊名一丁目,カナガワケンヨコハマシコウホククキクナイッチョウメ,045-123-4032,139.6326,35.50049,1732.0
S14033,阿久和店,14,神奈川県,神奈川県横浜市瀬谷区阿久和西一丁目,カナガワケンヨコハマシセヤクアクワニシイッチョウメ,045-123-4043,139.4961,35.45918,1495.0
S14036,相模原中央店,14,神奈川県,神奈川県相模原市中央二丁目,カナガワケンサガミハラシチュウオウニチョウメ,042-123-4045,139.3716,35.57327,1679.0
S14040,長津田店,14,神奈川県,神奈川県横浜市緑区長津田みなみ台五丁目,カナガワケンヨコハマシミドリクナガツタミナミダイゴチョウメ,045-123-4046,139.4994,35.52398,1548.0
S14050,阿久和西店,14,神奈川県,神奈川県横浜市瀬谷区阿久和西一丁目,カナガワケンヨコハマシセヤクアクワニシイッチョウメ,045-123-4053,139.4961,35.45918,1830.0
S13052,森野店,13,東京都,東京都町田市森野三丁目,トウキョウトマチダシモリノサンチョウメ,042-123-4030,139.4383,35.55293,1087.0
S14028,二ツ橋店,14,神奈川県,神奈川県横浜市瀬谷区二ツ橋町,カナガワケンヨコハマシセヤクフタツバシチョウ,045-123-4042,139.4963,35.46304,1574.0
S14012,本牧和田店,14,神奈川県,神奈川県横浜市中区本牧和田,カナガワケンヨコハマシナカクホンモクワダ,045-123-4034,139.6582,35.42156,1341.0
S14046,北山田店,14,神奈川県,神奈川県横浜市都筑区北山田一丁目,カナガワケンヨコハマシツヅキクキタヤマタイッチョウメ,045-123-4049,139.5916,35.56189,831.0
S14022,逗子店,14,神奈川県,神奈川県逗子市逗子一丁目,カナガワケンズシシズシイッチョウメ,046-123-4036,139.5789,35.29642,1838.0
S14011,日吉本町店,14,神奈川県,神奈川県横浜市港北区日吉本町四丁目,カナガワケンヨコハマシコウホククヒヨシホンチョウヨンチョウメ,045-123-4033,139.6316,35.54655,890.0
S13016,小金井店,13,東京都,東京都小金井市本町一丁目,トウキョウトコガネイシホンチョウイッチョウメ,042-123-4015,139.5094,35.70018,1399.0
S14034,川崎野川店,14,神奈川県,神奈川県川崎市宮前区野川,カナガワケンカワサキシミヤマエクノガワ,044-123-4044,139.5998,35.57693,1318.0
S14048,中川中央店,14,神奈川県,神奈川県横浜市都筑区中川中央二丁目,カナガワケンヨコハマシツヅキクナカガワチュウオウニチョウメ,045-123-4051,139.5758,35.54912,1657.0
S12007,佐倉店,12,千葉県,千葉県佐倉市上志津,チバケンサクラシカミシヅ,043-123-4001,140.1452,35.71872,1895.0
S14026,辻堂西海岸店,14,神奈川県,神奈川県藤沢市辻堂西海岸二丁目,カナガワケンフジサワシツジドウニシカイガンニチョウメ,046-123-4040,139.4466,35.32464,1732.0
S13041,八王子店,13,東京都,東京都八王子市大塚,トウキョウトハチオウジシオオツカ,042-123-4026,139.4235,35.63787,810.0
S14049,川崎大師店,14,神奈川県,神奈川県川崎市川崎区中瀬三丁目,カナガワケンカワサキシカワサキクナカゼサンチョウメ,044-123-4052,139.7327,35.53759,962.0
S14023,川崎店,14,神奈川県,神奈川県川崎市川崎区本町二丁目,カナガワケンカワサキシカワサキクホンチョウニチョウメ,044-123-4037,139.7028,35.53599,1804.0
S13018,清瀬店,13,東京都,東京都清瀬市松山一丁目,トウキョウトキヨセシマツヤマイッチョウメ,042-123-4017,139.5178,35.76885,1220.0
S14027,南藤沢店,14,神奈川県,神奈川県藤沢市南藤沢,カナガワケンフジサワシミナミフジサワ,046-123-4041,139.4896,35.33762,1521.0
S14021,伊勢原店,14,神奈川県,神奈川県伊勢原市伊勢原四丁目,カナガワケンイセハラシイセハラヨンチョウメ,046-123-4035,139.3129,35.40169,962.0
S14047,相模原店,14,神奈川県,神奈川県相模原市千代田六丁目,カナガワケンサガミハラシチヨダロクチョウメ,042-123-4050,139.3748,35.55959,1047.0
S12013,習志野店,12,千葉県,千葉県習志野市芝園一丁目,チバケンナラシノシシバゾノイッチョウメ,047-123-4002,140.022,35.66122,808.0
S14042,新山下店,14,神奈川県,神奈川県横浜市中区新山下二丁目,カナガワケンヨコハマシナカクシンヤマシタニチョウメ,045-123-4047,139.6593,35.43894,1044.0
S12030,八幡店,12,千葉県,千葉県市川市八幡三丁目,チバケンイチカワシヤワタサンチョウメ,047-123-4005,139.924,35.72318,1162.0
S14025,大和店,14,神奈川県,神奈川県大和市下和田,カナガワケンヤマトシシモワダ,046-123-4039,139.468,35.43414,1011.0
S14045,厚木店,14,神奈川県,神奈川県厚木市中町二丁目,カナガワケンアツギシナカチョウニチョウメ,046-123-4048,139.3651,35.44182,980.0
S12029,東野店,12,千葉県,千葉県浦安市東野一丁目,チバケンウラヤスシヒガシノイッチョウメ,047-123-4004,139.8968,35.65086,1101.0
S12053,高洲店,12,千葉県,千葉県浦安市高洲五丁目,チバケンウラヤスシタカスゴチョウメ,047-123-4006,139.9176,35.63755,1555.0
S14024,三田店,14,神奈川県,神奈川県川崎市多摩区三田四丁目,カナガワケンカワサキシタマクミタヨンチョウメ,044-123-4038,139.5424,35.6077,972.0
S14006,葛が谷店,14,神奈川県,神奈川県横浜市都筑区葛が谷,カナガワケンヨコハマシツヅキククズガヤ,045-123-4031,139.5633,35.53573,1886.0
```

### Q17

**顧客テーブル（df_customer）を生年月日（birth_day）で高齢順にソートし、先頭10件を全項目表示せよ。**

```bash
#!/bin/bash

# sortコマンドで特定の列に対して昇順
head -n 1 ./data/customer.csv; cat ./data/customer.csv | LC_ALL=C sort -t$',' -k5 | head -n 10
```

```
customer_id,customer_name,gender_cd,gender,birth_day,age,postal_cd,address,application_store_cd,application_date,status_cd
CS003813000014,村山 菜々美,1,女性,1928-11-26,90,182-0007,東京都調布市菊野台**********,S13003,20160214,0-00000000-0
CS026813000004,吉村 朝陽,1,女性,1928-12-14,90,251-0043,神奈川県藤沢市辻堂元町**********,S14026,20150723,0-00000000-0
CS018811000003,熊沢 美里,1,女性,1929-01-07,90,204-0004,東京都清瀬市野塩**********,S13018,20150403,0-00000000-0
CS027803000004,内村 拓郎,0,男性,1929-01-12,90,251-0031,神奈川県藤沢市鵠沼藤が谷**********,S14027,20151227,0-00000000-0
CS013801000003,天野 拓郎,0,男性,1929-01-15,90,274-0824,千葉県船橋市前原東**********,S12013,20160120,0-00000000-0
CS001814000022,鶴田 里穂,1,女性,1929-01-28,90,144-0045,東京都大田区南六郷**********,S13001,20161012,A-20090415-7
CS016815000002,山元 美紀,1,女性,1929-02-22,90,184-0005,東京都小金井市桜町**********,S13016,20150629,C-20090923-C
CS009815000003,中田 里穂,1,女性,1929-04-08,89,154-0014,東京都世田谷区新町**********,S13009,20150421,D-20091021-E
CS005813000015,金谷 恵梨香,1,女性,1929-04-09,89,165-0032,東京都中野区鷺宮**********,S13005,20150506,0-00000000-0
CS012813000013,宇野 南朋,1,女性,1929-04-09,89,231-0806,神奈川県横浜市中区本牧町**********,S14012,20150712,0-00000000-0
```

### Q18

**顧客テーブル（df_customer）を生年月日（birth_day）で若い順にソートし、先頭10件を全項目表示せよ。**

```bash
#!/bin/bash

# Q17の降順版
head -n 1 ./data/customer.csv; cat ./data/customer.csv | awk -F, 'NR > 1' | LS_ALL=C sort -t$',' -k5r | head -n 10
```

```
customer_id,customer_name,gender_cd,gender,birth_day,age,postal_cd,address,application_store_cd,application_date,status_cd
CS035114000004,大村 美里,1,女性,2007-11-25,11,156-0053,東京都世田谷区桜**********,S13035,20150619,6-20091205-6
CS022103000002,福山 はじめ,9,不明,2007-10-02,11,249-0006,神奈川県逗子市逗子**********,S14022,20160909,0-00000000-0
CS002113000009,柴田 真悠子,1,女性,2007-09-17,11,184-0014,東京都小金井市貫井南町**********,S13002,20160304,0-00000000-0
CS004115000014,松井 京子,1,女性,2007-08-09,11,165-0031,東京都中野区上鷺宮**********,S13004,20161120,1-20081231-1
CS002114000010,山内 遥,1,女性,2007-06-03,11,184-0015,東京都小金井市貫井北町**********,S13002,20160920,6-20100510-1
CS025115000002,小柳 夏希,1,女性,2007-04-18,11,245-0018,神奈川県横浜市泉区上飯田町**********,S14025,20160116,D-20100913-D
CS002113000025,広末 まなみ,1,女性,2007-03-30,12,184-0015,東京都小金井市貫井北町**********,S13002,20171030,0-00000000-0
CS033112000003,長野 美紀,1,女性,2007-03-22,12,245-0051,神奈川県横浜市戸塚区名瀬町**********,S14033,20150606,0-00000000-0
CS007115000006,福岡 瞬,1,女性,2007-03-10,12,285-0845,千葉県佐倉市西志津**********,S12007,20151118,F-20101016-F
CS014113000008,矢口 莉緒,1,女性,2007-03-05,12,260-0041,千葉県千葉市中央区東千葉**********,S12014,20150622,3-20091108-6
```


### Q19

**レシート明細テーブル（df_receipt）に対し、1件あたりの売上金額（amount）が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID（customer_id）、売上金額（amount）、付与したランクを表示させること。なお、売上金額（amount）が等しい場合は同一順位を付与するものとする。**

```bash
#!/bin/bash

# 1件あたりの売上金額が一番高い値を取得
compare_amount=$(cat ./data/receipt.csv | awk -F, 'NR > 1' | LC_ALL=C sort -t$',' -k9nr | head -n 1 | awk -F, '{ print $9 }')


# 1行目を用いて6列目、9列目、rankのカラムを作成、2行目以降をamount降順で並べ替えた後、compare_amount変数を使って同順位を考慮した順位を生成
head -n 1 ./data/receipt.csv | awk -F, '{ print $6,$9,"rank"}'; cat ./data/receipt.csv | awk -F, 'NR > 1' | LC_ALL=C sort -t$',' -k9nr | awk -F, -v compare_amount="$compare_amount" '
BEGIN { rank = 0; count = 0; compare_amount = $compare_amount }
{
	if (compare_amount != $9) {
		rank = count + 1;
		compare_amount = $9;
	}
	count++;
	print $6, $9, rank;
}' | head -n 10
```

```
customer_id amount rank
CS011415000006 10925 1
ZZ000000000000 6800 2
CS028605000002 5780 3
CS015515000034 5480 4
ZZ000000000000 5480 4
ZZ000000000000 5480 4
ZZ000000000000 5440 7
CS021515000089 5440 7
CS039415000073 5280 9
CS032414000072 5280 9
```

### Q20

**レシート明細テーブル（df_receipt）に対し、1件あたりの売上金額（amount）が高い順にランクを付与し、先頭10件を抽出せよ。項目は顧客ID（customer_id）、売上金額（amount）、付与したランクを表示させること。なお、売上金額（amount）が等しい場合でも別順位を付与すること。**

```bash
#!/bin/bash


# amount降順にして、1ずつ足した数字を描画していくだけ
head -n 1 ./data/receipt.csv | awk -F, '{ print $6,$9,"rank"}'; cat ./data/receipt.csv | awk -F, 'NR > 1' | LC_ALL=C sort -t$',' -k9nr | awk -F, '
BEGIN { rank = 1; }
{
	print $6, $9, rank;
	rank++;
}' | head -n 10
```

```
customer_id amount rank
CS011415000006 10925 1
ZZ000000000000 6800 2
CS028605000002 5780 3
CS015515000034 5480 4
ZZ000000000000 5480 5
ZZ000000000000 5480 6
ZZ000000000000 5440 7
CS021515000089 5440 8
CS039415000073 5280 9
CS032414000072 5280 10
```

### Q21

**レシート明細テーブル（df_receipt）に対し、件数をカウントせよ。**

```bash
#!/bin/bash

# tailで列を除外してwc -lで行数カウント
tail -n +2 ./data/receipt.csv | wc -l
```

```
104681
```


### Q22

**レシート明細テーブル（df_receipt）の顧客ID（customer_id）に対し、ユニーク件数をカウントせよ。**

```bash
#!/bin/bash

# customer_idだけをawkで取り出し、sortしてからuniqコマンドでユニークな値だけにした後、wcで行数カウント
cat ./data/receipt.csv | awk -F, 'NR > 1 { print $6 }' | LC_ALL=C sort | LC_ALL=C uniq | wc -l
```

```
8307
```


### Q23

**レシート明細テーブル（df_receipt）に対し、店舗コード（store_cd）ごとに売上金額（amount）と売上数量（quantity）を合計せよ。**

```bash
#!/bin/bash

echo "store_code,sum_amount,sum_quantity";
tail -n +2 ./data/receipt.csv | awk -F, '
{
	if($0 != "") {
		a[$3]+=$9; # a[store_cd]にamountをSUM
		b[$3]+=$8; # b[store_cd]にquantityをSUM
	}
}
END {
	for(i in a) {
		print i","a[i]","b[i]; # ENDで結果をprint
	}
}
' | LC_ALL=C sort -t$',' -k1 # 問題文的に不要だがソート

```

```
store_code,sum_amount,sum_quantity
S12007,638761,2099
S12013,787513,2425
S12014,725167,2358
S12029,794741,2555
S12030,684402,2403
S13001,811936,2347
S13002,727821,2340
S13003,764294,2197
S13004,779373,2390
S13005,629876,2004
S13008,809288,2491
S13009,808870,2486
S13015,780873,2248
S13016,793773,2432
S13017,748221,2376
S13018,790535,2562
S13019,827833,2541
S13020,796383,2383
S13031,705968,2336
S13032,790501,2491
S13035,715869,2219
S13037,693087,2344
S13038,708884,2337
S13039,611888,1981
S13041,728266,2233
S13043,587895,1881
S13044,520764,1729
S13051,107452,354
S13052,100314,250
S14006,712839,2284
S14010,790361,2290
S14011,805724,2434
S14012,720600,2412
S14021,699511,2231
S14022,651328,2047
S14023,727630,2258
S14024,736323,2417
S14025,755581,2394
S14026,824537,2503
S14027,714550,2303
S14028,786145,2458
S14033,725318,2282
S14034,653681,2024
S14036,203694,635
S14040,701858,2233
S14042,534689,1935
S14045,458484,1398
S14046,412646,1354
S14047,338329,1041
S14048,234276,769
S14049,230808,788
S14050,167090,580
```

### Q24

**レシート明細テーブル（df_receipt）に対し、顧客ID（customer_id）ごとに最も新しい売上日（sales_ymd）を求め、10件表示せよ。**

```bash
#!/bin/bash

echo "customer_id,max_sales_ymd";
tail -n +2 ./data/receipt.csv | awk -F, '
{
	if(a[$6] < $1) { # customer_id毎にsales_ymdが大きい場合はa[customer_id]に代入
		a[$6]=$1;
	}
}
END {
	for(i in a) {
		print i","a[i];
	}
}
' | head -n 10
```

```
customer_id,max_sales_ymd
CS018311000042,20170426
CS031414000033,20191001
CS020615000096,20190104
CS032215000068,20190518
CS005414000110,20190610
CS039515000090,20191010
CS001414000238,20190114
CS004414000037,20190116
CS037211000010,20190707
CS039515000092,20190831
```

### Q25

**レシート明細テーブル（df_receipt）に対し、顧客ID（customer_id）ごとに最も古い売上日（sales_ymd）を求め、10件表示せよ。**

```bash
#!/bin/bash

echo "customer_id,min_sales_ymd";

# 「もっとも古い」は未定義変数の初期値の関係でQ24のように求められないため、ソートしてからcustomer_idごとに最初の行を表示。uniqでも可能。
tail -n +2 ./data/receipt.csv | LC_ALL=C sort -t, -k6 -k1n | awk -F, '
{
	if (prev != $6) {
		print $6","$1
		prev = $6
	}
}
' | head -n 10


```

```
customer_id,min_sales_ymd
CS001113000004,20190308
CS001114000005,20190731
CS001115000010,20180701
CS001205000004,20180821
CS001205000006,20180521
CS001211000025,20190322
CS001212000027,20170127
CS001212000031,20180906
CS001212000046,20170811
CS001212000070,20191018
```


### Q26

**レシート明細テーブル（df_receipt）に対し、顧客ID（customer_id）ごとに最も新しい売上日（sales_ymd）と古い売上日を求め、両者が異なるデータを10件表示せよ。**

```bash
#!/bin/bash

echo "customer_id,max_sales_ymd,min_sales_ymd";

# Q25スタイルで新しい売り上げを求める
maxdata=$(tail -n +2 ./data/receipt.csv | LC_ALL=C sort -t, -k6 -k1rn | awk -F, '
{
	if (prev != $6) {
		print $6","$1
		prev = $6
	}
}
')

# Q25
mindata=$(tail -n +2 ./data/receipt.csv | LC_ALL=C sort -t, -k6 -k1n | awk -F, '
{
	if (prev != $6) {
		print $6","$1
		prev = $6
	}
}
')


# それぞれファイルに書き出してpasteで横づけ
printf "%s\n" $maxdata > /tmp/maxdata.txt
printf "%s\n" $mindata > /tmp/mindata.txt
paste -d, /tmp/maxdata.txt /tmp/mindata.txt > /tmp/minmaxdata.txt

# cutで列を指定した後、awkでminとmaxが異なる場合出力
cut -d "," -f 1,2,4 /tmp/minmaxdata.txt | awk -F, '
{
	if ($2 != $3) {
		print $0
	}	
}
' | head

```

```
customer_id,max_sales_ymd,min_sales_ymd
CS001415000114,20190224,20170327
CS002414000170,20190609,20180715
CS003412000377,20190926,20171027
CS005414000295,20190629,20190204
CS006414000015,20190428,20190227
CS006515000037,20181128,20171211
CS007514000094,20190721,20170717
CS007612000006,20181101,20180504
CS008414000048,20180123,20170328
CS008415000214,20180520,20170404
```


### Q27

**レシート明細テーブル（df_receipt）に対し、店舗コード（store_cd）ごとに売上金額（amount）の平均を計算し、降順でTOP5を表示せよ。**

```bash
#!/bin/bash

echo "store_code,sum_amount,count_amount";
tail -n +2 ./data/receipt.csv | awk -F, '
{
    if($0 != "") {
		a[$3]+=$9; # Q23のような形でamountをSUM
		b[$3]+=1;  # amountの件数を数える
    }
}
END {
        for(i in a) {
                print i","a[i]","b[i]","(a[i] / b[i]); # 合計/件数で平均を計算
        }
}
' | LC_ALL=C sort -t$',' -k4nr | head -n 5 # 平均部分を降順して表示

```

```
store_code,sum_amount,count_amount
S13052,100314,249,402.867
S13015,780873,2224,351.112
S13003,764294,2178,350.916
S14010,790361,2266,348.791
S13001,811936,2330,348.47
```

## さいごに

1行で書けるレベルの「件数」「ソート」「簡単な論理演算子による抽出」についてはやりやすいなと思いました。
順位や細かい集計は、別の方法で行ったほうが良さそうです。

ここまで見ていただきありがとうございました。