依存を可能な限り少なくして、irisデータセットの散布図を描きたい
グラフを描きたいと思ったときには以下の2つ場合がある
- 絵が描きたい
- データを分析したい(EDA)
今回は概ね前者の場合の話。ついでにnumpy,scipy,pandasなどに依存したくない。依存はこれだけ。
$ pip freeze pygal==2.4.0 vega-datasets==0.8.0
依存を可能な限り少なくして絵を描きたい
絵(グラフ)を描くためには以下2つが必要。
- データ(データセット)
- 描画方法
いちいち手元にファイルをダウンロードしてどこかに保存するということは面倒。 そして動かすのに依存が多いものもまた面倒。準備が可能な限り楽であってほしいし。不要な依存の読み込みなどで時間がかかってほしくもない。
irisデータセット
有名なやつ
This famous (Fisher's or Anderson's) iris data set gives the measurements in centimeters of the variables sepal length and width and petal length and width, respectively, for 50 flowers from each of 3 species of iris. The species are Iris setosa, versicolor, and virginica.
R
Rでirisという名で入っていたり。
# help(iris) > summary(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 Median :5.800 Median :3.000 Median :4.350 Median :1.300 Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800 Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500 Species setosa :50 versicolor:50 virginica :50
scikit-learn
scikit-learnにも入っていたり。
from sklearn import datasets import pandas as pd iris = datasets.load_iris() df = pd.DataFrame(data=iris["data"], columns=iris["feature_names"]) print(df.describe())
ちなみに、pandasとRの互換表はこのあたりを見ると良い。
vega-datasets
ただ、どれも環境を整えるのがちょっと面倒。vega-datasetsの方が依存が少ないかもしれない。こちらのほうが依存が少ないので読み込みなどが早い。
from vega_datasets import data df = data.iris() print(df.describe())
(追記: それぞれの実行時間)
実行時間。おおよそデータのロード時間。不要な依存モジュールを読み込んでいるほど遅くなる。
# R $ make 00 time r CMD BATCH --vanilla --slave 00iris.r 00iris.r.out 0.88 real 0.17 user 0.12 sys # sklearn $ make 01 time python 01iris.py | tee 01iris.py.out ... real 0m4.661s user 0m1.130s sys 0m0.523s # vega_datasets $ make 02 time python 02iris.py | tee 02iris.py.out ... real 0m0.599s user 0m0.500s sys 0m0.141s # vega_detasets with importlib.util.find_spec() $ make 03 time python 03iris.py | tee 03iris.py.out ... real 0m0.078s user 0m0.038s sys 0m0.028s
gist https://gist.github.com/podhmo/afe65fc26f11c4e4e020654655e44175
pygal?
SVGを出力してくれるグラフライブラリ。最終更新日が2年前だったりライセンスがLGPLだったりとちょっと気になる点があるものの、依存がゼロなのでインストールも実行もはやい。こういうお絵描きのときには便利かもしれない。
ただ、複雑な機能を使わずお絵かきだけに徹するライブラリというのは、一昔前という感じはするかもしれない。最近のもの(?)はpandas前提のものが多い気がする。
最小のインストール
vega_datasetsは実はpandasに依存している。このpandasのインストールをスキップしたい。
$ pipdeptree -p vega-datasets vega-datasets==0.8.0 - pandas [required: Any, installed: 1.0.3] - numpy [required: >=1.13.3, installed: 1.18.2] - python-dateutil [required: >=2.6.1, installed: 2.8.1] - six [required: >=1.5, installed: 1.14.0] - pytz [required: >=2017.2, installed: 2019.3
pipに--no-deps
オプションを付けると依存ライブラリを取得せずに自信だけをインストールしてくれる。そんなわけで以下の様な感じでインストールする。
# $ mkdir foo # $ python -m venv foo # $ cd foo # $ . bin/activate $ python -m pip install pygal $ python -m pip install --no-deps vega_datasets
インストールされたパッケージは2つだけ
$ python -m pip freeze pygal==2.4.0 vega-datasets==0.8.0
最小のデータ取得
直接vega_datasetsをimportしてしまうと、pandasをimportしようとしてエラーになる。まぁそれはそう。
>>> import vega_datasets ModuleNotFoundError: No module named 'pandas'
実際にはモジュールのimportをせずに、あるモジュールがインストールされた位置のファイルを開きたい。具体的には vega_datasets/_data/alias.json
にアクセスしたい。
importlib.util.find_specを使うとspecオブジェクトが手に入る。これはモジュールをimportする諸々の途中で使われるオブジェクト。そんなわけでこれを使ってModuleNotFoundErrorを迂回できる。こんな感じで。
# import vega_datasets # error on import panda import pathlib import json import importlib.util spec = importlib.util.find_spec("vega_datasets") dirpath = spec.submodule_search_locations[0] with (pathlib.Path(dirpath) / "_data/iris.json").open() as rf: data = json.load(rf)
テキトーに散布図を描く
どうやらpygalはpython2.xが主流だった頃の設計らしく、is_unicode=True
をつけてあげないとbytes
を返すようだ。そんなわけでこんな感じでコードを書けばirisデータセットの散布図が手に入る。
こんなかんじ。
import pygal import pathlib import json from collections import defaultdict import importlib.util # dataset spec = importlib.util.find_spec("vega_datasets") dirpath = spec.submodule_search_locations[0] with (pathlib.Path(dirpath) / "_data/iris.json").open() as rf: data = json.load(rf) # aggregate d = defaultdict(list) for row in data: d[row["species"]].append(row) # render graph xy_chart = pygal.XY(stroke=False) xy_chart.title = "Correlation" for species, rows in d.items(): xy_chart.add(species, [(row["sepalWidth"], row["sepalLength"]) for row in rows]) print(xy_chart.render(is_unicode=True))
参考にしたページはこのあたり
(ちなみに、render_to_png()
でpng画像を生成できるが、これはlibcairoに依存しちゃっているので小さな依存を保てなくなる)
gist
より高機能なものを使いたい
ということで、この記事の趣旨自体は終わりなのだけれど。もう少し高機能なものを使いたくなる事がある。
その場合には個人的にはvegaとaltairを推そうと思っている。vegaはJSONを返すとグラフをよしなに描画してくれるというようなもの。そのvegaの形式に対応したJSONを生成してくれるのがaltair。
あとは、plotlyを使う人もいるかも知れない。
データの集計などには素直にpandasを使ったりするのが普通なのかもしれない。CSVを渡せば簡易DBになるし、dataframeは便利なときには便利。
(memo:) データを分析したい場合の例
お絵かきではなくデータを分析したい場合には例えばこういう感じのことをする。散布図一個じゃなくてpairplotするよね。。
(ここから下はテキトーに検索してその場で集めたリンクなのでメモ程度のもの。seabornとか使い方を忘れてしまったし、他のものを使いたい)
EDA (探索的データ解析)
もう少し雰囲気をつかみたい場合には
- やっている雰囲気を知りたいとき https://qiita.com/kakiuchis/items/db57e4df1cdab3f6bfb9
- タイタニックのEDA https://www.kaggle.com/ash316/eda-to-prediction-dietanic
- ポケモンのデータのEDA https://qiita.com/maskot1977/items/2680927b58cdc4fad8d4
- いろいろなグラフ https://qiita.com/4m1t0/items/76b0033edb545a78cef5
データセット
手軽なデータセットを集めたい場合は、kaggleなどから取ってきても良さそう。
- マーケティングでよくあるようなデータ https://www.kaggle.com/pankajjsh06/ibm-watson-marketing-customer-value-data
- 学校の試験の成績 https://www.kaggle.com/spscientist/students-performance-in-exams
- ゲームのユニットの性能評価をしたいとき https://www.kaggle.com/raxnamosa/defense-of-the-ancients