[python] Dataframeから複数条件で行を抽出する

## やりたいこと
* ```dataframe```から複数条件で行を抽出したい
* データには欠損値が含まれる

## 試してみたこと
データ抽出にはいくつか方法があるようだけれど今回は下記の2つで試した
1. ```pandas```の```query```関数を使用する
2. ```query```を使わないで列名を使用する

## サンプルデータ
| ID | NAME| ADDRESS_1| ADDRESS_2| CORPORATIONNUMBER| COUNTRY|
|:-:|:-:|:-:|:-:|:-:|:-:|
| 12345  |まるばつ産業   | 東京都中央区  | 東京都千代田区  | 25671900  | JAPAN  |
|26890   |どれみ物産   | NaN  |  東京都港区 | 10008765  | JAPAN  |
| 66635  | abc corporation | NaN  |  NaN | 57682399   | USA |

## 抽出条件
1. COUNTRYがJAPANであること
2. ADDRESS_1があり、かつADDRESS_2もあること

## 抽出したい行
| ID | NAME| ADDRESS_1| ADDRESS_2| CORPORATIONNUMBER| COUNTRY|
|:-:|:-:|:-:|:-:|:-:|:-:|
| 12345  |まるばつ産業   | 東京都中央区  | 東京都千代田区  | 25671900  | JAPAN  |

## 出力したいカラム
**COUNTRY以外**を出力する

| ID | NAME| ADDRESS_1| ADDRESS_2| CORPORATIONNUMBER|
|:-:|:-:|:-:|:-:|:-:|:-:|
| 12345  |まるばつ産業   | 東京都中央区  | 東京都千代田区  | 25671900  |


## 条件式をつくる
1. COUNTRYがJAPANであること

```python:query
COUNTRY=='JAPAN'
```
```python:queryを使わない
df[COUNTRY]=='JAPAN'
```
2. ADDRESS_1があり、かつADDRESS_2もあること
 ＝ ADDRESS_1が欠損値（NaN）ではなく、ADDRESS_2も欠損値でない

```python:query
# and でつなぐ
ADDRESS_1.notna() and ADDRESS_2.notna()

# & でもよい
ADDRESS_1.notna() & ADDRESS_2.notna()
```
```python:queryを使わない
# & を使う
df[ADDRESS_1].notna() & df[ADDRESS_2].notna()
```

ちなみに「または」の条件の時はこうなる

```python:query
# or でつなぐ
ADDRESS_1.notna() or ADDRESS_2.notna()

# | でもよい
ADDRESS_1.notna() | ADDRESS_2.notna()
```
```python:queryを使わない
# | を使う
df[ADDRESS_1].notna() | df[ADDRESS_2].notna()
```

* ```query```では```and```や```or```が使えるが、```query```を使わない場合は使えないので注意

条件式を組み立てる

```python:query
# 条件を&でつないでダブルクォーテーションでくるむ
df.query("COUNTRY =='JAPAN' & ADDRESS_1.notna() & ADDRESS_2.notna()")
```
```python:queryを使わない
# 条件を&でつないでダブルクォーテーションでくるむ
df.query("df[COUNTRY] =='JAPAN' & df[ADDRESS_1].notna() & df[ADDRESS_2].notna()")
```

## 抽出したい列を選択する
* ```loc```を使う
* ```loc```[対象行:,(列名)] 

```python:列選択
# 全ての行を対象として'ID','NAME','ADDRESS_1','ADDRESS_2','CORPORATIONNUMBER'列を抽出する場合
loc[:,('ID','NAME','ADDRESS_1','ADDRESS_2','CORPORATIONNUMBER')]

# IDが12345の行を対象として'ID','NAME','ADDRESS_1','ADDRESS_2','CORPORATIONNUMBER'列を抽出する場合
loc['12345' :,('ID','NAME','ADDRESS_1','ADDRESS_2','CORPORATIONNUMBER')]
```

## サンプルコード
```python:test
import pandas as pd
import codecs

# 読み込むcsv
target = 'sample.csv'
# 出力先
out = 'output.tsv'

with codecs.open(target, mode='r', encoding='shift-jis', errors='ignore') as f:
    df = pd.read_csv(
            f,
            sep=',',
            engine='python',	# encodingのかわりにengine='python'にするとおまかせになるらしい
            # 特定のカラムだけ出力したい時は```usecols```で設定する
            usecols=[
                'ID',
                'NAME',
                'ADDRESS_1',
                'ADDRESS_2',
                'CORPORATIONNUMBER',
                'COUNTRY'
            ],
            # 一見数値に見えるカラムの値も文字として扱いたいので文字列にコンバートしておく
            # 何もしないと出力時に小数点以下がついたりするので注意
            converters={
                'ID': str,
                'CORPORATIONNUMBER': str,
                }
    )

    # データ抽出, 列選択
    result = df.query("COUNTRY =='JAPAN' & ADDRESS_1.notna() & ADDRESS_2.notna()").loc[:,('ID','NAME','ADDRESS_1','ADDRESS_2','CORPORATIONNUMBER')]

    # または
　　result = df.query("df[COUNTRY] =='JAPAN' & df[ADDRESS_1].notna() & df[ADDRESS_2].notna()").loc[:,('ID','NAME','ADDRESS_1','ADDRESS_2','CORPORATIONNUMBER')]

    # 出力
    result.to_csv(out, sep='\t',encoding='utf-8',index=False)
```