spark-summit 2014のSpark Streamingのお題をやってみる
最近はSparkにお熱ということで、spark-summit 2014で催されたSpark StreamingでTwitterのタイムラインからハッシュタグの出現頻度を抽出する、というお題をやってみたいとおもいます。
spark-summit 2014のhands on資料
Stream Processing w/ Spark Streaming
ソースコード
spark-summit 2014 spark streaming hands on
以上。次はKafkaからデータ流してナントカカントカ、というのもやってみたい。
Go占い
あけましておめでとうございます。
一昨年はpython, 去年はHaskellだったので今年はGoで占いします。
以下の.goを作ります。
// lottery.go package main import ( "fmt" "math/rand" "time" ) func main() { rand.Seed(time.Now().Unix()) values := []string{"大凶", "凶", "大吉", "中吉", "小吉", "吉", "マジ吉"} fmt.Println(values[rand.Intn(len(values))]) }
実行してみます。
$ go run lottery.go 吉
まぁまぁですね!今年もよろしくお願いします。
PyconJP 2014に参加した
毎年恒例pyconに参加しました。
今年は例年に比べ機械学習や数理系の話題が多く、自分自身も業務で最近はこの辺に触ることが多かったので嬉しい内容でした。
内容は、1セッションの時間が30分ということもあり、使っているライブラリの紹介や入門内容的なものが多かったですが、それでもどんなライブラリを使っているか知れてよかったです。
機械学習系でよく使われていそうだったライブラリ
numpy
高速な行列計算が便利なライブラリ。
以下のプレゼンでは、1から1億までの数を合計するプログラムが、素のpythonと比べて80倍早かった(Cと同等)とのこと。
Effective numerical computation in num py and scipy
scipy
sparse matrixなど、便利なデータ構造がある。距離計算関数なども。
matplotlib
グラフ描画ライブラリ。APIがMATLABに似ているとのこと。プロジェクトは非常に成熟・安定しているとのこと。
scikit-learn
機械学習ライブラリ。機械学習系のライブラリは他にもいくつかありそうでしたが、これがデファクトという感じでした。
メリットは、
- 使い方が簡単
- 比較的高速
- メジャーなアルゴリズムはだいたい網羅している
- プロジェクトが活発
pandas
クロス集計など、行列計算を楽にするライブラリ。RのData.Frameに似ているらしい。scikit-learnと相性が悪い、という人も一人だけいた(詳しいことはわかりませんでしたが)。
anaconda
これらデータ分析に必要なライブラリを一挙にインストールするためのパッケージ。numpyやscipyのコンパイルは大変なので(何かしらハマりどころが多い)、これを使うと楽らしい。
標準モジュール
itertools
permutationやgroupbyなど、便利なモジュール多いです。
collections
defaultdictには毎日のようにお世話になってます。Counterとかも便利だそうです。
statistics
python3.4から新しく入ったライブラリ。平均や標準偏差などの統計量を計算するライブラリです。
iPython Notebook
プレゼンのツールとして, iPython Notebookを使っている人が多かったです。グラフとコードを一体にして見せれるので、分析系の人たちには重宝されていそう。
その他面白かったもの
Deep Learningと画像認識
「Deep learning for Image Recognition in Python」というタイトルでHideki Tanakaさんの発表でした。
Deep Learning for Image Recognition in Python
機械学習の精度を競うKaagleというウェブサイトがあり、そこで犬と猫の画像を自動判定する課題に挑戦した。
- 最初は、画像認識のための一般的な特徴量であるHaar-like featuresを使った。
- 60%くらいの精度しか出ず。しかしながら、Kaagleでのトップランナーは99%近い精度を出している。
- 最初は、画像認識のための一般的な特徴量であるHaar-like featuresを使った。
トップの連中はどうやらDeep learningという手法を用いているらしい。
- Deep Learning (Pre-Trained Networks)を使ってみたところ95%まで急上昇した。
後半に公開された会場限定のスライドが非常に面白く、初日のキーノートと並んで最も面白く、記憶に残る楽しいプレゼンでした。
Oktavia
Oktaviaという全文検索エンジンのプレゼンがありました。
従来の転置インデックスではなく、「高速文字列解析の世界」にあったFM-Indexというアルゴリズムを採用したという話でした。
- 検索エンジンのインデックスとしては、一般的には転置インデックスが用いられる。
日本語や中国語などアジア系の言語は単純に単語に分割できない。
そこで、FM-Index
- 「高速文字列解析の世界」で紹介されていた。
- 検索前に単語を分割する必要がない。
- 圧縮インデックスファイルを使った検索アルゴリズムの中でも最速。
- インデックスファイルからオリジナルのドキュメントを復元できる。
- 参考
キーノート(1日目)
スピーカーはreqeustsの作者であるKenneth Reitzさん。
python2, python3のコミュニティの分断について語られました。
個人的には、python2はこれ以上進化しないとわかっているわけだし、ライブラリのpython3対応もかなり進んでいるので、あとは趣味レベルを越えたビジネスでの事例が出てくれば自然に移行していくんじゃないかなと楽観的に見てます。
事例が少ないだけに、今python3を採用すれば先進的なブランドイメージが得られるかもしれないですね。
以上。運営の皆様、お疲れ様でした!
haskellの勉強として、twitter apiライブラリを書いてみた
すごいH本をひと通り読んだので次は自分でコードを書いてみようと思い、Twitter APIのライブラリを適当な感じで書いてみました。
Attsun1031/birdwatcher · GitHub
使い方
import Web.Birdwatcher main = do user <- users_show [("screen_name", "__Attsun__")] putStrLn $ show user
感想
- モナドむずい
- Aesonが便利(型クラスの仕組みのおかげ?)
- ライブラリコードを読んだりcabalを設定したりするのに時間を多く使ってしまったので、使った時間の割にはコード量が少なかった。
レコードのアクセサ関数で困った
レコードとは以下の様な構造体のようなもの。
data Point = Pt {x :: Integer, y :: Integer}
レコードを定義すると、フィールドへのアクセサ関数x, yが自動的に定義されるわけだけど、アクセサ関数の名前がだぶってしまうので同じ名前のフィールド名を持つレコードを同じ名前空間に複数おけない。
例えば自分の作ったライブラリの場合、UsersShowとUserTimelineのどちらにもidという名前があるため同じ名前空間におけない。とりあえずmoduleを分けるという手で対処しているが、分けたくないってケースもあるだろうし、どうやってやりくりするんだろ?
pythonの正規表現における先頭・末尾マッチ
こんなエントリーを見ました。
正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう | 徳丸浩の日記
へー、知らなかったなー、pythonではどうなんだろうなー、と思って試してみたメモ。バージョンは3.3。
\z(小文字)ではなく\Z(大文字)
Rubyと同じように\zを指定してみたら思うように動かなかったのでなんでだろー、と思ってドキュメント見たら\Zでした。
>>> import re >>> re.match('\Aabc\Z', 'abc') <_sre.SRE_Match object at 0x7f12f3d371d0> >>> re.match('\Aabc\Z', 'abc\ndef')
ちなみにRubyでは\Zと\zは分かれている模様。\Zは末尾の改行を無視して判定するみたい。
デフォルトは複数行モードではない
Rubyはデフォルトで複数行モードになっているから罠になるよ、という話でしたがpythonはそうではなかったので安心です。`re.MULTILINE`オプションをつけると複数行モードになります。
>>> re.match('^abc$', 'abc\ndef') >>> >>> re.match('^abc$', 'abc\ndef', re.MULTILINE) <_sre.SRE_Match object at 0x7f12f3d37168>
末尾の改行の扱い
複数行モードでなくとも$は末尾の改行を無視してマッチするので注意が必要ですね。\zは末尾の改行は無視しません。
>>> re.match('^abc$', 'abc\n') <_sre.SRE_Match object at 0x7f12f3d371d0> >>> re.match('\Aabc\Z', 'abc\n') >>>
javascriptでは・・・
どうなんだろうと思って調べてみましたがどうやら\Aや\zはない模様。(ちょこっと調べただけなので本当はあるのも。)
Haskell占い
あけましておめでとうございます。
去年はpython占いしたので今年はHaskell占いします。
-- ghciで実行(letとか省いてます) import System.Random choice :: [String] -> Int -> String choice choices seed = (choices !!) . fst $ randomR (0, length choices - 1) $ mkStdGen seed putStrLn $ choice ["大凶", "凶", "大吉", "中吉", "小吉", "吉", "マジ吉"] 2014 > 中吉
いいですね!
今年もよろしくお願いします。
cliffとその実装
python advent calendar 15日目の記事です。
以前から気になっていたcliffについて調べてみました。
ライブラリやフレームワークのコードを読むのが最近のマイブームなので、使い方とかは適当に流してcliffがどのような実装構成になっているか見てみたいと思います。
詳細が気になる方はドキュメントがちゃんとしてるので読んでみてください。 https://cliff.readthedocs.org/en/latest/demoapp.html
cliffってなに
pythonのコマンドラインアプリケーションフレームワーク。サブコマンドを登録したり引数を解析したりログを出したり、コマンドラインアプリに共通する部分を担ってくれます。
私は知りませんでしたが、gearboxというツールの実装に使われているそうです。
使用方法
標準出力になにか出すだけでの簡単なアプリケーションを作りながら、どのようにcliffを使うのか見てみましょう。
必要なもの
cliff.app.App
を継承したクラスこのクラスのrunメソッドを実行することでアプリが起動されます。インスタンス化してrunメソッドを叩くための関数も用意しておきましょう。(main.py)
# -*- coding: utf-8 -*- import sys from cliff.app import App from cliff.commandmanager import CommandManager class MyDemoApp(App): def __init__(self): super(MyDemoApp, self).__init__( description = 'my demo app', version = '0.1', command_manager = CommandManager('myapp.commands'), ) def main(argv=sys.argv[1:]): # エントリーポイントなる関数 myapp = MyDemoApp() return myapp.run(argv) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))
CommandManager
は各コマンドを管理するクラスで、コンストラクタ引数にはコマンドが登録されているエントリーポイントグループ名を渡します。cliff.command.Command
を継承したクラスこのクラスが各コマンドを定義するクラスとなります。例えば標準出力になにか出すだけのコマンドだったらこんな感じ。(say.py)
# -*- coding: utf-8 -*- from cliff.command import Command class Say(Command): "A say command that prints a message." def take_action(self, parsed_args): self.app.stdout.write('hey!\n')
setup.py
バッチプログラムをインストールするスクリプトです。
詳細は省きますが、
entry_points
の定義にだけ触れておきます。console_scripts
にバッチの起動コマンドとなる関数を定義し、CommandManager
の初期化時に渡していたエントリーポイントグループに各コマンドのエントリーポイントを書きます。entry_points={ 'console_scripts': [ 'mycliffapp = app.main:main' ], 'myapp.commands': [ 'say = app.say:Say', ], },
これを
python setup.py install
することで、$ mycliffapp say hay!
というコマンドを実行できるようになります。(setuptoolsは知らないとこが多い・・。)
だいたいの使い方はこんなとこです。
オプション
特にアプリケーション側で何もすることなく、ヘルプやdebugなどのよくあるオプションをサポートしてくれます。
usage: mycliffapp [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug]
my demo app
optional arguments:
--version show program's version number and exit
-v, --verbose Increase verbosity of output. Can be repeated.
--log-file LOG_FILE Specify a file to log output. Disabled by default.
-q, --quiet suppress output except warnings and errors
-h, --help show this help message and exit
--debug show tracebacks on errors
インタラクティブモード
引数なしで実行すると、インタラクティブモードに入ります。インタラクティブモードでは、コマンド名のみでコマンドを実行できたりします。
$ mycliffapp
(mycliffapp) say
hay!
この実装にはcmd2というライブラリが使われています。
実装
ではcliff本体の実装がどうなってるか見ていきます。
クラス構成
ざっくりとこんな感じです。
- Appクラスがコマンドの流れを制御するクラス
- CommandManagerクラスが登録されたサブコマンドをロードしたり検索したりするクラス
- Commandクラスが各サブコマンドの動作を規定するクラス
cliffのユーザーはAppクラスとCommandoクラスを継承することになります。 簡単ですね。
※クラス図をastahで作ったんですが、pythonなひとたちはUML書くときに何使ってんでしょ?
それではひとつひとつ見て行きましょう。
cliff.app.App
アプリケーションのエントリーポイントとなるクラス。__init__
でロケールの設定やArgumentParser
の生成を行い、run
メソッドによりアプリケーションを起動します。
runメソッドが重要なので、処理の流れを見ていきます。 なお、runは長いのでコードは貼りません。気になる人は以下を見てください。 https://github.com/dreamhost/cliff/blob/master/cliff/app.py
runメソッド
ArgumentParser.parse_known_args
によりコマンドライン引数の解析を行う。--verbose
や--debug
などのオプションがデフォルトでセットされる。- ロガーを生成する。
- 初期化後のhookポイントである
self.initialize_app
メソッドを呼び出す。デフォルトでは何もしない。 - コマンド名が引数で渡されている場合、
self.run_subcommand
へ。コマンド名が渡されていない場合はインタラクティブモードに以降(詳細割愛) self.command_manager.find_command
によりコマンドをロード。- コマンド実行前のhookポイントである
self.prepare_to_run_command
を実行。デフォルトでは何もしない。 - コマンドオブジェクトの
get_parser
によりコマンド固有引数解析用Parserを取得しパース。 - パースした結果を引数にコマンドオブジェクトの
run
を実行。 - コマンド実行後のhookポイントである
self.clean_up
を実行。デフォルトでは何もしない。このメソッドはコマンドで例外が発生した場合でも実行される。
hookポイントを提供することでアプリケーション固有処理をポイントポイントで入れられるようになっています。テンプレートメソッドパターンというやつですね。
cliff.command.Command
サブコマンドを表すクラスです。
run
Appクラスからコールされます。
コードはこんな感じ
def run(self, parsed_args):
self.take_action(parsed_args)
return 0
戻り値はexit codeとなり得るので(実装次第)、変更したい場合はオーバーライドする必要があるでしょう。
take_action
サブコマンドの実際の処理を書くところです。abc.abstractmethod
になっているので、継承クラスでこのメソッドをオーバーライドする必要があります。
cliff.commandmanager.CommandManager
サブコマンドの管理をするクラスです。ロードしたり検索したり。 より役割をはっきりさせた名前にするなら、CommandRepositoryといったところでしょうか。
_load_commands
initの最後に_load_commandsというメソッドをコールしています。このメソッドは以下のような実装になっています。
def _load_commands(self):
for ep in pkg_resources.iter_entry_points(self.namespace):
LOG.debug('found command %r', ep.name)
cmd_name = (ep.name.replace('_', ' ')
if self.convert_underscores
else ep.name)
self.commands[cmd_name] = ep
return
pkg_resources
を使ってentry_pointを頼りにコマンドをロードしています。entry_pointへのコマンドの登録はsetup.pyで行います。
find_command
_load_commands
やadd_command
で追加されたコマンドから、引数argv[0]に一致するコマンド名をもつコマンドを探します。
戻り値ではコマンドクラスを返しており、この段階ではインスタンス化は行いません。
コマンドクラスのインスタンス化はAppクラスがfind_command
を呼んでコマンドクラスを取得したあと、optionsを元にすぐさま行っているのですが、どういう考慮でしょうね。
コマンドの生成ロジックはCommandManager
に隠蔽するのが素直な気がするのですが。
感想
バッチフレームワークの設計にも応用できそうな気がしました。
あんまりバッチやコマンドラインアプリケーション系のフレームワークって使ったことないのですが、だいたいがこういう設計になってるのかな。
明日はdrillbitsさんです!