SlideShare a Scribd company logo
1 of 47
Download to read offline
数式を numpy に落としこむコツ
  ~機械学習を題材に~
         2011/10/15
   中谷   秀洋@サイボウズ・ラボ
    @shuyo / id:n_shuyo
「機械学習の手法を実装」って
    どうするの?

  機械学習の手法いろいろ



   数式! 数式! 数式!!!


     numpy で実装
今回のターゲット

機械学習の手法いろいろ
                ここは対象外



                    こ
数式! 数式! 数式!!!       こ
                    を
                    や
                ←   っ
                    つ
                    け
                    ま
  numpy で実装         す
                    !!
「数式→実装」は共通

機械学習      数値解析         統計処理



       数式! 数式! 数式!!!         こ
                             こ
                         ←   は
                             共
                             通
         numpy で実装
数式から実装まで
数式! 数式! 数式!!!



         数式見てすぐ実装?
         ムリムリ!




  numpy で実装
小さいステップに分解
 数式! 数式! 数式!!!

    数式から
 行間の情報を読み解く
                 今日のポイント

 「逐語訳」できる形に
  数式を書き換える

   numpy で実装
この後の流れ
1. 数式が降ってきた!
 – 「式はどうやって出てきたか」は無視!
2. (必要なら)数式を読み解こう
3. (必要なら)数式を書き換えよう
4. 数式を「逐語訳」で実装しよう
「数式」と言っても
  いろいろある
対象とする「数式」
• 数式の例は「パターン認識と機械学習」
  (以降 PRML)から引く
• 主に行列やその要素の掛け算が出てくる数式
 – 掛け算は基本中の基本!
• コンピュータで実装したい数式は、行列を
  使って表されているものも多い
 – 機械学習は典型例の1つ、かな?
 – 他の分野は……あまり知りません(苦笑
おことわり
• Python/numpyの基本機能は説明しません
 – Python の文法とか
 – 行列やベクトルの四則演算とか
  • ラムダ式とリスト内包はちょろっと紹介

• 線形代数の基本的な知識も説明しません
 – 四則演算とか、転置とか、逆行列とかとか
  • 行列式や固有値なんかは出てこないので安心して
記法
• 数式
 – ベクトルは太字の小文字
 – 行列は太字の大文字
                                 ネームスペースを
• コード                           省略するの嫌い~
                             C++ の using namespace も
 – import numpy は省略              使ったことないしw

 – import numpy as np はしない
 – numpy.matrix は使わず ndarray で
   • 行列積と要素積が紛らわしくなるとかいろいろ嫌いw
書き換え不要なパターン
まずは一番簡単なパターンから

 ������ =   ������ ������ ������ −1 ������ ������ ������   (PRML 3.15 改)

• 線形回帰のパラメータ推定の式
 – この式がどこから降ってきたかは気にしな
   い!
ちなみに「線形回帰」って?
• 回帰:与えられた点を(だいたい)通る曲線
  (関数)を見つけること
 – 「回帰」って何が戻ってくるの?     というの
   は突っ込んではいけないお約束
• 線形回帰:∑������������ ������(������)という線形結合の形
  の中で点を通るものを探す
 – 線形の関数(つまり直線)を求めているわけで
   はありません
一応紹介してみたけど、気にしなくていいですw
数式の「読み解き」

  ������ =   ������ ������ ������ −1 ������ ������ ������   (PRML 3.15 改)

• ������:N×M次元の特徴行列
 – 中身は気にしない
 – N×M次元の行列が与えられているだけ!
• t:N次のベクトル(正解データ)
 – 中身は気にしない(以下同様)
• w はベクトル? 行列? 何次の?
                 ※特徴行列の作り方は後の「おまけ」で出てきます
掛け算した行列のサイズの求め方
                                     各行列のサイズ。
                                       ベクトルは
                ������      −1     ������
       ������ = ������ ������            ������ ������   1列の行列として




M×1 ← (M×N N×M) M×N N×1

 両端の行数・列数が           隣接する行列の列数と行数は一致。
行列(ベクトル)のサイズ。        そうでなければ必ずどこか間違ってる
 列数が1ならベクトル

      「数式がわからない」というとき
    この段階で間違っていることも少なくない
numpy に「逐語訳」

     ������ =      ������ ������ ������ −1 ������ ������ ������       (PRML 3.15 改)


      numpy.dot(PHI.T, PHI)   numpy.dot(PHI.T, t)

     ������−1 ������ = numpy.linalg.solve(������, ������)
# PHI = N×M次元の特徴行列
# t = N次のベクトル(正解データ)

w = numpy.linalg.solve(numpy.dot(PHI.T, PHI),
                          numpy.dot(PHI.T, t))
                          ※ 逆行列のところで inv() を使ってもいいですが、
                       solve() の方がコードが短いし、速度もかなり速いです
いつもこんなにかんたんとは
   限りませんよね
書き換えが必要になるパターン
多クラスロジスティック回帰の
       誤差関数の勾配
                   ������

 ������������������ ������ ������ =          ������������������ − ������������������ ������������ (k = 1, ⋯ , ������)
                  ������=1
                                                (PRML 4.109 改)

• ������ = ������������������ : N×K 次行列(予測値)
                                                           与
• ������ = ������������������ : N×K 次行列(1-of-K 表現)                         え
                                                           ら
• ������ = ������1 , … , ������������ = (������������������ ) : M×K 次行列                れ
                                                           て
                                                           い
• ������ = ������������������ = ������1 , ⋯ , ������������      ������
                                         : N×M 次行列         る
                                                           情
   – ������������ = ������ ������������ = ������������ ������������   ������ :   M 次ベクトル           報
「ロジスティック回帰」って?
「誤差関数」って?
「勾配」って?
式がどこから降ってきたかは
   気にしない!
さすがに「勾配」は
      必要なんじゃあないの?
                        ������
 これ
      ������������������ ������ ������ =          ������������������ − ������������������ ������������
                       ������=1
• 右辺は M 次ベクトル
 – ������������������ − ������������������ はただのスカラー
 – 一般には先ほどの方法で次元を読み解けばいい
• それが k=1,……,K 個あるだけ
 – つまり求めるのは「M×K次元の行列」と読み解く
• ∴「勾配」は実装になんの関係もない!
求めるものは
読み解けたが
どうすれば実装できるか
  まだよくわからない
「逐語訳」できる形に書き換える

• 掛けて行列になるパターンは大きく3通り
 – 上から要素積、行列積、直積

  ������������������ = ������������������ ������������������   ⇔       C=A*B
������������������ = ∑������ ������������������ ������������������ ⇔   C=numpy.dot(A, B)
    ������������������ = ������������ ������������     ⇔ C=numpy.outer(a, b)
        数式を左の形に書き換えれば、
      右の numpy コードに「逐語訳」できる
                           ※「外積」もあるが、使う人やシーンが限られるので略
式を書き換える (1)
                          ������

      ������������������ ������ ������ =             ������������������ − ������������������ ������������
                       ������=1

• 行列の要素の式になおす
                           ������

     ������������ ������   ������������
                      =           ������������������ − ������������������ ������������������
                          ������=1
                                (������ = 1, ⋯ , ������; ������ = 1, ⋯ , ������)
 – ������������ ������ は「求める行列」としてひとかたまりで扱う
式を書き換える (2)
                            ������

      ������������ ������   ������������
                       =          ������������������ − ������������������ ������������������
                           ������=1
• 注:右辺の添え字に未解決のものは残らない
 – 左辺に現れる : m, k
 – 右辺で解決 : n (総和で消える)
• 3種類の積のどれかに帰着するよう変形
 – この場合、総和があるので ������������������ = ∑������ ������������������ ������������������ に
式を書き換える (3)
  ������ = ������������������ = ������������������ − ������������������ とおくと(������ × ������ 行列)
                         ������                       ������

   ������������ ������   ������������
                    =          ������������������ ������������������ =          ������   ������������   ������   ������������
                        ������=1                     ������=1
• 右辺を Σn○mn○nk の形に調整
                                                                       内側は
  – 左辺が○mk & 右辺は n で和を取っている                                          同じ添え字同士
  – 添え字の順序を逆にしたければ転置でOK
• ������������ ������ = ������ ������ ������ であることがわかる
  – 難しくて実装できなさそうだった式が かんたんに!
numpyに「逐語訳」
• ������ = ������ − ������, ������������ ������ = ������ ������ ������ を実装
   – うわあ、かんたんすぎ
# PHI = N×M 次元の特徴行列
# Y, T = N×K 次元の行列

gradient_E = numpy.dot(PHI.T, Y - T)
• 元の数式と見比べてみよう
                      ������

    ������������������ ������ ������ =          ������������������ − ������������������ ������������ (k = 1, ⋯ , ������)
                     ������=1
まとめ
• 数式から条件を読み解こう
 – この段階で間違っていると、絶対うまく行かない
 – さぼらず紙と鉛筆で確認するのが一番賢い
• 「逐語訳」できる数式なら実装かんたん
 – 基本機能の呼び出しで完成!
 – 難しい数式は「逐語訳」できる形に書き換え
 – さぼらず紙と鉛筆(ry
(おまけ)
「リスト内包」を使いこなして楽しよう
特徴行列(先ほどの ������)
         ������1 ������1    ������1 ������2    ⋯ ������1 ������������
         ������2 ������1    ������2 ������2    ⋯ ������2 ������������
  ������ =
             ⋮          ⋮      ⋱     ⋮
         ������������ ������1   ������������ ������2   ⋯ ������������ ������������


• 関数 ������ ������ = ������1 ������ , ⋯ , ������������ ������   と、
• データ ������ = (������1 , ⋯ , ������������ ) から作る行列
  – カーネル法のグラム行列も似たような作り
特徴行列の作り方 (1)
# X = N×D 次元の行列(今回は D=1)
phi = [
  lambda x: 1,
  lambda x: x,      # φ:特徴関数の列
  lambda x: x ** 2, # lambda ってなに?
  lambda x: x ** 3
]

N =   len(X)
M =   len(phi)
PHI   = numpy.zeros((N, M)) # Φ:N×M行列の入れ物を用意
for   n in xrange(N):
      for m in xrange(M):
          PHI[n, m] = phi[m](X[n]) # φ_m(x_n)
‘lambda’ ってなに?
ぷちPython講座:ラムダ式
• lambda : その場で関数を作る
   – def を書かなくていい
f = lambda x: x ** 3

                                だいたい同じ

def f(x):
    return x ** 3

                    ※厳密には def と lambda はいろいろ違うわけだけど、
                                   ここでは細かいことは気にしない
つまりラムダ式のところは
phi = [
  lambda   x:   1,        #   φ_0(x)   =   1
  lambda   x:   x,        #   φ_1(x)   =   x
  lambda   x:   x ** 2,   #   φ_2(x)   =   x^2
  lambda   x:   x ** 3    #   φ_3(x)   =   x^3
]

• 実はこの数式の実装でした
    ������������ ������ = ������ ������ (������ = 0, ⋯ , ������ − 1)
• 繰り返しなんだから、もっとかんたんに
  できそう
ぷちPython講座:リスト内包
• リスト内包 : ルールから配列を作る
   – for ループを書かなくていい
   – R の apply() 系の関数に相当
a = []
for x in xrange(10):
    a.append(x * x)

                                  リスト内包なら簡潔!

a = [x * x for x in xrange(10)]
                                     ※厳密にはいろいろ(ry
「リスト内包」を使えば……
phi = [
  lambda   x:   1,
  lambda   x:   x,
                          ������������ ������ = ������ ������ (������ = 0, ⋯ , ������ − 1)
  lambda   x:   x ** 2,
  lambda   x:   x ** 3
]

                                    こう書ける気がする

phi = [lambda x: x ** m for m in xrange(M)]

• かんたんになったね!
だめでした……
• ������0 2 , ������1 2 , ������2 2 , ������3 2 を表示してみる
   – “1 2 4 8” と出力されることを期待

M = 4
phi = [lambda x: x ** m for m in xrange(M)]
print phi[0](2), phi[1](2), phi[2](2), phi[3](2)


• ところがこれの実行結果は “8 8 8 8”
   – って、全部同じ!? なんで???
うまくいかない理由は……
• 「レキシカルスコープ」がどうとか
   – ちょっとややこしい
• 回避する裏技もあるけど……
   – もっとややこしい

M = 4
phi = [lambda x, c=m: x ** c for m in xrange(M)]
print phi[0](2), phi[1](2), phi[2](2), phi[3](2)
# => “1 2 4 8” と表示される(ドヤ
結論
• リスト内包の中では lambda を使わない
  ようにしよう!(ぇ
 – これで同種の問題はだいたい避けられる
• かんたんに書く他の方法を考えてみる
特徴行列の作り方 (2)
• phi を「ベクトルを返す関数」として定義
   – ������������ のリストではなく,������ = (������������ )を扱う
   – lambda を書かなくていい
   – 関数の呼び出し回数も減って高速化
• 行列の生成にもリスト内包を使う                        numpy の機能の
                                          一部と言っても
   – numpy.array(リスト内包) は頻出!               いいくらい


def phi(x):
    return [x ** m for m in xrange(4)]

PHI = numpy.array([phi(x) for x in X])
まとめ
• リスト内包は超便利
 – 憶えましょう
 – 憶えてなかったら Python 使ってる意味ない
   と言い切ってしまっていいくらい
• ラムダ式も便利
 – でもリスト内包の中で使うとハマることがあ
   るので避けましょう
よだん
• numpy.fromfunction() を使って特徴行
  列を作る方法もあるよ。あるけど……
   – なんかいろいろひどい
      • take とか dtype=int とか
   – ダメな numpy の見本

PHI = numpy.fromfunction(
       lambda n, m: X.take(n) ** m, (N, M), dtype=int)

More Related Content

What's hot

Rで階層ベイズモデル
Rで階層ベイズモデルRで階層ベイズモデル
Rで階層ベイズモデル
Yohei Sato
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類
Shintaro Fukushima
 
変分推論法(変分ベイズ法)(PRML第10章)
変分推論法(変分ベイズ法)(PRML第10章)変分推論法(変分ベイズ法)(PRML第10章)
変分推論法(変分ベイズ法)(PRML第10章)
Takao Yamanaka
 
階層ベイズによるワンToワンマーケティング入門
階層ベイズによるワンToワンマーケティング入門階層ベイズによるワンToワンマーケティング入門
階層ベイズによるワンToワンマーケティング入門
shima o
 

What's hot (20)

関数データ解析の概要とその方法
関数データ解析の概要とその方法関数データ解析の概要とその方法
関数データ解析の概要とその方法
 
サポートベクターマシン(SVM)の数学をみんなに説明したいだけの会
サポートベクターマシン(SVM)の数学をみんなに説明したいだけの会サポートベクターマシン(SVM)の数学をみんなに説明したいだけの会
サポートベクターマシン(SVM)の数学をみんなに説明したいだけの会
 
Fisher線形判別分析とFisher Weight Maps
Fisher線形判別分析とFisher Weight MapsFisher線形判別分析とFisher Weight Maps
Fisher線形判別分析とFisher Weight Maps
 
PRML読み会第一章
PRML読み会第一章PRML読み会第一章
PRML読み会第一章
 
スパース推定法による統計モデリング(入門)
スパース推定法による統計モデリング(入門)スパース推定法による統計モデリング(入門)
スパース推定法による統計モデリング(入門)
 
Rで階層ベイズモデル
Rで階層ベイズモデルRで階層ベイズモデル
Rで階層ベイズモデル
 
機械学習による統計的実験計画(ベイズ最適化を中心に)
機械学習による統計的実験計画(ベイズ最適化を中心に)機械学習による統計的実験計画(ベイズ最適化を中心に)
機械学習による統計的実験計画(ベイズ最適化を中心に)
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類
 
変分推論法(変分ベイズ法)(PRML第10章)
変分推論法(変分ベイズ法)(PRML第10章)変分推論法(変分ベイズ法)(PRML第10章)
変分推論法(変分ベイズ法)(PRML第10章)
 
変分ベイズ法の説明
変分ベイズ法の説明変分ベイズ法の説明
変分ベイズ法の説明
 
金融時系列のための深層t過程回帰モデル
金融時系列のための深層t過程回帰モデル金融時系列のための深層t過程回帰モデル
金融時系列のための深層t過程回帰モデル
 
心理学者のためのGlmm・階層ベイズ
心理学者のためのGlmm・階層ベイズ心理学者のためのGlmm・階層ベイズ
心理学者のためのGlmm・階層ベイズ
 
クラシックな機械学習入門:付録:よく使う線形代数の公式
クラシックな機械学習入門:付録:よく使う線形代数の公式クラシックな機械学習入門:付録:よく使う線形代数の公式
クラシックな機械学習入門:付録:よく使う線形代数の公式
 
スパースモデリング、スパースコーディングとその数理(第11回WBA若手の会)
スパースモデリング、スパースコーディングとその数理(第11回WBA若手の会)スパースモデリング、スパースコーディングとその数理(第11回WBA若手の会)
スパースモデリング、スパースコーディングとその数理(第11回WBA若手の会)
 
ベイズ統計学の概論的紹介
ベイズ統計学の概論的紹介ベイズ統計学の概論的紹介
ベイズ統計学の概論的紹介
 
階層ベイズによるワンToワンマーケティング入門
階層ベイズによるワンToワンマーケティング入門階層ベイズによるワンToワンマーケティング入門
階層ベイズによるワンToワンマーケティング入門
 
PRML 第4章
PRML 第4章PRML 第4章
PRML 第4章
 
coordinate descent 法について
coordinate descent 法についてcoordinate descent 法について
coordinate descent 法について
 
StanとRでベイズ統計モデリングに関する読書会(Osaka.stan) 第四章
StanとRでベイズ統計モデリングに関する読書会(Osaka.stan) 第四章StanとRでベイズ統計モデリングに関する読書会(Osaka.stan) 第四章
StanとRでベイズ統計モデリングに関する読書会(Osaka.stan) 第四章
 
IIBMP2016 深層生成モデルによる表現学習
IIBMP2016 深層生成モデルによる表現学習IIBMP2016 深層生成モデルによる表現学習
IIBMP2016 深層生成モデルによる表現学習
 

Viewers also liked

数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013
Shuyo Nakatani
 
111015 tokyo scipy2_ディスカッション
111015 tokyo scipy2_ディスカッション111015 tokyo scipy2_ディスカッション
111015 tokyo scipy2_ディスカッション
Shohei Hido
 
猫に教えてもらうルベーグ可測
猫に教えてもらうルベーグ可測猫に教えてもらうルベーグ可測
猫に教えてもらうルベーグ可測
Shuyo Nakatani
 
Simple perceptron by TJO
Simple perceptron by TJOSimple perceptron by TJO
Simple perceptron by TJO
Takashi J OZAKI
 

Viewers also liked (14)

NumPy闇入門
NumPy闇入門NumPy闇入門
NumPy闇入門
 
数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013
 
CuPy解説
CuPy解説CuPy解説
CuPy解説
 
20160319 プログラマのための数学勉強会
20160319 プログラマのための数学勉強会20160319 プログラマのための数学勉強会
20160319 プログラマのための数学勉強会
 
111015 tokyo scipy2_ディスカッション
111015 tokyo scipy2_ディスカッション111015 tokyo scipy2_ディスカッション
111015 tokyo scipy2_ディスカッション
 
多次元配列の効率的利用法の検討
多次元配列の効率的利用法の検討多次元配列の効率的利用法の検討
多次元配列の効率的利用法の検討
 
「plyrパッケージで君も前処理スタ☆」改め「plyrパッケージ徹底入門」
「plyrパッケージで君も前処理スタ☆」改め「plyrパッケージ徹底入門」「plyrパッケージで君も前処理スタ☆」改め「plyrパッケージ徹底入門」
「plyrパッケージで君も前処理スタ☆」改め「plyrパッケージ徹底入門」
 
猫に教えてもらうルベーグ可測
猫に教えてもらうルベーグ可測猫に教えてもらうルベーグ可測
猫に教えてもらうルベーグ可測
 
ディープラーニングにおける学習の高速化の重要性とその手法
ディープラーニングにおける学習の高速化の重要性とその手法ディープラーニングにおける学習の高速化の重要性とその手法
ディープラーニングにおける学習の高速化の重要性とその手法
 
ボケるRNNを学習したい (Chainer meetup 01)
ボケるRNNを学習したい (Chainer meetup 01)ボケるRNNを学習したい (Chainer meetup 01)
ボケるRNNを学習したい (Chainer meetup 01)
 
Lighting talk chainer hands on
Lighting talk chainer hands onLighting talk chainer hands on
Lighting talk chainer hands on
 
Chainer Contribution Guide
Chainer Contribution GuideChainer Contribution Guide
Chainer Contribution Guide
 
Chainer meetup lt
Chainer meetup ltChainer meetup lt
Chainer meetup lt
 
Simple perceptron by TJO
Simple perceptron by TJOSimple perceptron by TJO
Simple perceptron by TJO
 

Similar to 数式をnumpyに落としこむコツ

mathemaical_notation
mathemaical_notationmathemaical_notation
mathemaical_notation
Kenta Oono
 
2011年11月11日
2011年11月11日2011年11月11日
2011年11月11日
nukaemon
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
Ransui Iso
 
Math tutorial public
Math tutorial publicMath tutorial public
Math tutorial public
Kenta Oono
 

Similar to 数式をnumpyに落としこむコツ (20)

Lispでやる記号微分
Lispでやる記号微分Lispでやる記号微分
Lispでやる記号微分
 
関数型都市忘年会『はじめての函数型プログラミング』
関数型都市忘年会『はじめての函数型プログラミング』関数型都市忘年会『はじめての函数型プログラミング』
関数型都市忘年会『はじめての函数型プログラミング』
 
秘密分散法の数理
秘密分散法の数理秘密分散法の数理
秘密分散法の数理
 
Pythonintro
PythonintroPythonintro
Pythonintro
 
mathemaical_notation
mathemaical_notationmathemaical_notation
mathemaical_notation
 
勉強会課題①
勉強会課題①勉強会課題①
勉強会課題①
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
 
【Zansa】第12回勉強会 -PRMLからベイズの世界へ
【Zansa】第12回勉強会 -PRMLからベイズの世界へ【Zansa】第12回勉強会 -PRMLからベイズの世界へ
【Zansa】第12回勉強会 -PRMLからベイズの世界へ
 
2011年11月11日
2011年11月11日2011年11月11日
2011年11月11日
 
Python勉強会2-数値と文字列
Python勉強会2-数値と文字列Python勉強会2-数値と文字列
Python勉強会2-数値と文字列
 
論文紹介 Semi-supervised Learning with Deep Generative Models
論文紹介 Semi-supervised Learning with Deep Generative Models論文紹介 Semi-supervised Learning with Deep Generative Models
論文紹介 Semi-supervised Learning with Deep Generative Models
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
 
Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2Lisp tutorial for Pythonista : Day 2
Lisp tutorial for Pythonista : Day 2
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
Math tutorial public
Math tutorial publicMath tutorial public
Math tutorial public
 
Abc009
Abc009Abc009
Abc009
 
AtCoder Beginner Contest 009 解説
AtCoder Beginner Contest 009 解説AtCoder Beginner Contest 009 解説
AtCoder Beginner Contest 009 解説
 
Ruby 3の型推論やってます
Ruby 3の型推論やってますRuby 3の型推論やってます
Ruby 3の型推論やってます
 
ランダム・シャッフル
ランダム・シャッフルランダム・シャッフル
ランダム・シャッフル
 
アルゴリズムとデータ構造10
アルゴリズムとデータ構造10アルゴリズムとデータ構造10
アルゴリズムとデータ構造10
 

More from Shuyo Nakatani

言語処理するのに Python でいいの? #PyDataTokyo
言語処理するのに Python でいいの? #PyDataTokyo言語処理するのに Python でいいの? #PyDataTokyo
言語処理するのに Python でいいの? #PyDataTokyo
Shuyo Nakatani
 
ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...
ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...
ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...
Shuyo Nakatani
 
どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013
どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013
どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013
Shuyo Nakatani
 
Active Learning 入門
Active Learning 入門Active Learning 入門
Active Learning 入門
Shuyo Nakatani
 
Short Text Language Detection with Infinity-Gram
Short Text Language Detection with Infinity-GramShort Text Language Detection with Infinity-Gram
Short Text Language Detection with Infinity-Gram
Shuyo Nakatani
 

More from Shuyo Nakatani (20)

画像をテキストで検索したい!(OpenAI CLIP) - VRC-LT #15
画像をテキストで検索したい!(OpenAI CLIP) - VRC-LT #15画像をテキストで検索したい!(OpenAI CLIP) - VRC-LT #15
画像をテキストで検索したい!(OpenAI CLIP) - VRC-LT #15
 
Generative adversarial networks
Generative adversarial networksGenerative adversarial networks
Generative adversarial networks
 
無限関係モデル (続・わかりやすいパターン認識 13章)
無限関係モデル (続・わかりやすいパターン認識 13章)無限関係モデル (続・わかりやすいパターン認識 13章)
無限関係モデル (続・わかりやすいパターン認識 13章)
 
Memory Networks (End-to-End Memory Networks の Chainer 実装)
Memory Networks (End-to-End Memory Networks の Chainer 実装)Memory Networks (End-to-End Memory Networks の Chainer 実装)
Memory Networks (End-to-End Memory Networks の Chainer 実装)
 
人工知能と機械学習の違いって?
人工知能と機械学習の違いって?人工知能と機械学習の違いって?
人工知能と機械学習の違いって?
 
RとStanでクラウドセットアップ時間を分析してみたら #TokyoR
RとStanでクラウドセットアップ時間を分析してみたら #TokyoRRとStanでクラウドセットアップ時間を分析してみたら #TokyoR
RとStanでクラウドセットアップ時間を分析してみたら #TokyoR
 
ドラえもんでわかる統計的因果推論 #TokyoR
ドラえもんでわかる統計的因果推論 #TokyoRドラえもんでわかる統計的因果推論 #TokyoR
ドラえもんでわかる統計的因果推論 #TokyoR
 
[Yang, Downey and Boyd-Graber 2015] Efficient Methods for Incorporating Knowl...
[Yang, Downey and Boyd-Graber 2015] Efficient Methods for Incorporating Knowl...[Yang, Downey and Boyd-Graber 2015] Efficient Methods for Incorporating Knowl...
[Yang, Downey and Boyd-Graber 2015] Efficient Methods for Incorporating Knowl...
 
星野「調査観察データの統計科学」第3章
星野「調査観察データの統計科学」第3章星野「調査観察データの統計科学」第3章
星野「調査観察データの統計科学」第3章
 
星野「調査観察データの統計科学」第1&2章
星野「調査観察データの統計科学」第1&2章星野「調査観察データの統計科学」第1&2章
星野「調査観察データの統計科学」第1&2章
 
言語処理するのに Python でいいの? #PyDataTokyo
言語処理するのに Python でいいの? #PyDataTokyo言語処理するのに Python でいいの? #PyDataTokyo
言語処理するのに Python でいいの? #PyDataTokyo
 
Zipf? (ジップ則のひみつ?) #DSIRNLP
Zipf? (ジップ則のひみつ?) #DSIRNLPZipf? (ジップ則のひみつ?) #DSIRNLP
Zipf? (ジップ則のひみつ?) #DSIRNLP
 
ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...
ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...
ACL2014 Reading: [Zhang+] "Kneser-Ney Smoothing on Expected Count" and [Pickh...
 
ソーシャルメディアの多言語判定 #SoC2014
ソーシャルメディアの多言語判定 #SoC2014ソーシャルメディアの多言語判定 #SoC2014
ソーシャルメディアの多言語判定 #SoC2014
 
アラビア語とペルシャ語の見分け方 #DSIRNLP 5
アラビア語とペルシャ語の見分け方 #DSIRNLP 5アラビア語とペルシャ語の見分け方 #DSIRNLP 5
アラビア語とペルシャ語の見分け方 #DSIRNLP 5
 
どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013
どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013
どの言語でつぶやかれたのか、機械が知る方法 #WebDBf2013
 
Active Learning 入門
Active Learning 入門Active Learning 入門
Active Learning 入門
 
ノンパラベイズ入門の入門
ノンパラベイズ入門の入門ノンパラベイズ入門の入門
ノンパラベイズ入門の入門
 
[Kim+ ICML2012] Dirichlet Process with Mixed Random Measures : A Nonparametri...
[Kim+ ICML2012] Dirichlet Process with Mixed Random Measures : A Nonparametri...[Kim+ ICML2012] Dirichlet Process with Mixed Random Measures : A Nonparametri...
[Kim+ ICML2012] Dirichlet Process with Mixed Random Measures : A Nonparametri...
 
Short Text Language Detection with Infinity-Gram
Short Text Language Detection with Infinity-GramShort Text Language Detection with Infinity-Gram
Short Text Language Detection with Infinity-Gram
 

数式をnumpyに落としこむコツ

  • 1. 数式を numpy に落としこむコツ ~機械学習を題材に~ 2011/10/15 中谷 秀洋@サイボウズ・ラボ @shuyo / id:n_shuyo
  • 2. 「機械学習の手法を実装」って どうするの? 機械学習の手法いろいろ 数式! 数式! 数式!!! numpy で実装
  • 3. 今回のターゲット 機械学習の手法いろいろ ここは対象外 こ 数式! 数式! 数式!!! こ を や ← っ つ け ま numpy で実装 す !!
  • 4. 「数式→実装」は共通 機械学習 数値解析 統計処理 数式! 数式! 数式!!! こ こ ← は 共 通 numpy で実装
  • 5. 数式から実装まで 数式! 数式! 数式!!! 数式見てすぐ実装? ムリムリ! numpy で実装
  • 6. 小さいステップに分解 数式! 数式! 数式!!! 数式から 行間の情報を読み解く 今日のポイント 「逐語訳」できる形に 数式を書き換える numpy で実装
  • 7. この後の流れ 1. 数式が降ってきた! – 「式はどうやって出てきたか」は無視! 2. (必要なら)数式を読み解こう 3. (必要なら)数式を書き換えよう 4. 数式を「逐語訳」で実装しよう
  • 9. 対象とする「数式」 • 数式の例は「パターン認識と機械学習」 (以降 PRML)から引く • 主に行列やその要素の掛け算が出てくる数式 – 掛け算は基本中の基本! • コンピュータで実装したい数式は、行列を 使って表されているものも多い – 機械学習は典型例の1つ、かな? – 他の分野は……あまり知りません(苦笑
  • 10. おことわり • Python/numpyの基本機能は説明しません – Python の文法とか – 行列やベクトルの四則演算とか • ラムダ式とリスト内包はちょろっと紹介 • 線形代数の基本的な知識も説明しません – 四則演算とか、転置とか、逆行列とかとか • 行列式や固有値なんかは出てこないので安心して
  • 11. 記法 • 数式 – ベクトルは太字の小文字 – 行列は太字の大文字 ネームスペースを • コード 省略するの嫌い~ C++ の using namespace も – import numpy は省略 使ったことないしw – import numpy as np はしない – numpy.matrix は使わず ndarray で • 行列積と要素積が紛らわしくなるとかいろいろ嫌いw
  • 13. まずは一番簡単なパターンから ������ = ������ ������ ������ −1 ������ ������ ������ (PRML 3.15 改) • 線形回帰のパラメータ推定の式 – この式がどこから降ってきたかは気にしな い!
  • 14. ちなみに「線形回帰」って? • 回帰:与えられた点を(だいたい)通る曲線 (関数)を見つけること – 「回帰」って何が戻ってくるの? というの は突っ込んではいけないお約束 • 線形回帰:∑������������ ������(������)という線形結合の形 の中で点を通るものを探す – 線形の関数(つまり直線)を求めているわけで はありません 一応紹介してみたけど、気にしなくていいですw
  • 15. 数式の「読み解き」 ������ = ������ ������ ������ −1 ������ ������ ������ (PRML 3.15 改) • ������:N×M次元の特徴行列 – 中身は気にしない – N×M次元の行列が与えられているだけ! • t:N次のベクトル(正解データ) – 中身は気にしない(以下同様) • w はベクトル? 行列? 何次の? ※特徴行列の作り方は後の「おまけ」で出てきます
  • 16. 掛け算した行列のサイズの求め方 各行列のサイズ。 ベクトルは ������ −1 ������ ������ = ������ ������ ������ ������ 1列の行列として M×1 ← (M×N N×M) M×N N×1 両端の行数・列数が 隣接する行列の列数と行数は一致。 行列(ベクトル)のサイズ。 そうでなければ必ずどこか間違ってる 列数が1ならベクトル 「数式がわからない」というとき この段階で間違っていることも少なくない
  • 17. numpy に「逐語訳」 ������ = ������ ������ ������ −1 ������ ������ ������ (PRML 3.15 改) numpy.dot(PHI.T, PHI) numpy.dot(PHI.T, t) ������−1 ������ = numpy.linalg.solve(������, ������) # PHI = N×M次元の特徴行列 # t = N次のベクトル(正解データ) w = numpy.linalg.solve(numpy.dot(PHI.T, PHI), numpy.dot(PHI.T, t)) ※ 逆行列のところで inv() を使ってもいいですが、 solve() の方がコードが短いし、速度もかなり速いです
  • 20. 多クラスロジスティック回帰の 誤差関数の勾配 ������ ������������������ ������ ������ = ������������������ − ������������������ ������������ (k = 1, ⋯ , ������) ������=1 (PRML 4.109 改) • ������ = ������������������ : N×K 次行列(予測値) 与 • ������ = ������������������ : N×K 次行列(1-of-K 表現) え ら • ������ = ������1 , … , ������������ = (������������������ ) : M×K 次行列 れ て い • ������ = ������������������ = ������1 , ⋯ , ������������ ������ : N×M 次行列 る 情 – ������������ = ������ ������������ = ������������ ������������ ������ : M 次ベクトル 報
  • 25. さすがに「勾配」は 必要なんじゃあないの? ������ これ ������������������ ������ ������ = ������������������ − ������������������ ������������ ������=1 • 右辺は M 次ベクトル – ������������������ − ������������������ はただのスカラー – 一般には先ほどの方法で次元を読み解けばいい • それが k=1,……,K 個あるだけ – つまり求めるのは「M×K次元の行列」と読み解く • ∴「勾配」は実装になんの関係もない!
  • 28. 「逐語訳」できる形に書き換える • 掛けて行列になるパターンは大きく3通り – 上から要素積、行列積、直積 ������������������ = ������������������ ������������������ ⇔ C=A*B ������������������ = ∑������ ������������������ ������������������ ⇔ C=numpy.dot(A, B) ������������������ = ������������ ������������ ⇔ C=numpy.outer(a, b) 数式を左の形に書き換えれば、 右の numpy コードに「逐語訳」できる ※「外積」もあるが、使う人やシーンが限られるので略
  • 29. 式を書き換える (1) ������ ������������������ ������ ������ = ������������������ − ������������������ ������������ ������=1 • 行列の要素の式になおす ������ ������������ ������ ������������ = ������������������ − ������������������ ������������������ ������=1 (������ = 1, ⋯ , ������; ������ = 1, ⋯ , ������) – ������������ ������ は「求める行列」としてひとかたまりで扱う
  • 30. 式を書き換える (2) ������ ������������ ������ ������������ = ������������������ − ������������������ ������������������ ������=1 • 注:右辺の添え字に未解決のものは残らない – 左辺に現れる : m, k – 右辺で解決 : n (総和で消える) • 3種類の積のどれかに帰着するよう変形 – この場合、総和があるので ������������������ = ∑������ ������������������ ������������������ に
  • 31. 式を書き換える (3) ������ = ������������������ = ������������������ − ������������������ とおくと(������ × ������ 行列) ������ ������ ������������ ������ ������������ = ������������������ ������������������ = Φ������ ������������ ������ ������������ ������=1 ������=1 • 右辺を Σn○mn○nk の形に調整 内側は – 左辺が○mk & 右辺は n で和を取っている 同じ添え字同士 – 添え字の順序を逆にしたければ転置でOK • ������������ ������ = ������ ������ ������ であることがわかる – 難しくて実装できなさそうだった式が かんたんに!
  • 32. numpyに「逐語訳」 • ������ = ������ − ������, ������������ ������ = ������ ������ ������ を実装 – うわあ、かんたんすぎ # PHI = N×M 次元の特徴行列 # Y, T = N×K 次元の行列 gradient_E = numpy.dot(PHI.T, Y - T) • 元の数式と見比べてみよう ������ ������������������ ������ ������ = ������������������ − ������������������ ������������ (k = 1, ⋯ , ������) ������=1
  • 33. まとめ • 数式から条件を読み解こう – この段階で間違っていると、絶対うまく行かない – さぼらず紙と鉛筆で確認するのが一番賢い • 「逐語訳」できる数式なら実装かんたん – 基本機能の呼び出しで完成! – 難しい数式は「逐語訳」できる形に書き換え – さぼらず紙と鉛筆(ry
  • 35. 特徴行列(先ほどの ������) ������1 ������1 ������1 ������2 ⋯ ������1 ������������ ������2 ������1 ������2 ������2 ⋯ ������2 ������������ ������ = ⋮ ⋮ ⋱ ⋮ ������������ ������1 ������������ ������2 ⋯ ������������ ������������ • 関数 ������ ������ = ������1 ������ , ⋯ , ������������ ������ と、 • データ ������ = (������1 , ⋯ , ������������ ) から作る行列 – カーネル法のグラム行列も似たような作り
  • 36. 特徴行列の作り方 (1) # X = N×D 次元の行列(今回は D=1) phi = [ lambda x: 1, lambda x: x, # φ:特徴関数の列 lambda x: x ** 2, # lambda ってなに? lambda x: x ** 3 ] N = len(X) M = len(phi) PHI = numpy.zeros((N, M)) # Φ:N×M行列の入れ物を用意 for n in xrange(N): for m in xrange(M): PHI[n, m] = phi[m](X[n]) # φ_m(x_n)
  • 38. ぷちPython講座:ラムダ式 • lambda : その場で関数を作る – def を書かなくていい f = lambda x: x ** 3 だいたい同じ def f(x): return x ** 3 ※厳密には def と lambda はいろいろ違うわけだけど、 ここでは細かいことは気にしない
  • 39. つまりラムダ式のところは phi = [ lambda x: 1, # φ_0(x) = 1 lambda x: x, # φ_1(x) = x lambda x: x ** 2, # φ_2(x) = x^2 lambda x: x ** 3 # φ_3(x) = x^3 ] • 実はこの数式の実装でした ������������ ������ = ������ ������ (������ = 0, ⋯ , ������ − 1) • 繰り返しなんだから、もっとかんたんに できそう
  • 40. ぷちPython講座:リスト内包 • リスト内包 : ルールから配列を作る – for ループを書かなくていい – R の apply() 系の関数に相当 a = [] for x in xrange(10): a.append(x * x) リスト内包なら簡潔! a = [x * x for x in xrange(10)] ※厳密にはいろいろ(ry
  • 41. 「リスト内包」を使えば…… phi = [ lambda x: 1, lambda x: x, ������������ ������ = ������ ������ (������ = 0, ⋯ , ������ − 1) lambda x: x ** 2, lambda x: x ** 3 ] こう書ける気がする phi = [lambda x: x ** m for m in xrange(M)] • かんたんになったね!
  • 42. だめでした…… • ������0 2 , ������1 2 , ������2 2 , ������3 2 を表示してみる – “1 2 4 8” と出力されることを期待 M = 4 phi = [lambda x: x ** m for m in xrange(M)] print phi[0](2), phi[1](2), phi[2](2), phi[3](2) • ところがこれの実行結果は “8 8 8 8” – って、全部同じ!? なんで???
  • 43. うまくいかない理由は…… • 「レキシカルスコープ」がどうとか – ちょっとややこしい • 回避する裏技もあるけど…… – もっとややこしい M = 4 phi = [lambda x, c=m: x ** c for m in xrange(M)] print phi[0](2), phi[1](2), phi[2](2), phi[3](2) # => “1 2 4 8” と表示される(ドヤ
  • 44. 結論 • リスト内包の中では lambda を使わない ようにしよう!(ぇ – これで同種の問題はだいたい避けられる • かんたんに書く他の方法を考えてみる
  • 45. 特徴行列の作り方 (2) • phi を「ベクトルを返す関数」として定義 – ������������ のリストではなく,������ = (������������ )を扱う – lambda を書かなくていい – 関数の呼び出し回数も減って高速化 • 行列の生成にもリスト内包を使う numpy の機能の 一部と言っても – numpy.array(リスト内包) は頻出! いいくらい def phi(x): return [x ** m for m in xrange(4)] PHI = numpy.array([phi(x) for x in X])
  • 46. まとめ • リスト内包は超便利 – 憶えましょう – 憶えてなかったら Python 使ってる意味ない と言い切ってしまっていいくらい • ラムダ式も便利 – でもリスト内包の中で使うとハマることがあ るので避けましょう
  • 47. よだん • numpy.fromfunction() を使って特徴行 列を作る方法もあるよ。あるけど…… – なんかいろいろひどい • take とか dtype=int とか – ダメな numpy の見本 PHI = numpy.fromfunction( lambda n, m: X.take(n) ** m, (N, M), dtype=int)