mathhunの日記

Haskellと機械学習の勉強日記。PRML読みます。

HaskellのOptparse-Applicativeの底力を知る

元ネタ RubyのOptionParserの底力を知る - ザリガニが見ていた...。

Haskell版で苦労最小限でオプションを解析できるのか、調べてみた。

使うライブラリは optparse-applicative
理由は最近見かけたこのスライドで推薦されていたから
Getting it Done with Haskell - Google スライド

optparse-applicative のバージョンは 0.9.1.1
githubの最新版ではいくつかの関数・APIが変更されているようで、使用バージョンではマニュアル通りに書いてもエラーになるものもあった。

基本

module Main where

import Data.Monoid
import Options.Applicative

data MyOption= MyOption { optName :: String }

runWithOptions :: MyOption -> IO ()
runWithOptions opts =
  putStrLn $ "name = " ++ optName opts

main :: IO ()
main = execParser opts >>= runWithOptions
  where
    parser = MyOption <$> argument str (metavar "NAME")
    opts = info parser mempty
  • オプション定義のデータ型を定義する
  • ハイフン付きのオプションだけでなく素の引数も定義できる
  • 簡単なヘルプが自動で出力される
$ runghc ex01.hs foo
name = foo
$ runghc ex01.hs
Usage: ex01.hs NAME

1文字オプション

  • 1文字オプションは、-で始まる1文字のオプション名。
  • short で設定する
module Main where

import Options.Applicative

data MyOption= MyOption { optName :: String
                        , a :: Bool
                        , b :: String
                        , c :: Maybe String
                        } deriving Show

run :: MyOption -> IO ()
run opts = print opts

parser = MyOption <$> argument str (metavar "NAME")
                  <*> switch              (short 'a' <> help "1文字オプション 引数なし")
                  <*> strOption           (short 'b' <> help "1文字オプション 引数あり (必須)")
                  <*> optional (strOption (short 'c' <> help "1文字オプション 引数あり (省略可能)"))

main :: IO ()
main = execParser opts >>= run
  where opts = info parser idm

1文字オプションとロングオプション

  • ロングオプションは、--で始まる2文字以上のオプション名。
module Main where

import Options.Applicative

data MyOption= MyOption { optName :: String
                        , a :: Bool
                        , b :: String
                        , c :: Maybe String
                        } deriving Show

run :: MyOption -> IO ()
run opts = print opts

parser = MyOption <$> argument str (metavar "NAME")
                  <*> switch              (short 'a' <> long "along" <> help "1文字オプション 引数なし")
                  <*> strOption           (short 'b' <> long "blong" <> help "1文字オプション 引数あり (必須)")
                  <*> optional (strOption (short 'c' <> long "clong" <> help "1文字オプション 引数あり (省略可能)"))

main :: IO ()
main = execParser opts >>= run
  where opts = info parser idm

noオプション

  • noオプションにあたるものは無さそう

オプション引数を数値や配列として受け取る

  • ハイフン指定無しの文字列引数は argument str
  • 文字列引数は strOption
  • 整数値などは option
  • 文字列リストは many . strOption
  • 整数リストはいくつか試してみたが方法がわからず
module Main where

import Options.Applicative

data MyOption= MyOption { optName :: String
                        , optStr  :: String
                        , optStr2 :: String
                        , optInt  :: Int
                        , optDouble :: Double
                        , optStrList :: [String]
                        -- , optIntList :: [Int]
                        } deriving Show

run :: MyOption -> IO ()
run opts = print opts

parser = MyOption <$> argument str       (metavar "NAME")
                  <*> strOption          (short 's' <> long "string"   <> help "string")
                  <*> option             (short 'x' <> long "string2" <> help "string2")
                  <*> option             (short 'i' <> long "int"      <> help "int")
                  <*> option             (short 'd' <> long "double"   <> help "double")
                  <*> (many . strOption) (short 'S' <> long "strlist"  <> help "string list")
                  -- <*> (many . option)    (short 'I' <> long "intlist"  <> help "int list")

main :: IO ()
main = execParser opts >>= run
  where opts = info parser idm

オプション引数の選択肢

TODO

オプション引数のパターン指定

TODO

ヘルプ表示をデザインする

TODO

その他の関数

このあたりを読めば他に使えそうな関数が見つかる

Options.Applicative.Builder

また、gitコマンドのようにサブコマンドを定義する方法も用意されていて便利そう
optparse-applicative/Cabal.hs at master · pcapriotti/optparse-applicative · GitHub

マニュアル

自分の勉強のために書いてみましたが、公式マニュアルが綺麗にまとまっているのでそっちを読んだ方がいいですよ、というオチ。

Haskellのデバッグ方法(受け売り)

Twitterでボヤいていたらいろいろ教えて頂いたので今後のために残しておこうと思います。


純粋なモナドでの

 !_ <- return $ trace (show a) a

は知らなかったのではまったら使いたいですね。

「エンジニアの学び方─効率的に知識を得て,成果に結び付ける」まとめ

記事の要約・引用。一部自分の言葉で若干表現を変えたかも。

1. 効率的に学ぶには

知識には3つの軸がある

  • 「広い視野」軸
    • 学ぶべき対象を見つける。勉強会・ブログ記事・ニュース記事。
  • 「深い理解」軸
    • 学びの効率化と応用のために必要
  • 「応用対象」軸
    • 自分の理解を応用して成果を出すために必要。

学びには3つのフェーズがある

  • 「知識収集」フェーズ
    • 情報収集
  • 「抽象化」フェーズ
    • 知識からモデルを作る
  • 「応用」フェーズ
    • 成功すると、正しく理解できているという自信が生まれる
やる気不足
  • やる気と成果は鶏と卵の関係。何かをやって成果を出すことで、次のやる気につながる。
  • 最初の一歩を踏み出す事が重要。

2. 最初の一歩をどう踏み出すか

  • やる気がでない場合、「勉強」を漠然とした大きなタスクとしてとらえていて、その大きさに圧倒されていることがよくある。
  • 近いゴールを設定し、そこまで走ることを目標にすることが必要。

必要なところから学ぶ

前提条件
  1. 目標が明確化されている
    • 達成したかどうかを判断できることが必要
  2. 目標が実現可能である
    • 「たどり着けそう」であることが必要
  3. 大まかに全体像を把握している

大まかに全体像をつかむ

  • 論文を最初から読んでも全然頭に入らない時、印刷し、25分間で章見出しとキーワードを赤ペンで囲う作業をした。
  • 論文を理解するというあいまいな目標の代わりに、時間を区切って明確なゴールを作り、大まかな構造を頭に入れようとした。

片っ端から写経する

時間を区切ろう

  • 本1冊を丸ごと写経するとどれくらいの時間がかかるでしょう。ゴールが見えないのでは、やる気がなくなります。そこで、時間を区切りましょう。たとえば「今から25分でできるとこまで写経するぞ」と目標を設定するのです。
  • 25分やってみると、やる前よりもいろいろなことがわかるようになります。「知りたいこと」が生まれているかもしれません。全体像がなんとなくわかったかもしれません。
  • もし何も得られた感じがしないのであれば、その本はあなたのニーズやレベルに合っていません。

3. どうやって深く理解するか

自分の知識が浅い気がする原因

  1. 「深い理解」方向の知識が足りない
  2. 「抽象化のフェーズ」に慣れていない
  • 「情報収集」だけでは成果は出せません。得た知識を自分の中で「抽象化」してモデルにし、自分の問題に応用して、はじめて成果が出ます。

なぜ抽象化が必要?

  • 抽象化によって応用範囲が広がります。抽象化は一般化・汎用化なのです。

どうやって抽象化するか

抽象化の確率を高めるツール
  1. 情報をたくさん収集する
  2. 情報を一覧できるようにする
  3. 関連のありそうなものを見つけて集め、ボトムアップで構造を作る。
比較から学ぶ
  • 同じ目的についての異なる著者の本を数冊、比較しながら読む。
歴史から学ぶ
抽象から学ぶ
  • 応用できる知識かどうかのチェックポイント
  1. 自分の言葉で説明できるか?
  2. 自分の経験に基づいた具体例を挙げることができるか?
  3. 自分の目的を達成するためにその知識を使えるか?

作って学ぶ
試してみて結果が期待どおりかを検証する
  • 本で読んだり勉強会で「なるほど、わかった」と思ったとします。
  • 「わかった」は「仮説」であり、「検証」が必要です。
  • 検証のためには、自分の理解をもとに行動をして、その結果が自分の期待どおりであるかをチェックする必要があります。
モデルが修正されるサイクル
作るものを高度にしすぎない
  • 遠すぎる目標を立てない
  • 作るものはプログラムとは限らず、「まだ知らない人、1日前の自分に説明するとしたら、どう説明するか?」を考えてブログ記事を書くのも「作る」です。
プログラミングは検証がしやすい
  • 他人の手を借りずに検証のサイクルを回せる
  • もしミュージシャンだったら、曲を作って演奏し、反響を見るまでにどれくらいの時間がかかることでしょう。
  • プログラマは理解を深めるうえでとても恵まれた環境にいるわけです。これを活かさないのはもったいないことです。

3のまとめ

  • モデルは正しくなくても、ないよりはマシ。
  • モデルがあれば、答えを知らない問題に対しても自分なりの答えを出すことができるようになります。

4. 何を学ぶか、何を作るか

やれと言われたことをやる

他人の真似をする

「解決すべき問題」を見つける

完璧を求めない

RJagsでMCMCやってみた (緑本9章)

9章の例題をやってみたメモ。
MacなのでWinBUGSは動かないからRJagsで。

インストール

Jags本体と、Rから使うためのRJagsを入れる必要がある。

Jags

Mac用のパッケージ(dmg)を入れた。
homebrewにもJagsはあるようだが、PATHがRJagsが想定しているデフォルトとは違うらしく面倒そう。特にこだわりが無ければパッケージを入れた方が楽。

RJags

普通に install.packages("rjags") するだけ

Rコード

使用するデータは書籍のサポートサイトからダウンロードできる。
同じ人の別記事にあるコードをちょっと変えただけで動いた。

library(rjags)

# 本のサポートサイトからダウンロードしたデータ読み込み
load("d.RData")

# データの準備
list.data <- list(
    N = nrow(d),
    Y = d$y,
    X = d$x,
    Mean.X = mean(d$x)
)

# 初期値の準備
inits <- list(
    beta1 = 0,
    beta2 = 0
)

# R内でのモデルの定義
m <- jags.model(
    file = "model.txt",
    data = list.data,
    inits = list(inits, inits, inits),
    n.chain = 3
)

# burn-in のためのカラまわしMCMC計算
update(m, 100)

# MCMC計算で事後分布からサンプリング
x <- coda.samples(
    m,
    c("beta1", "beta2"),
    thin = 3, n.iter = 1500, n.burnin = 100
)

plot(x)
  • 本の例題(WinBUGS)と違うのは、RJags では update(m, 100) がburn-inのための空回しらしい点。n.burnin=100 でも指定できているようだからどちらかが要らないと思う。

BUGSのコード (model.txt)

model
{
    for (i in 1:N) {
        Y[i] ~ dpois(lambda[i]);
        log(lambda[i]) <- beta1 + beta2 * (X[i] - Mean.X);
    }
    beta1 ~ dnorm(0, 1.0E-4);
    beta2 ~ dnorm(0, 1.0E-4);
}
  • Jagsではセミコロン必須らしい

プロット結果

f:id:mathhun:20140131081513p:plain

参考サイト

ログの収集・可視化サービス

人に教えてもらった。知らないのがたくさんある。
とりあえず貼っとくだけ。あとで軽く調べて概要書いてみる。

2つの正規分布(pdf)の積はまた正規分布?

PRML2章 (2.139)~(2.143)の式変形がわからない。

http://en.wikipedia.org/wiki/Conjugate_prior
http://www.cs.ubc.ca/~murphyk/Papers/bayesGauss.pdf
この辺を見ても同じことが書いてあるが手計算しても合わない。
あとでまた戻ってくるようにメモっとく。

「社内の情報共有・情報発信」(Web+DB Vol.77) を読んだ

今さら感満載だけど読んだ。というか読みなおした。社内でちょっとやってみようと思うので記事の内容を簡単にまとめておく。

書く側のメリット
  • 伝える技術を身につけられる
  • 書くことにより伝える事もうまくなる
  • 自分用メモ
読む側のメリット
  • いろいろな人のいろいろな見方・考え方を知ることができる
  • 誰がどんな仕事をしているのかがわかる
何を・何処に・誰が
  • 何を
    • 何でも良い。技術ネタはもちろん、共有メモ、サービスについての考え、ライフハックなど。
  • 何処に
    • 情報発信の場としては社内ブログなど
    • 情報ストックの場としてはWikiなど
  • 誰が
    • まずは1人でも書き始めてみる
    • メリットが認知されれば徐々に他のエンジニア、また非エンジニア職の人も書き始める。
情報の流通制御
  • 情報は流通すればするほど情報過多になってしまう
  • プッシュ型とプル型を使い分ける
    • 本当に知る必要があるものはプッシュ型。メールなど。
    • 必要と感じた時に能動的に受け取る情報はプル型
  • 価値の高い情報の見せ方
    • 「いいね」がたくさん集まったページをトップページに
まとめ
  • 社内で情報共有しよう。社内ブログやWikiを活用しよう。
  • 自分の知識や考えを伝えたり他人の知識を吸収できる。
  • 組織に所属するワクワク感アップ。
  • まずは1人でも書き始めてみる。


WEB+DB PRESS Vol.77

WEB+DB PRESS Vol.77

  • 作者: 中川勝樹,山内沙瑛,舟崎健治,吉荒祐一,今井雄太,八木橋徹平,安川健太,近藤宇智朗,奥野幹也,天野祐介,賈成カイ,伊藤直也,住川裕岳,北川貴久,菅原一志,後藤秀宣,久森達郎,登尾徳誠,渡邊恵太,中島聡,A-Listers,小俣裕一,はまちや2,川添貴生,石本光司,舘野祐一,沖田邦夫,澤村正樹,卜部昌平,吉藤博記,片山暁雄,平山毅,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/10/24
  • メディア: 大型本
  • この商品を含むブログ (2件) を見る