書籍「集合知プログラミング」の疑問点

集合知プログラミング

集合知プログラミング


とりあえず、2章の「推薦を行う」を読んだだけだけど、疑問点がいろいろ。

ユークリッド距離をだすのに平方をとらなくていいのか

「2.3.1 ユークリッド距離によるスコア」
ユークリッド距離を出すには平方根の定理を使ってこんな感じにするというのはOK。

In [7]: from math import sqrt
In [8]: sqrt(pow(3.5 - 2, 2) + pow(3.5 - 4, 2))
Out[8]: 1.5811388300841898

でもそれを、2つのアイテムじゃなくて全てのアイテムで出力するという関数のサンプルのコードがこんなので謎。

from math import sqrt

# Returns a distance-based similarity score for person1 and person2
def sim_distance(prefs,person1,person2):
  # Get the list of shared_items
  si={}
  for item in prefs[person1]: 
    if item in prefs[person2]: si[item]=1

  # if they have no ratings in common, return 0
  if len(si)==0: return 0

  # Add up the squares of all the differences
  sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2) 
                      for item in prefs[person1] if item in prefs[person2]])

  return 1/(1+sum_of_squares)

リストで済むところをなぜかディクショナリを使ってたり、評価アイテムが重複してるユーザーを探す処理を2回やってるところはまあいいんだけど、最後で、X軸とY軸の違いを2乗した値の合計をした最後に、平方をとってないのが不思議。
疑問に思ったひとはほかにもけっこういるみたいで、http://d.hatena.ne.jp/ksmemo/20080731/p1

ユークリッド距離を基にした類似性スコア」と書いているのでこれでいいのかな、という感じですが。

というのを読んで、あくまで指数なので上下関係が変わらなければいいんじゃないっていうことなのかと暫定的に理解。

類似度は評価ポイントの重み付けに使うだけいいんじゃないのか

「2.4 アイテムを推薦する」
自分と自分以外のユーザーの類似性をもとにして、自分がまだ未評価のアイテムの評価ポイントに、類似度分の重み付けをするというのはOKだけど、最後にそのアイテムを評価しているユーザーの類似度の計で除算するというのが理解できない。
たとえば自分をXとしてこんな感じな類似度だった場合、この本の通りに推薦の度合いをだしちゃうとこうなる。

評者 Xとの類似度 Item1 S.x1 Item2 S.x2
A 0.90 4.00 3.60 0.00
B 0.90 4.00 3.60 0.00
C 0.90 3.00 2.70 0.00
D 0.10 0.00 5.00 0.50
E 0.10 0.00 4.00 0.40
F 0.10 0.00 3.00 0.30
合計 9.90 1.20
評者の類似度の計 2.70 0.30
推薦の度合い 3.67 4.00

これだと、「評価の類似度が高いひとが評価しているアイテム」と「評価の類似度が低いひとが評価しているアイテム」とで、前者が1ポイント低いだけなのに、類似度の低いひとが評価してるアイテムのほうが推薦される結果になってしまう。
普通に評価者の数で割るだけでいいんじゃないのかなー。謎。
「2.7.1 アイテム間の類似度のデータセットを作る」も同様の謎が残ってる。

オライリーのフィードバックページでこの記事へのリンクを送っておこう。