データ整形まわりで必要な Python の細かいテクニックを先週少し説明しましたが、他にもいくつかよく気にしておくべきポイントがあります。
特に昨日のように D3.js でデータを可視化しようとすると JSON のデータセットを生成する必要があるわけですが、データセットがどういったデータ構造になっているかはよく把握しておかないといけません。
コンパイルして実行する言語のように IDE 上でエラーチェックできて完成するまでバグを取ってから動かすといった方法が採れれば良いのですが、 JavaScript の場合ブラウザで実行しても思うように表示されない、警告メッセージから真の原因まで辿り着くのに時間を取られがちという傾向があります。それは実行環境によるものなのか、データの型や形式によるものなのか、あるいはコードの細かいミスなのか、切り分けをするのに時間がかかるのが原因かと思います。
そんなわけでデータセットの形式を正しく理解し、ユニットテストを書いて正確性の担保をすることは結果的に時間の節約につながりますし、地味で手間がかかりますが省略するべきではないとても重要な手順です。
尺度水準の変換と時刻印の変更
たとえば時系列のログデータを可視化することを考えてみます。時間というのはそもそも区切りのない延々と連続する情報です。これをスライドバーで動かして時間の推移によるデータの変化を見せたい場合、尺度水準を変更し間隔尺度への変換をおこなうのがよくある手法です。
7/22 〜 7/25 の 4 日間の顧客の数を見せたいとします。距離尺度を等間隔に確保するために UNIX 時刻と人間の日時の変換をします。
人間の日時 | UNIX 時刻 |
---|---|
20140722 | 1404226800 |
20140723 | 1404313200 |
20140724 | 1404399600 |
20140725 | 1404486000 |
このように 1 日単位の推移を可視化するために、左側の人間の日時から UNIX 時刻に変換するための関数を用意しておきます。 Python では time.mktime で UNIX 時刻が浮動小数点型で帰ります。
def to_unixtime(self, d):
# time.mktime(2014,07,22,0,0,0,0,0,0) する
return int(time.mktime((int(d[0:4]),int(d[5:6]),int(d[7:8]),0,0,0,0,0,0)))
上の例ではひとまず 1 日単位の距離尺度を求められれば良いので時刻の部分には 0 を固定で指定しました。 1 時間単位、 10 分単位という風に距離を設定する場合のためにもう少し改良したほうが良いでしょう。どうしたら良いかは読者の皆様が考えてみてください。
また JavaScript の世界では 1/1000 秒単位で時刻を扱うのが普通です。 JSON に変換するときに数値を 1000 倍することを忘れないようにしましょう。
なお UNIX 時刻印から人間の日時への変換は次のようにおこないます。
now = 1406255406992 / 1000
datetime.datetime.fromtimestamp(now)
#=> datetime.datetime(2014, 7, 25, 11, 30, 6, 992000)
リスト内包表記
たとえば次のようなデータ形式を考えてみます。ネストした辞書型、一般に言う連想配列です。
{1404399600.0: {'a': 1, 'b': 2}, 1404486000.0: {'c': 3, 'd': 4}}
これを昨日紹介した Stacked Area Chart で表示したい場合、本体のコードでは JSON のデータ形式を多次元配列として扱っていることがわかります。辞書型からの変換は一見面倒そうですが Python の持つリスト内容表記を使えば簡潔に記述ができます。
[[a*1000,b] for a,b in v.items()]
#=> [[1404399600000.0, {'a': 1, 'b': 2}], [1404486000000.0, {'c': 3, 'd': 4}]]
数学の世界では実数、整数などのすべては普遍集合 (universal set) であると解釈します。 for によってデータの要素を参照し各々に対して射影を得ると考えればすっきり理解できます。数学の表記に似せてあることがわかりますね。
Python 3 ではリスト内包表記の動作がジェネレータ式に改善されており例えば次のような構文は
[f(x) for x in S if P(x)]
以下のように list() 関数をジェネレータ式に適用したものと等価になります。
list(f(x) for x in S if P(x))
まとめ
今日もひたすら地味なデータ変換をおこなう上でよく登場する細かいテクニックを紹介しました。