データクレンジングする前に確認した方が良いと思ったこと

## はじめに
ぺーぺーですが、案件でデータサイエンスの分野の作業を行っています。
現在とあるデータの解析を行っていますが、何かにつけて『最初に確認しておけば…orz』ということが多かったため、備忘録のために残す&Updateしていきたいと思います。
「当たり前だろ？」と思われるかもしれませんが、ペーペーだったので気づかなかったのです…
「こんなんもあるよー」という観点をお持ちの方はコメント頂ければ幸いです。
なお、これは実体験に基づくものとそうでないものがありますので、超個人的見解である旨ご了承ください。

## 確認したい事
### データのメタデータを知る
データのメタデータ、いわゆるデータそのものの情報を確認する必要があります。
データ分析を行っている企業の大半は、外部企業からデータ分析を依頼されていると思います。そのため、前提情報なしにデータのみを提供される事が多いのではないでしょうか。
従って、具体的に個々のデータを見ていくことと並行して、そのデータが本当に正しいのか否か、という判断をする必要があると考えます。
確認したいと思った事を以下に挙げます。
特に明言していなければPythonコードはpyspark(df=DataFrame)を想定して記載しています。

#### データそのものの正当性

##### データが正しく読み込めるか

* 確認点
    * データの文字コードは何か
        * sparkやPythonなど使って解析する場合、大体がLinux(Unix)環境であるので、文字コード指定して読み込む必要がある
* 想定原因
    * 出力元と解析先の文字コードが異なる
        * WindowsOSから出力されたデータは、大体shift-jisになっている
* 確認方法
    * データの文字コードを調べる
* 確認方法例
    * Linuxコマンドの場合、以下のようなコマンドでファイル内が文字化けしていないか否かで判断できる
    * 
    ``` head -n 3 [ファイル名] ```

* 確認点
    * データ内に文章があるか
        * csvデータでデータ内に文章が含まれている場合、カラム毎に「"」が無いとアウト
            * 文章中の「,」や改行が判断つかないため
                * 頑張れば補完はできるかもしれないが、そもそも頑張る所ではないので可能であればデータを出し直してもらった方が良い
        * sparkの場合、特にエラーを出さず読み込めてしまうためデータ不備に気づけないので注意
            * pandasの場合はエラーになるため、csvが読み込めない時はこのような問題を想定するのも重要
* 想定原因
    * データ出力時の設定ミス
* 確認方法
    * データ1行ずつカラム数を確認する
* 確認方法例
    * スクリプトを作る


##### 想定されるデータ数が合致しているか

* 確認点
    * データ量が想定通りか
        * 過不足なくデータ量があるか
        * 多ければ(少なければ)その理由は何か
    * 重複したデータがないか
        * 重複したデータがある場合、データそのものの正当性が怪しいと思われる
* 想定原因
    * データのダウンロードに失敗している
    * 受領する前からデータが間違っている
* 確認方法
    * データの量(データ列の数)の確認
    * 重複行を除外したデータ量の確認
* 確認方法例

```shell:sample.sh
# 行数カウント
wc -l "対象ファイル"
```
```python:sample.py
# 全データのカウント
df.count()

# データの重複を除いたカウント その1
df.select("DBでいう主キーとなるカラム").distinct().count()

# データの重複を除いたカウント その2
df.groupBy("DBでいう主キーとなるカラム").count().count()
```

##### カラムに対して入力されている値が想定通りか

* 確認点
    * カラムに対して入力されうる値の範囲が決まっているか否か
        * 決まっているのであれば異常値は含まれていないか
    * カラムに入力されている値に揺らぎはないか
        * 名寄せ(統一化)が必要なのか
    * カラムに入力されている値は正しいか
        * 例えば「性別」に男/女という値は一般的に妥当であるが、データの値としてはM/Fのみであれば男/女は異常値である
* 想定原因
    * データ作成ロジック(システム)のミス
* 対策
    * カラムの想定値を提供元に確認する
    * カラムごとに入力値を確認する
* 確認方法例

```python:sample.py
# カラムの内容をgroupByで確認する
df.groupBy("対象のカラム").count().show()

# カラムの揺らぎをワイルドカード(like)で検索
df.where(df["対象のカラム"].like("%単語%")).groupBy("対象のカラム").count().show()

# 例えば値「hoge」を「fuga」に置き換える場合はこんな感じ
df = df.withColumn(
    "対象のカラム", when(df["対象のカラム"] == "hoge", "fuga").otherwise(df["対象のカラム"])
)
```

##### カラム間に関連があるか

* 確認点
    * カラムに対して関連するカラムが無いか
        * 例えば「姓名」や「性別」だけでは一般的に個人を特定できないため、他のカラムの値で個人を特定しているはず。そのカラムが何か
    * 関連するカラムに対して、矛盾の無い値になっているか
        * 例えば、「生年月日」と「年齢」があり、明らかに計算が合わないなど無いか
* 想定原因
    * データ作成時のミス
    * メタデータの情報共有不備
* 対策
    * カラム間の関連を提供元に確認する
    * カラム間の矛盾を確認する
* 確認方法例

```python:sample.py
# カラム1とカラム2の内容(組み合わせ)をgroupByで確認する
df.groupBy("対象のカラム1", "対象のカラム2").count().show()
```

##### カラムのデータが何を表しているか

* 確認点
    * カラムに入力されている値が何を意味しているのか
        * 例えば一口に「住所」といっても、県/市/町などデータの値として粒度がないか
    * 値として使用されている単語が何を意味しているか
        * データを作る人間と使う人間のバックグラウンドが違うので、単語の意味に齟齬がないか
    * そもそも使われているか
        * 使われていないが、「とりあえず確保しておく」というカラムもないこともない
* 想定原因
    * メタデータの情報共有不備
* 対策
    * カラムの想定値を提供元に確認する
* 確認方法例
    * 表など対応表を作る。

```python:sample.py
# カラムの入力率を確認する
df.count()
df.where(df["対象のカラム1"].isNull()).count()
```

##### データがどのように作られたか

* 確認点
    * 異常値の置き換えはされているか
        * 異常値は異常値として残っているのか
        * 置き換えているのであればどのように置き換えられているのか
        * 例えばNullが入力されてた場合でも、それは本来の意味で異常値なのか否か
    * データは複数のデータ(マスタデータ)を統合して作られたのか
        * 統合されている場合、どのように統合されているのか(例えばキーとなるカラムは何なのか)
        * 統合されている場合、統合前のデータは同じタイミングで取得したデータなのか(例えばデータAは2018年だがデータBは2017年など、時期が違うなどないか)
* 想定原因
    * メタデータの情報共有不備
* 対策
    * 提供元に確認する
    * 確認した上でどのように対策をするか決めておく
        * カバーできるのであればする/しないなど
        * カバーしきれないのであればその旨を共有する
* 確認方法例
    * 提供元に確認
    * プロジェクトオーナに共有


## 〆
今まで開発を行った経験なども踏まえ、やっておけば良かったと思ったことを列挙しました。
データを作成する(出力する)のは人間なので、データ作成者とデータ分析者との意識のすり合わせは大切だと感じました。