【Pandas基礎】特定の文字列を含むデータを抽出したい

## はじめに

#### 自己紹介
Python勉強中の大学院生です。自分が詰まったところを記録していきます。
#### 記事を書くに至った経緯
pandasのデータフレームからある特定の文字列が含まれるデータだけ取り出す方法がわからなかったので、ここにメモとして残します。


## 本記事の概要
##### どんな人に読んでほしいか
- Pythonのpandasを学び始めた人
- pandasのdataframeから指定した文字列が含まれるデータのみを抽出する方法がわからない人

##### この記事に書くこと、わかること
文字列の指定によるデータ抽出の基本的な方法がわかります。今回整理する具体的なメソッドは以下の5つです。

- 完全一致
    - `==`　

- 部分一致
    - `df.contains()`
    - `df.startswith()`
    - `df.endswith()`

- 否定
    - `~`

## 具体的な方法
例として以下のデータを使用します。（データサイエンス100本ノックの問題を参考にしています）

```py:dataframeの作成
import pandas as pd

data = [['S12014', '千草台店', '千葉県', '千葉県千葉市稲毛区千草台一丁目'],
        ['C13002', '国分寺店', '東京都', '東京都国分寺市本多二丁目'],
        ['C14010', '菊名店', '神奈川県', '神奈川県横浜市港北区菊名一丁目'],
        ['S14033', '阿久和店', '神奈川県', '神奈川県横浜市瀬谷区阿久和西一丁目'],
        ['S13051', '板橋大原店', '東京都', '東京都板橋区大原町'],
        ['S14036', '相模原中央店', '神奈川県', '神奈川県相模原市中央二丁目'],
        ['H13015', '南砂店', '東京都', '東京都江東区南砂二丁目']]

columns = ['store_cd', 'store_name', 'prefecture', 'address']

df = pd.DataFrame(data=data, columns=columns)
df
```
実行結果
|   | store_cd|  store_name|  prefecture|  address|
|---|:---:|:---:|:---:|---:|
|0  |   S12014|   千草台店|  千葉県|  千葉県千葉市稲毛区千草台一丁目|
|1  |   C13002|   国分寺店|  東京都|  東京都国分寺市本多二丁目|
|2  |   C14010|   菊名店|  神奈川県|  神奈川県横浜市港北区菊名一丁目|
|3  |   S14033|   阿久和店|  神奈川県|  神奈川県横浜市瀬谷区阿久和西一丁目|
|4  |   S13051|   板橋大原店|  東京都|  東京都板橋区大原町|
|5  |   S14036|   相模原中央店|  神奈川県|  神奈川県相模原市中央二丁目|
|6  |   H13015|   南砂店|  東京都|  東京都江東区南砂二丁目|

ある飲食店の店舗データということにします。

### 指定した文字列が要素と完全一致するデータを抽出したい場合
今回であれば、店舗データからstore_cdがC13002のデータを抽出したいときは以下のようにして取得できます。

```py
df[df['store_cd'] == 'C13002']
```
実行結果
|   | store_cd|  store_name|  prefecture|  address|
|---|:---:|:---:|:---:|---:|
|1  |   C13002|   国分寺店|  東京都|  東京都国分寺市本多二丁目|

指定する文字列と一致する要素のdfの列を指定し、`==`を用いることで抽出することができました。

### 完全一致はしないが、特定の文字列を含むデータを抽出したい場合
この場合であれば、文字列メソッドである`str.contains()`を使うと、要素が特定の文字列を含むデータを抽出することができます。例えば、店舗データからaddressに'横浜市'が含まれるものだけを取り出したいときは以下のようにして取得できます。

```py
df[df['address'].str.contains('横浜市')]
```
実行結果
|   | store_cd|  store_name|  prefecture|  address|
|---|:---:|:---:|:---:|---:|
|2  |   C14010|   菊名店|  神奈川県|  神奈川県横浜市港北区菊名一丁目|
|3  |   S14033|   阿久和店|  神奈川県|  神奈川県横浜市瀬谷区阿久和西一丁目|

このように、横浜市を含むデータだけを取得することができました。

#### おまけ
特定の文字列から始まる・終わるデータを抽出したいという時もあると思います。その時は以下のメソッドを用います。

- `str.startswith()` 
- `str.endswith()`

使い方は`str.contains()`とほぼ同じです。例えば、store_cdのCから始まるデータだけを取り出したい場合は、

```py
df[df['store_cd'].str.startswith('C')]
```
実行結果
|   | store_cd|  store_name|  prefecture|  address|
|---|:---:|:---:|:---:|---:|
|1  |   C13002|   国分寺店|  東京都|  東京都国分寺市本多二丁目|
|2  |   C14010|   菊名店|  神奈川県|  神奈川県横浜市港北区菊名一丁目|

このようにstore_cdがCから始まるデータだけを抽出できました。`str.endswith()`も同じやり方で使うことができます。

逆に、store_cdがHから始まるデータ以外を取り出したい場合は、各メソッドの前に`~`を加えることで実行できます。

```py
df[~df['store_cd'].str.startswith('H')]
```
実行結果
|   | store_cd|  store_name|  prefecture|  address|
|---|:---:|:---:|:---:|---:|
|0  |   S12014|   千草台店|  千葉県|  千葉県千葉市稲毛区千草台一丁目|
|1  |   C13002|   国分寺店|  東京都|  東京都国分寺市本多二丁目|
|2  |   C14010|   菊名店|  神奈川県|  神奈川県横浜市港北区菊名一丁目|
|3  |   S14033|   阿久和店|  神奈川県|  神奈川県横浜市瀬谷区阿久和西一丁目|
|4  |   S13051|   板橋大原店|  東京都|  東京都板橋区大原町|
|5  |   S14036|   相模原中央店|  神奈川県|  神奈川県相模原市中央二丁目|

このようにしてstore_cdがHから始まるデータ以外の全てを取り出すことができました。この`~`は`str.contains()`の時も同じ使い方で用いることができます。

※Pandasでは`not`は使わずに`~`を使う必要があります。`not`を使うとエラーになってしまいます。

## まとめ
今回は、Pandasの文字列を使ったデータ抽出の基礎的なやり方についてまとめました。この記事で出てきたメソッドのまとめです。

- `==`（完全一致するデータを抽出）
- `df.contains()`（特定の文字列を含むデータを抽出）
- `df.startswith()`（特定の文字から始まるデータを抽出）
- `df.endswith()`（特定の文字で終わるデータを抽出）
- `~`（指定したメソッド以外を抽出）

また、文字列メソッドで条件を指定してデータを取り出す方法は`query()`メソッドでも代用可能です。`query()`についてはまた別の記事でまとめようと思います。

今回まとめたメソッドが使えるようになれば、データ抽出がより簡単になると思うのでしっかりマスターしたいと思います。

## 参考サイト
- [データサイエンス100本ノック](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess)

- より詳細な内容についてはこちら
[pandasで特定の文字列を含む行を抽出（完全一致、部分一致）](https://note.nkmk.me/python-pandas-str-contains-match/)

- queryについてはこちら
[pandas.DataFrameの行を条件で抽出するquery](https://note.nkmk.me/python-pandas-query/)