PythonのNumPyとFakerパッケージを使ってダミーデータを作成する

#なぜダミーデータにこだわるのか#
機械学習などのライブラリやツールを使う際に扱うデータはとても重要になります。データがなければ、デモを行うこともできません。実データを使うことが一番ですが、なかなか身近に求めているタイプの実データがないケースも多いと思います。最近は分析に使いやすい実データが一部の企業から[公開](http://www.nii.ac.jp/dsc/idr/datalist.html)されていますが、研究目的の使用に限られているなど、使用条件を満たせられないこともあります。

データがなければ自分で作ればいいということで、ダミーデータを自由に作れると便利です。
ダミーデータを作るにあたっては、その目的によって作り方に工夫が必要です。大きく分けると次の二つになると思います。

+ パフォーマンス測定としてのダミーデータ
+ データ分析としてのダミーデータ

パフォーマンス測定においては、全データ読み込み速度測定などシンプルなものであれば、データ量さえ合わせれば用件を満たすケースも多いと思います。ただ、圧縮率やSQLでデータに対して結合や絞り込みなどのある程度複雑なパフォーマンス測定を行う場合には、データのカーディナリティなどにもこだわる必要があります。すべての値が同じ状態でデータ量だけを合わせた場合では、実データに比べて異常にいい圧縮率が出たりと、使えない測定値となってしまうことがあります。

データ分析では、パフォーマンス測定で求められるものよりももう少し細かいシナリオを持ったダミーデータが必要となります。また、デモで見せる場合には、どんな分析結果なのかまでを見せることを考えるため、数字や意味のない文字列の羅列では格好がつきません。

今回は、データ分析で使うダミーデータを全部一様乱数で埋めるような寂しいものでなく、少しだけこだわって作成する場合の手順を紹介していきたいと思います。

#顧客データのダミーデータのシナリオをきめる#

顧客データを作るにあたって、どんな属性を持たせるかを決めます。以下の項目のダミーデータを作っていきたいと思います。

|属性|データ特性|例|
|:-:|:-:|:-:|
|顧客ID|一意な値|12345|
|顧客名|任意の日本語氏名|田中太郎|
|年齢|一様分布|30歳|
|身長|正規分布|176cm|
|年収|対数正規分布|456万円|
|車保有フラグ|0保有,1なし (4:6)|1|
|婚姻ステータス|0独身,1既婚,2離別 (3:6:1)|2

今回は説明のため、少なめですが、20~30属性くらいあればダミーデータとしては申し分ないと思います。

#Pythonで顧客ダミーデータを作ってみる#
今回はPythonを使ってダミーデータを作ってみます。
Pythonを選んだ理由としては、[NumPy](http://www.numpy.org)を使って様々な分布の値を生成できることと[Faker](https://github.com/joke2k/faker)というパッケージがなかなか便利だからです。(個人的に好きな言語という理由が一番大きいです)

##一意な顧客IDを作成する##
一意な値なので、シーケンスなどで順繰りに数字を作っていけば完了です。

```lang:python3.4.3
for i in range(1000)
    i
```

##任意の顧客名を作成する##
Fakerパッケージを利用すれば、簡単に名前などのダミーデータを作成可能です。データの種類は少なくなりましたが、各国ごとのデータも生成可能です。

```lang:python3.4.3
from faker import Faker
fake = Faker('ja_JP')
fake.name()
```

バラエティが豊富で苗字だけや、メールアドレスなども生成できます。日本語はどうしてもパターンが少ないですが、英語だと相当な種類があります。

```lang:python3.4.3
from faker import Faker
fake = Faker('ja_JP')
fake.last_name()
fake.email()
```

##一様分布の年齢データを作成する##
利用者の年齢ですので、一様分布で15~85までの値を乱数で発生させます。

```lang:python3.4.3 
import numpy as np
from numpy.random import *
randint(15,85)
```

##正規分布の身長データを作成する##
顧客データに身長が入っているケースとはどんなケースなのかと自分でもちょっと腑に落ちていないところはありますが、一般的に正規分布と言われる他の属性値が思いつかず身長としています。

```lang:python3.4.3 
import numpy as np
from numpy.random import *
normal(170,6)
```

男女で平均と分散は違うため、二回発生させればいい感じになると思います。また性別、年齢別の平均と分散が厚労省の調査結果で公開されているため、そちらにしたがって複数回正規分布を発生するととてもリアルなダミーデータになると思います。

##対数正規分布で年収データを作成する##
年収の平均が400万円代なのに中央値は200万円代と年収などは、平均値と中央値に大きなずれがあります。これははずれ値がある程度の数いることに起因します。金融業界とかだとファットテールとか言ったりします。そんなデータを作る場合には対数正規分布で乱数を生成していきましょう。

```lang:python3.4.3 
import numpy as np
from numpy.random import *
lognormal(0,1)
```

##車保有フラグを作成する##
データの中には、何々をしたことがある、何々を持っているなどyes,noで管理されるフラグと呼ばれるものがあります。基本的には0か1で管理されるので、いろいろな発生方法が考えられます。数字を生成して2で割って余りを使うなど。今回はもう少し直観的に車を保有している人を1とし、保有していない人を0として保有率を6割のデータを作成していきます。

```lang:python3.4.3 
import numpy as np
from numpy.random import *
CarFlagList = [0,1]
Weight = [0.4,0.6]
np.random.choice(CarFlagList,p=Weight)
```

##婚姻ステータスを作成する##
フラグと違って、二つの状態でなく、複数の状態になるものもあります。フラグの組み合わせで表現することも可能ですが、いたずらに属性を増やすのも管理性が悪いので、素直に複数の値を持たせることが一般的です。今回は婚姻ステータスとして0独身,1既婚,2離別と三種類のデータからの乱数を作成していきます。それぞれの割合は3対6対1とします。

```lang:python3.4.3 
import numpy as np
from numpy.random import *
MariageList = ["0独身","1既婚","2離別"]
Weight = [0.3,0.6,0.1]
np.random.choice(MariageList ,p=Weight)
```

先ほどの車保有フラグとほとんど同じ手順で乱数が作成できます。今回は数字じゃなく、文字列を値としていますが、ここらへんも柔軟に対応できるのが、便利なところです。

##まとめ##
一通りの乱数生成のパターンを書いたので、あとはこの組み合わせとFor文などでループを回せばシナリオごとのダミーデータを作成できます。とある案件で、70列のダミーデータを作りましたが、70列のそれぞれの重みとかを設定していくのが一番大変でした。。