VARISTAで新型コロナウイルスの分析-データクレンジング編

#分析の目的
<img width="1388" alt="スクリーンショット 2020-04-24 19.51.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/e3771fdf-16b6-29bd-a3b1-bd46641c3f8b.png">

SIGNATEによって公開されている、オープンデータを利用して、コロナウイルスに感染することで**重症化する人の特徴**を分析することに挑戦してみました。
#データ
SIGNATEのCOVID-19フェーズ２コンペにリンクが載っている以下のデータを利用します。👇
https://drive.google.com/open?id=10MFfRQTblbOpuvOs_yjIYgntpMGBg592dL8veXoPpp4
<img width="1613" alt="スクリーンショット 2020-04-24 19.54.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/4bf6eee0-46e6-85be-babb-bb1c5553b797.png">
###データの構造
各行にコロナウイルス感染者一人一人のステータスが記録されています。
元データは12038行×32列となっています。

列には、年代、性別などの基本情報や、「軽症」、「重症」、「死亡」などのステータス、「熱」、「筋肉痛」などの症状一覧などもあります。

これらのデータを加工し、VARISTAで学習にかけられる状態にします。
#VARISTAについて
<img width="1679" alt="スクリーンショット 2020-04-24 20.02.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620435/1fd48d83-c780-6a93-35d0-636e2a2e417b.png">
SaaS型のAutoMLサービスで、環境構築することなく機械学習モデルを生成し推論することができます。
CSV, エクセルファイルなどのテーブルデータをXGBoost/LightGBMなどの多数アルゴリズムで学習を行い
アンサンブルモデルを自動生成してくれます。
基本プランは無料なので、誰でも気軽にデータ分析が行えます。
サイトはこちら👇
https://collesta.com/ja
新規登録は以下から行えます👇
https://console.varista.ai/user/register/
#データ加工
numpy, pandasを利用してデータを加工していきます⚡️

```python:prep.py
import pandas as pd
import numpy as np

df = pd.read_csv('covid19-case-dataset.csv')
```
###使わなそうな列削除
```python:prep.py
# Drop Columns
df = df.drop('退院済ﾌﾗｸﾞ', axis=1)
df = df.drop('情報源1', axis=1)
df = df.drop('情報源2', axis=1)
df = df.drop('都道府県症例番号', axis=1)
df = df.drop('備考', axis=1)
df = df.drop('行動歴', axis=1)
df = df.drop('厚労省コード', axis=1)
df = df.drop('公表日', axis=1)
df = df.drop('全国地方公共団体コード', axis=1)
df = df.drop('管理市区町村', axis=1)
df = df.drop('濃厚接触者状況', axis=1)
df = df.drop('都道府県コード', axis=1)
```
###年代をカテゴリ列から数値列に変換
```python:prep.py
# Age [60 - 69] -> [60]
def convert_age(x):
    if x is np.nan:
        return np.nan
    arr = x.split(' - ')
    if len(arr) == 2:
        age = arr[0]
    else:
        age = np.nan
    return age

df['年代'] = df['年代'].apply(convert_age)
```
###各症状のフラグを追加
「症状・経過」列にある単語を参照し、症状があるかどうかのフラグを追加していきます。

```python:prep.py
# 発熱の有無
def have_heating(x):
    if x is np.nan:
        return 0
    return 1 if '熱' in x else 0

df['発熱の有無'] = df['症状・経過']
df['発熱の有無'] = df['発熱の有無'].apply(have_heating)

# 咳の有無
def have_coughing(x):
    if x is np.nan:
        return 0
    return 1 if '咳' in x else 0

df['咳の有無'] = df['症状・経過']
df['咳の有無'] = df['咳の有無'].apply(have_coughing)

# 倦怠感の有無
def have_feeling_of_lethargy(x):
    if x is np.nan:
        return 0
    return 1 if '倦怠' in x else 0

df['倦怠の有無'] = df['症状・経過']
df['倦怠の有無'] = df['倦怠の有無'].apply(have_feeling_of_lethargy)

# 倦怠感の有無
def have_feeling_of_lethargy(x):
    if x is np.nan:
        return 0
    return 1 if '倦怠' in x else 0

df['倦怠の有無'] = df['症状・経過']
df['倦怠の有無'] = df['倦怠の有無'].apply(have_feeling_of_lethargy)

# 悪寒の有無
def have_chills(x):
    if x is np.nan:
        return 0
    return 1 if '悪寒' in x or '寒気' in x else 0

df['悪寒の有無'] = df['症状・経過']
df['悪寒の有無'] = df['悪寒の有無'].apply(have_chills)

# 筋肉痛の有無
def have_mascle_pain(x):
    if x is np.nan:
        return 0
    return 1 if '筋肉痛' in x else 0

df['筋肉痛の有無'] = df['症状・経過']
df['筋肉痛の有無'] = df['筋肉痛の有無'].apply(have_mascle_pain)

# 咽頭痛の有無
def have_soring_throat(x):
    if x is np.nan:
        return 0
    return 1 if '咽頭' in x or '喉' in x or 'のど' in x else 0

df['咽頭痛の有無'] = df['症状・経過']
df['咽頭痛の有無'] = df['咽頭痛の有無'].apply(have_soring_throat)

# 肺炎の有無
def have_pneumonia(x):
    if x is np.nan:
        return 0
    return 1 if '肺炎' in x else 0

df['肺炎の有無'] = df['症状・経過']
df['肺炎の有無'] = df['肺炎の有無'].apply(have_pneumonia)

# 鼻水の有無
def have_snot(x):
    if x is np.nan:
        return 0
    return 1 if '鼻' in x else 0

df['鼻水の有無'] = df['症状・経過']
df['鼻水の有無'] = df['鼻水の有無'].apply(have_snot)

# 味覚嗅覚異常の有無
def have_taste_disorder(x):
    if x is np.nan:
        return 0
    return 1 if '嗅覚' in x or '味覚' in x else 0

df['味覚嗅覚異常の有無'] = df['症状・経過']
df['味覚嗅覚異常の有無'] = df['味覚嗅覚異常の有無'].apply(have_taste_disorder)

# 呼吸苦の有無
def have_respiratory_distress(x):
    if x is np.nan:
        return 0
    return 1 if '呼吸苦' in x or '呼吸困難' in x or '息苦し' in x else 0

df['呼吸苦の有無'] = df['症状・経過']
df['呼吸苦の有無'] = df['呼吸苦の有無'].apply(have_respiratory_distress)

# 頭痛の有無
def have_headache(x):
    if x is np.nan:
        return 0
    return 1 if '頭痛' in x else 0

df['頭痛の有無'] = df['症状・経過']
df['頭痛の有無'] = df['頭痛の有無'].apply(have_headache)

# 吐き気の有無
def have_nausea(x):
    if x is np.nan:
        return 0
    return 1 if '嘔吐' in x or '吐き気' in x else 0

df['吐き気の有無'] = df['症状・経過']
df['吐き気の有無'] = df['吐き気の有無'].apply(have_nausea)

df = df.drop('症状・経過', axis=1)
```
この変換により、以下のような特徴を作り出します。

|症状・経過|熱の有無|吐き気の有無|肺炎症状の有無|
|--------|----:|---------:|---------:|
|熱あり|1|0|0|
|吐き気あり|0|1|0|
|熱と肺炎の症状あり|1|0|1|

###職業の表記揺れ修正
```python:prep.py
# 職業の表記揺れ修正
def fix_job_name(x):
    if x is np.nan:
        return np.nan
    if x == '非公表' or x == 'NA' or x == '不明' or '非公開' in x or '調査中' in x or '確認中' in x or '不詳' in x:
        return np.nan
    if 'パート' in x or 'アルバイ' in x or 'テナント従業員' in x or 'スーパー' in x or 'コーヒー' in x or '日々雇用' in x or '店勤務' in x:
        return 'パート/アルバイト'
    if '自営' in x or '自由業' in x or 'フリーランス' in x or '契約社員' in x or '経営者' in x:
        return '自営業'
    if '無職' in x or '入居者' in x or '患者' in x or '無 職' in x or '休職' in x or '専業主婦' in x or '施設' in x or 'フリーター' in x or 'なし' in x:
        return '無職'
    if '看護' in x or '医' in x or '病院' in x or 'リハビリ' in x or '薬' in x or '検疫' in x or '療法' in x or '整体' in x:
        return '医療系'
    if '講師' in x or '教師' in x or '園職員' in x or '教育' in x or '学校' in x or '非常勤' in x or '教員' in x or '教授' in x or '外国語' in x:
        return '教員'
    if '保育' in x or 'こども園' in x:
        return '保育'
    if '警察' in x:
        return '警察官'
    if '学生' in x:
        return '学生'
    if '県職員' in x or '団体職員' in x or '施設職員' in x or '役所' in x or '府職員' in x or '役場' in x or '税務職員' in x or '市職員' in x or '局勤務' in x or '市議' in x or '保健所職員' in x or '公務' in x or '局員' in x or '北海道' in x:
        return '公務員'
    if '介護' in x or '福祉' in x or '老人ホーム' in x or 'デイサービス' in x or 'デイケア' in x or '高齢者' in x:
        return '介護/福祉'
    if '事務' in x:
        return '事務'
    if '飲食' in x or 'バー' in x or '居酒屋' in x or '調理' in x:
        return '飲食'
    if '学生' in x or '高校生' in x or '就職予定' in x or '生徒' in x or '大生' in x or '大学' in x or '卒業生' in x:
        return '学生'
    if '運転' in x or 'ドライバ' in x or '乗務員' in x or '運送' in x or '運輸' in x or '配達' in x:
        return 'ドライバー/運送'
    if '選手' in x or 'スポーツ' in x or 'サッカー' in x or '柔道' in x:
        return 'スポーツ関係'
    if '会社' in x or '支店' in x or 'メーカー' in x or '支社' in x or '社員' in x or '本社' in x or '従業員' in x or '営業' in x or '販売' in x:
        return '会社員'
    if '接客' in x or 'インストラクター' in x or 'ガイド' in x or 'ツアー' in x or '旅行' in x:
        return 'サービス業'
    if '技術' in x or 'エンジニア' in x or '技師' in x:
        return '技術職'
    if '自衛' in x or '消防' in x:
        return '自衛隊/消防'
    if '工場' in x:
        return '工場'
    if '小売' in x or 'ワイナリー' in x:
        return '小売'
    if '土木' in x or '工事' in x or '建設' in x or '建築' in x:
        return '建設/土木'
    if 'あり' in x or '林檎' in x or 'ＪＲＡ' in x or 'ー' in x or '団体役員' in x or '千葉県' in x or '-' in x or 'JRA' in x:
        return 'その他'
    if '未就学' in x or '乳児' in x or '園児' in x or '幼児' in x or '児童' in x or '歳未満' in x:
        return '乳児/児童'

    arr = x.split('(')
    if len(arr) > 1:
        return arr[0]

    arr = x.split('（')
    if len(arr) > 1:
        return arr[0]
        
    return x

df['職業'] = df['職業'].apply(fix_job_name)
```
☝️この処理、結構実装面倒でしたが、正直重症化するかどうかの分析に職業があまり関係していないと思うので、無駄な努力かもしれません😭

###目的変数追加
今回は「重症化するかどうか」を予測したいので、ステータス列が「重症」、「死亡」の場合**1**、それ以外なら**0**となる列を追加し、それを予測させます。

```python:prep.py
# Target column
df['重症化'] = df['ステータス']
def is_critical(x):
    if x is np.nan:
        return 0
    if '重症' in x or '死' in x:
        return 1
    else: 0

df['重症化'] = df['重症化'].apply(is_critical)
df = df.drop('ステータス', axis=1)
```

###書き出し
```python:prep.py
df.to_csv('covid19-case-dataset-001.csv', index=False)
```

#つづく
これで学習に利用するデータが用意できました！
次の記事では実際にVARISTAで学習を行い、分析結果をまとめたいと思います。