集合知プログラミングの勉強(1)

集合知プログラミング」を集中的に勉強する。ただし既に風邪で1日ロス。熱は下がったのでがんばろう。

素直に python でやろうとしたが、補完の効かない(正確には貧弱な) python(emacs python-mode) の repl では何かと辛い。recommendations.sim_distance(recommendations.critics, ... ) なんて長ったらしい文字列は、無精なわたしには入力できない。あきらめて SBCL(emacs slime mode)に移行。既に id:miyamuko さんが xyzzy集合知プログラミングの勉強をされているので真似させてもらおう。

現時点で気付いたこの本で嬉しくないところとして、数式が無くいきなりプログラムで説明している。(5/3 訂正。付録に数式の記載あり。)関連して変数名の付け方がいまいち気に入らない。
ともかく今日はまず 2.4 まで。趣味で loop で書いているが、最近 scheme ばっかり(すなわち再帰ばっかり)だったのでほとんど何もかも忘れていた。

;; pci chapter 2
;; data from http://d.hatena.ne.jp/miyamuko/20090224/pci_sim_euclid_distance by id:miyamuko

(defparameter *critics*
  '(("Lisa Rose"
     ("Lady in the Water" . 2.5)
     ("Snakes on a Plane" . 3.5)
     ("Just My Luck" . 3.0)
     ("Superman Returns" . 3.5)
     ("You, Me and Dupree" . 2.5)
     ("The Night Listener" . 3.0))
    ("Gene Seymour"
     ("Lady in the Water" . 3.0)
     ("Snakes on a Plane" . 3.5)
     ("Just My Luck" . 1.5)
     ("Superman Returns" . 5.0)
     ("The Night Listener" . 3.0)
     ("You, Me and Dupree" . 3.5))
    ("Michael Phillips"
     ("Lady in the Water" . 2.5)
     ("Snakes on a Plane" . 3.0)
     ("Superman Returns" . 3.5)
     ("The Night Listener" . 4.0))
    ("Claudia Puig"
     ("Snakes on a Plane" . 3.5)
     ("Just My Luck" . 3.0)
     ("The Night Listener" . 4.5)
     ("Superman Returns" . 4.0)
     ("You, Me and Dupree" . 2.5))
    ("Mick LaSalle"
     ("Lady in the Water" . 3.0)
     ("Snakes on a Plane" . 4.0)
     ("Just My Luck" . 2.0)
     ("Superman Returns" . 3.0)
     ("The Night Listener" . 3.0)
     ("You, Me and Dupree" . 2.0))
    ("Jack Matthews"
     ("Lady in the Water" . 3.0)
     ("Snakes on a Plane" . 4.0)
     ("The Night Listener" . 3.0)
     ("Superman Returns" . 5.0)
     ("You, Me and Dupree" . 3.5))
    ("Toby"
     ("Snakes on a Plane" . 4.5)
     ("You, Me and Dupree" . 1.0)
     ("Superman Returns" . 4.0))
    ("Crane"
     ("Dolly with the Star of Life" . 5.0)
     ("EDEN (Chubo-de-ai-masyou)" . 5.0)
     ("Mamma-miya!" . 4.5))
    ("Toby-Clone"
     ("You, Me and Dupree" . 1.0)
     ("Superman Returns" . 4.0)
     ("Snakes on a Plane" . 4.5))
    ))

;; 2.3.1 euclid distance
(defun sim-distance (prefs person1 person2)
  (let ((pref1 (cdr (assoc person1 prefs :test #'equal)))
        (pref2 (cdr (assoc person2 prefs :test #'equal))))
    (let ((lst (loop for (title1 . score1) in pref1
                 for data2 = (find title1 pref2 :key #'car :test #'equal)
                 if data2
                 collect (expt (- score1 (cdr data2)) 2))))
      (if (= (length lst) 0)
          0
          (/ 1 (1+ (apply #'+ lst)))))))

(defun find-most-sim (prefs)
  (let ((persons (mapcar #'car prefs)))
    (loop for p1 in persons
       append
         (loop for p2 in persons
            unless (equal p1 p2)
            collect (list p1 p2 (sim-distance prefs p1 p2))))))

;; 2.3.2 pierson
(defun sim-pearson (prefs person1 person2)
  (let ((pref1 (cdr (assoc person1 prefs :test #'equal)))
        (pref2 (cdr (assoc person2 prefs :test #'equal))))
    (loop for (title1 . score1) in pref1
       for score2 = (cdr (find title1 pref2 :key #'car :test #'equal))
       if score2
       collect title1 into titles and
       sum score1 into sum1 and
       sum score2 into sum2 and
       sum (expt score1 2) into sum1sq and
       sum (expt score2 2) into sum2sq and
       sum (* score1 score2) into psum
       finally
         (if (= (length titles) 0)
             (return 0)
             (let* ((n (length titles))
                    (num (- psum (/ (* sum1 sum2) n)))
                    (den (sqrt (* (- sum1sq (/ (expt sum1 2) n))
                                  (- sum2sq (/ (expt sum2 2) n))))))
               (if (= den 0)
                   (return 0)
                   (return (/ num den))))))))

とりあえずは動いてそうだけど明日ちゃんと確かめる。熱が上がる前に寝よう。