Prestoで2つの配列を同時に行に変換する
最近、Treasure Dataに触る機会が増えた。 その中で1行に2つのカラムにそれぞれコンマ区切りのデータがあり、それを行展開するのにハマったポイントがあったのでメモしておく。 そして長くなるので、最初に結論を載せておく。
どういうデータか
以下のようなデータ形式を想定している。
column1 | column2 |
---|---|
a,b,c | 1,2,3 |
そして、このデータを以下のデータ形式に展開する。
column1 | column2 |
---|---|
a | 1 |
b | 2 |
c | 3 |
前提としては、column1もcolumn2も同数の要素数が含まれていることとする。
どうするか
以下のように CROSS JOIN UNNEST
の中に複数の split
関数を入れる。
SELECT clmA, clmB FROM tbl1 CROSS JOIN UNNEST( split( tbl1.column1, ',' ), split( tbl1.column2, ',' ) ) AS t(clmA, clmB);
これにより上記のような展開ができます。
どういうことをしたか
ググってみると、Prestoでカンマ区切りのデータを展開した記事はよく出てくる。
これを見たときは、『そっか、じゃあ CROSS JOIN UNNEST をもう1段挟めばいいのか』
と安易に考えてしまいました。
ざっと以下のような感じ。()
SELECT t1.clmA, t2.clmB FROM tbl1 CROSS JOIN UNNEST( split( tbl1.column1, ',' ) AS t1(clmA) CROSS JOIN UNNEST( split( tbl1.column2, ',' ) ) AS t2(clmB);
そうすると以下のような結果が得られた。
column1 | column2 |
---|---|
a | 1 |
a | 2 |
a | 3 |
b | 1 |
b | 2 |
b | 3 |
c | 1 |
c | 2 |
c | 3 |
まさに CROSS JOIN。
なので、次は、『そっか、じゃあWITH句をつかって、一回テーブルとして展開してから、ID付きで展開すればうまくいくんじゃね?』 と思い、やりました。 が、やはり上記のようなクエリの結果になってしまいました。 なかなか奥深いですね…
勉強会に登壇してきました。
機械学習エンジニアとして副業をしていることもあり、FindyでCTOしている @ma3tk からのお誘いもあり登壇してきました。
engineer-parallel-work.connpass.com
発表資料はこちら。
副業をしていて感じていることを話してきた。
まだ初めて数ヶ月だが、いい振り返りになった。
視座を高めるために知識の input だけでなく、 output を行い経験値を増やすこと。
そのサイクルを回すことで自身の視座を高くしていく努力をしていくこと。
それを再認識できた発表だった。
懇親会であった質問
ものすごくありがたいことに参加者から、『発表が良かった』と言ってくださる方が多くいらっしゃった。
その方々といろいろ話すことができたので、質問と自分の考えをまとめておく。
始め方はどうされたのですか?
僕の場合、スライドに載せているFISMという会社のCTOをしている @kzkohashi と同僚であり、
そのつながりで始めることができた。
元々興味はあったが、なかなか始める決意がつかなかったが、とてもいいきっかけをくれたと思っている。
いいなと思っている会社があり、そこで副業できればなと思っていますが、どう思いますか?
副業として受け入れてくださるのであれば、積極的に取り組めばいいと思っている。
正直、外から見ていていいなーと思う会社はいっぱいある。
ただ、入ってみて、あれ?と思うこともある。
そうなってしまったときに、現職を退職してまでって後悔がすごく、これが現職にとどまり続ける要因の一つなのかと思う。
そういう意味では副業として参加し、正社員と肩を並べて働いてみて、直に会社の文化に触れることはいいスタートの切り方なのではないだろうか?
そして、思ったより肌に合わないと判断できた場合は、信頼を稼いでつながりを構築することに専念すればいいと思っている。
アウトプットの仕方どうしていますか?
データ分析の場合、データを分析して最後の可視化と考察の部分が重要だと思っている。
結局のところ期待されているのはアウトプットであり、例えば、
- 必要なタスクに対して実現可能なのか不可能なのか
- 不可能な場合、だいたい手段はあるのかもっと作業を進めれば可能性はでてくるのか
などが期待されているのではないだろうか。
データ分析といえばデータの前処理が重要であることは重々承知している。
しかし副業だと、発注者側にデータ分析を理解してくれる人がいない場合、
最初から前処理をコツコツやっていても、「何してるんですか?」ってなると思う。
それよりも、
「既存のデータを使ってこうしました。ここの部分の改善をすることで精度があがると思うので、次にここを着手します。」
と道筋を見せて上げたほうが納得感が得られるし、自分自身必要な処理が見えてくるはずである。
なので、アウトプットを細かく見せることはすごく重要だと考えている。
ポートフォリオはどうされていますか?
ここで悩んでいる人が多かった印象だった。
正直、自分は知り合いの相談から副業がスタートしているので、ポートフォリオとかを考えなくても良かった。
しかし、もっといろんな会社の案件を触ってみたいなと思ったときに、ポートフォリオをつくらないとなとなった。
恐らく、ポートフォリオとして上がるのは、「エンジニアならgithubだろ!」というのが定石なのではないだろうか。
その声がすごく多かったし、それには賛成である。
しかし、機械学習のエンジニアはデータがないとなかなかアピールポイントがないので、
githubにコードを上げることは難しいのではないかと思う。
そこで僕はブログもセットでポートフォリオを組むといいのではないかと思っている。
データ前処理の中で得られた気づきは、大抵、gistやgithubに上げるほどではない。
だが、その一部をブログとして残すことで自分がどの程度データに触れているのかというのをアピールすることに繋げられる。
積もり積もればれっきとした履歴書であるし、コード以外の考えをアピールすることができるのでよいと思う。
ブログのアウトプットについては @kakakakku のブログに対する考え方は参考になるので、
一度は読まれたほうがいいと思う。
最後に
今回は本当に貴重な会で登壇させていただけた。 今後もいろんな勉強会に登壇できるよう、自分の成長に繋げられるように input/output を引き続きがんばろう。
PandasでJSONファイルを保存するときの注意点
個人的にはTensorFlowでモデリングするようになってから、numpyを触る頻度が高くなって、それに伴いpandasを触る機会が減っていった。
データの可視化もpyplotとかseaboneとかを使って、可視化の方法を調べながら模索している状況が増えていった。
しかし、先日副業の案件で学習データをサクッと可視化させようと思ったときに選んだのは、pandasだった。
やはりpandasは優秀かな
テキストデータを読み込んで、異常値を探すとかその場でフィルタリングしようかと思うと、
やはりpandasは楽だなと改めて思たった。(ただnumpy力が低いだけかもしれないが…)
例えば、とりあえずテキストに保存したデータセットをDataFrameに読み込んで、
データセットの概要を知りたいなーと思ったら、
df.describe()
とすれば、カラム毎の最大値・最小値、四分位数とかを出してくれるし、
histグラムで可視化したいなーとおもったら、
df.plot.hist(y=[<可視化するカラム名>], bins=<ビン数>)
とすれば、指定したカラムだけのヒストグラムが可視化できて、すごく楽だった。
分布はどのような形なのか、どの範囲で異常値を切り出すのかなど判断して
そのままDataFrameでフィルターすればいいので、短時間でデータセットのチェックと更新ができた。
DataFrameの保存には注意が必要
前提
前提として、データセットはJSON形式で保存しており、
すでに実験するノートブックを用意してある、としてます。
なので、同じJSONの形式で保存することで実験のノートブックを再利用することが前提です。
問題点
通常、PythonでdictionaryをJSONとして保存した場合、
import json dict_list = [] for i in range(10): dict_obj = {} dict_obj["single"] = i dict_obj["double"] = i * 2 dict_obj["square"] = i * i dict_list.append(dict_obj) with open('dict2json.json', 'w') as f: json.dump(dict_list, f)
のような処理になる。 そして、この場合テキストにはざっくりと
[{"single": 0, "double": 0, "square": 0}, {"single": 1, "double": 2, "square": 1}, {"single": 2, "double": 4, "square": 4}, {"single": 3, "double": 6, "square": 9}, {"single": 4, "double": 8, "square": 16}, {"single": 5, "double": 10, "square": 25}, {"single": 6, "double": 12, "square": 36}, {"single": 7, "double": 14, "square": 49}, {"single": 8, "double": 16, "square": 64}, {"single": 9, "double": 18, "square": 81}]
このような形式で保存されている。
いわゆる、key-valueが配列に格納されている形である。
なので、配列の1要素が1行(1レコード)のデータを表現している。
そして、何も意識せずにDataFrameをJSONファイルとして保存すると痛い目に遭った。 それが今回の教訓だった。
PandasでJSONを読み込むには、
import pandas as pd df = pd.read_json('dict2json.json')
とすればよい。 そして、このDataFrameをJSONとして保存する場合、以下のように書けば良い。
df.to_json("df2json.json")
人によりけりだとは思うが、簡単で直感的だ。ただし、この場合保存されたファイルの中身は、
{"double":{"0":0,"1":2,"2":4,"3":6,"4":8,"5":10,"6":12,"7":14,"8":16,"9":18},"single":{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9},"square":{"0":0,"1":1,"2":4,"3":9,"4":16,"5":25,"6":36,"7":49,"8":64,"9":81}}
となる。
形としては、カラム毎に、 "index: value"
の形で保存されている。
この場合、保存されたファイルを
with open('df2json.json') as f: json_data = json.load(f)
として読み込むと、1レコードずつとして読み込まれず、keyが想定していたものと異なる結果になる。
Key-Valueの形式で保存するには、
DataFrameをkey-valueの形式のJSONに保存するときには orient
オプションに record
を指定する必要があることに注意する。
df.to_json(filtered_data_filepath, orient='records')
そうすると、
[{"double":0,"single":0,"square":0},{"double":2,"single":1,"square":1},{"double":4,"single":2,"square":4},{"double":6,"single":3,"square":9},{"double":8,"single":4,"square":16},{"double":10,"single":5,"square":25},{"double":12,"single":6,"square":36},{"double":14,"single":7,"square":49},{"double":16,"single":8,"square":64},{"double":18,"single":9,"square":81}]
と保存された。
JupyterLabでアニメーションが動作しないときの対処
背景・目的
最近、深層強化学習を勉強していて、教材としては
https://www.amazon.co.jp/dp/4839965625
を使っている。 コードはノートブックに記述していて、JupyterLabを利用している。 Toy problem として自作で3×3マスの迷路を自作して、選択した行動をアニメーションとして描画するところで問題があったのでメモしておく。
エージェントが通るパスをアニメーションとして表示するコードを部分的に抜粋して載せておく。
from matplotlib import animation from IPython.display import HTML %matplotlib inline def init(): line.set_data([], []) return (line,) def animate(i): state = state_history[i] x = (state % 3) + 0.5 y = 2.5 - int(state / 3) line.set_data(x, y) return (line,) anim = animation.FuncAnimation(fig, animate, init_func=init, frames=len(state_history), interval=200, repeat=False) anim.save("maze.gif", writer = "imagemagick") HTML(anim.to_jshtml())
state_historyにはエージェントが通るパスのが保存されていて、それをアニメーションとして動かす。
今回問題になったは HTML(anim.to_jshtml())
の部分である。
アニメーションとして動かすには
Jupyter内で図をアニメーションとして動かすには、 matplotlib
の animation
を利用すると簡単に実現できる。
実際に、書籍では恐らくJupyter Notebookで実験することを想定しており、簡単にアニメーションを動かすことができた。
しかし、JupyterLabではJavaScriptの問題のためかアニメーションを再生することができない。
この問題はGithub上でissueとして上がっている。
ここでは、animationのオブジェクトにある to_jshtml()
を使っているが、
その他にも to_html5_video()
関数があり、これを使ってもアニメーションを再生できなかった。
どうやって解決したか
JupyterのNotebookはコードのみでなく、Markdownとして文章を記述することが可能である。 今回は、アニメーションをgifとして保存し、そのファイルをMarkdownで読み込みアニメーションを再生することで回避した。 上記のコードの中の
anim.save("maze.gif", writer = "imagemagick")
でアニメーションをgifとして保存している。 ここで保存したファイルをMarkdownで
<div class="pull-left"> ![Animated GIF](maze.gif) <div>
と記述した。
これにより、Jupyter NotebookでもJupyterLabでもアニメーションを表示することができた。
難点としては、アニメーションが無限にリピート再生されてしまうところくらいかなと思っている。
それよりも簡単に可視化されどのような挙動になるのか、可視化されながら説明できる点のほうがはるかに重要だと思うので、
回避方法が見つかってよかった。
おなじ問題に出くわしている人の解決方法になれば幸いです。
また、JupyterLabで to_jshtml()
や to_html5_video()
などコードでアニメーションが実現できた人はコメントなどでぜひとも教えてください!
Kerasで学習したモデルをWebAPIとして提供する
機械学習で学習済みモデルの予測結果をどうやって返すべきか勉強したので、WebAPIとして提供する場合のコードのメモする。 リポジトリはこちら。
個人的な学びポイントは、
load.py
のinit
関数でリロードした学習済みモデルを返している部分- 画像データの受け取り方
の2つである。
まず、学習済みモデルを返している部分についてだが、
tensorflow の場合、 Saver などを使い、 graph に学習済みモデルを読み込む必要があるが、
Keras の場合は学習済みのモデルをリロードし、 predict
関数を使って推論が行える。
そして、もう一つの画像データの受け取り方について。
今回、画像を DataUrl
という形式に変換して渡している。
これを利用することで、 API 側では画像を base64 の文字列として受け取ることができ、
画像として復元し、推論可能なデータサイズにリサイズすることで予測を行っている。
Flask を利用すれば非常に簡単に推論結果を返すことができるので、 モデルを作成して推論結果を検証するためのインターフェイスとしては効率の良い方法の一つではないかと思う。
ブログをはじめました
はじめまして
toohskといいます。よろしくお願いします。
toohskの読み方は決まってません。 いろいろなところでこのIDを使ってるのですが。
友達の仕事を手伝うことを契機に 仕事でのメモや技術的なことをポストしたくなり、ブログをはじめました。 以前自前でブログをやってたのですが、 自分で管理するのも面倒だし、SEO上げるの頑張るのも大変だし… ということではてぶを始めることにしました。 よろしくお願いします。