The Dabsong Conshirtoe

技術系の話を主にします。

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

グラフ描画ライブラリ。APIMATLABに似ているとのこと。プロジェクトは非常に成熟・安定しているとのこと。

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%近い精度を出している。
  • トップの連中はどうやらDeep learningという手法を用いているらしい。

    • Deep Learning (Pre-Trained Networks)を使ってみたところ95%まで急上昇した。

後半に公開された会場限定のスライドが非常に面白く、初日のキーノートと並んで最も面白く、記憶に残る楽しいプレゼンでした。

Oktavia

Oktaviaという全文検索エンジンのプレゼンがありました。

従来の転置インデックスではなく、「高速文字列解析の世界」にあったFM-Indexというアルゴリズムを採用したという話でした。

  • 検索エンジンのインデックスとしては、一般的には転置インデックスが用いられる。
    • 日本語や中国語などアジア系の言語は単純に単語に分割できない。

      • 形態素解析を用いて分割し、転置インデックスを作る
        • 各言語に精通している必要がある。
        • 巨大な辞書が必要。
        • 検索ワードに対しても、同様の処理(形態素解析)を行う必要がある。
      • N-gram
        • インデックスファイルが巨大になりやすい。
    • そこで、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本体の実装がどうなってるか見ていきます。

クラス構成

ざっくりとこんな感じです。

f:id:Attsun_1031:20131202220639p:plain

  • 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メソッド

  1. ArgumentParser.parse_known_argsによりコマンドライン引数の解析を行う。--verbose--debugなどのオプションがデフォルトでセットされる。
  2. ロガーを生成する。
  3. 初期化後のhookポイントであるself.initialize_appメソッドを呼び出す。デフォルトでは何もしない。
  4. コマンド名が引数で渡されている場合、self.run_subcommandへ。コマンド名が渡されていない場合はインタラクティブモードに以降(詳細割愛)
  5. self.command_manager.find_commandによりコマンドをロード。
  6. コマンド実行前のhookポイントであるself.prepare_to_run_commandを実行。デフォルトでは何もしない。
  7. コマンドオブジェクトのget_parserによりコマンド固有引数解析用Parserを取得しパース。
  8. パースした結果を引数にコマンドオブジェクトのrunを実行。
  9. コマンド実行後の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_commandsadd_commandで追加されたコマンドから、引数argv[0]に一致するコマンド名をもつコマンドを探します。

戻り値ではコマンドクラスを返しており、この段階ではインスタンス化は行いません。

コマンドクラスのインスタンス化はAppクラスがfind_commandを呼んでコマンドクラスを取得したあと、optionsを元にすぐさま行っているのですが、どういう考慮でしょうね。

コマンドの生成ロジックはCommandManagerに隠蔽するのが素直な気がするのですが。

感想

バッチフレームワークの設計にも応用できそうな気がしました。

あんまりバッチやコマンドラインアプリケーション系のフレームワークって使ったことないのですが、だいたいがこういう設計になってるのかな。

明日はdrillbitsさんです!