データサイエンス100本ノック（構造化データ加工編）をやってみた part1(P-001~P-016)

　この記事はデータサイエンスを勉強しながら、データサイエンス協会が提供する__データサイエンス100本ノック（構造化データ加工編）__を解く過程を自分用にまとめたものです。

|　チャプター　|　リンク　|　チャプター　|　リンク　|
|:------:|:----:|:------:|:---:|
|　P-001~P-016　|　[part1](https://qiita.com/pyon/items/c208e585e0cdfabc58bd)　|　P-052~P-062　|　[part6](https://qiita.com/pyon/items/5c5926241b8e6da978f3)　|
|　P-017~P-022　|　[part2](https://qiita.com/pyon/items/73bf9e8fe75f807aeea8)　|　P-063~P-068　|　[part7](https://qiita.com/pyon/items/ac8c7fb9110dbba061f5)　|
|　P-023~P-031　|　[part3](https://qiita.com/pyon/items/948ca309c7985fa2e855)　|　P-069~P-078　|　[part8](https://qiita.com/pyon/items/60daed73e5ff670e209d)　|
|　P-032~P-039　|　[part4](https://qiita.com/pyon/items/e7146bbb728979430814)　|　P-079~P-088　|　[part9](https://qiita.com/pyon/items/911e3d236fad8df13f44)　|
|　P-040~P-051　|　[part5](https://qiita.com/pyon/items/dac17fb162c99769978b)　| P-089~P-100 |　[part10](https://qiita.com/pyon/items/70c1e222914c658a480c)　|

+ `head()`
+ `rename()`
+ `query()`
+ 論理演算子(`AND`, `OR`, `NOT`)
+ 比較演算子(`==`, `!=`)
+ 文字列の先頭一致 `str.startswith()`
+ 文字列の末尾一致 `str.endswith()`
+ 文字列の部分一致 `str.contains()`
+ 正規表現を使用した文字列の検索

# P-001 `head()`
>P-001: レシート明細のデータフレーム（df_receipt）から全項目の先頭10件を表示し、どのようなデータを保有しているか目視で確認せよ。

```python:p001.py
df_receipt.head(10)
```

　`head()`：データフレームの先頭の行を返す
　(引数に整数を与えるとその分の行を表示する。デフォルトは5行。)
　`tail()`：データフレームの末尾の行を返す。

# P-002
>P-002: レシート明細のデータフレーム（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、10件表示させよ。

```python:p002.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "amount"]].head(10)
```

　データフレームの1つのカラムを参照する場合は`df['カラム名']`
　データフレームの複数のカラムを参照する場合は`df[['カラム1', 'カラム2', 'カラム3']]`

# P-003 `rename()`
>P-003: レシート明細のデータフレーム（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、10件表示させよ。ただし、sales_ymdはsales_dateに項目名を変更しながら抽出すること。

```python:p003.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "amount"]].rename(columns={'sales_ymd':'sales_date'}).head(10)
```

　`rename()`：データフレームの行名・列名を変更する。
　行名を変更 `df.rename(index={'変更したい行名':'新しい行名'})`
　列名を変更 `df.rename(columns={'変更したい列名':'新しい列名'})`
　(行名・列名を同時に変更することも複数変更することも可能)

# P-004 `query()`
>P-004: レシート明細のデータフレーム（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。
・顧客ID（customer_id）が"CS018205000001"

```python:p004.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "amount"]].query('customer_id == "CS018205000001"')
```

　`query()`：列の値に対する条件に応じて行を抽出する。
　比較演算子や文字列メソッドを使った条件指定、複数条件の組み合わせなどをかなり簡潔に記述できて便利。

# P-005 `&`
>P-005: レシート明細のデータフレーム（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。
・顧客ID（customer_id）が"CS018205000001"
・売上金額（amount）が1,000以上

```python:p005.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "amount"]].query('customer_id == "CS018205000001" & amount >= 1000 ')
```

　`&`：論理演算子 AND

# P-006 `|`
>P-006: レシート明細データフレーム「df_receipt」から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上数量（quantity）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。
・顧客ID（customer_id）が"CS018205000001"
・売上金額（amount）が1,000以上または売上数量（quantity）が5以上

```python:p006.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "quantity", "amount"]].query('customer_id == "CS018205000001" & (amount >= 1000 | quantity >= 5) ')
```

　`|`：論理演算子 OR

# P-007
>P-007: レシート明細のデータフレーム（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。
・顧客ID（customer_id）が"CS018205000001"
・売上金額（amount）が1,000以上2,000以下

```python:007.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "amount"]].query('customer_id == "CS018205000001" & 1000<= amount <= 2000')
```

　`1000<= amount <= 2000`：'amountが1000以上2000以下
　ANDを使って`1000<=amount | amount<=2000`とも書ける。

# P-008 `==`, `!=`
>P-008: レシート明細のデータフレーム（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。
・顧客ID（customer_id）が"CS018205000001"
・商品コード（product_cd）が"P071401019"以外

```python:p008.py
df_receipt[["sales_ymd", "customer_id", "product_cd", "amount"]].query('customer_id == "CS018205000001" & product_cd != "P071401019"')
```

　`==`：比較演算子　__左辺と右辺が同じ__場合`True`
　`!=`：比較演算子　__左辺と右辺が違う__場合`True`

# P-009 `not`
>P-009: 以下の処理において、出力結果を変えずにORをANDに書き換えよ。
`df_store.query('not(prefecture_cd == "13" | floor_area > 900)')`

```python:p009.py
df_store.query('prefecture_cd != "13" & floor_area <=900')
```
_　NOT( A OR B )_　↔️ _NOT(A) AND NOT(B)_
![ベン図.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751395/fccbefd5-cf70-8edd-f2a3-b63b46b8fdcd.jpeg)

# P-010 `str.startswith()`
>P-010: 店舗データフレーム（df_store）から、店舗コード（store_cd）が"S14"で始まるものだけ全項目抽出し、10件だけ表示せよ。

```python:p010.py
df_store.query('store_cd.str.startswith("S14")', engine='python').head(10)
```
　`str.startswith("文字列")`：特定の文字列で始まる場合`True`
　通常 query メソッドでは引数の条件に文字列メソッドを記述できないため、文字列メソッドを使用して条件を指定する場合は、query メソッドの引数にengine='python'と指定する。

# P-011 `str.endswith()`
>P-011: 顧客データフレーム（df_customer）から顧客ID（customer_id）の末尾が1のものだけ全項目抽出し、10件だけ表示せよ。

```python:p011.py
df_customer.query('customer_id.str.endswith("1")', engine='python').head(10)
```
　`str.endswith("文字列")`：特定の文字列で終わる場合`True`

# P-012 `str.contains()`
>P-012: 店舗データフレーム（df_store）から横浜市の店舗だけ全項目表示せよ。

```python:p012.py
df_store.query('address.str.contains("横浜市")', engine='python')
```
　`str.contains("文字列")`：特定の文字列を含む場合`True`

# P-013 `正規表現`
>P-013: 顧客データフレーム（df_customer）から、ステータスコード（status_cd）の先頭がアルファベットのA〜Fで始まるデータを全項目抽出し、10件だけ表示せよ。

```python:p013.py
df_customer.query('status_cd.str.contains("^[A-F]", regex=True)', engine='python').head(10)
```
　`^[A-F]`：正規表現　先頭の文字がA~Fで始まる場合`True`
　正規表現を使って判定したことを強調するため、引数に`regex=True`と書いた。(書かなくても動作はする。)

# P-014
>P-014: 顧客データフレーム（df_customer）から、ステータスコード（status_cd）の末尾が数字の1〜9で終わるデータを全項目抽出し、10件だけ表示せよ。

```python:p014.py
df_customer.query("status_cd.str.contains('[1-9]$', regex=True)", engine="python").head(10)
```
　`[1-9]$`：正規表現　末尾の文字が1~9の数字の場合`True`

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

```python:p015.py
df_customer.query("status_cd.str.contains('^[A-F].*[1-9]$', regex=True)", engine="python").head(10)
```
　`.`：任意の1文字
　`A*`：0文字以上のA('spo*n'の場合 'spn', 'spon', 'spoon', 'spooon'などにマッチ)
　つまり`.*`で__任意の1文字以上の文字__となる。

# P-016
>P-016: 店舗データフレーム（df_store）から、電話番号（tel_no）が3桁-3桁-4桁のデータを全項目表示せよ。

```python:p016.py
df_store.query("tel_no.str.contains('\d{3}-\d{3}-\d{4}', regex=True)", engine="python")
```
　`\d`：Unicode10進数
　`{n}`：n回
　つまり`\d{3}`で__0~9の数字が3つ並んだものと一致__となる。(`[0-9]{3}`でもOK)