tanimoto score

忘れないうちに。
Tanimotoさんがどんな人なのかはまだ調べてない。化学系の分子同定とかで分子fingerprintsの類似度として良くつかわれているみたい。
Wikipediaをみると
http://en.wikipedia.org/wiki/Jaccard_index
Jaccard indexのところに Tanimoto Coefficientとして書かれていた。他のサイトを見るとJaccard indexの事を Tanimoto Scoreと称している物も結構あったりで、そりゃ間違ってはいないけども、という感じ。基本的には Tanimoto coefficient は Jaccard indexの拡張で、Jaccardが真理値ベクトルしか考えてないのに対して、そうでない場合に一般化したのがTanimoto係数。
詳細は Wikipediaにゆずるとして Jaccard indexは実に単純明快。真理値ベクトルの AND(重なり)を OR(1全体)で割っただけ。あ、当たり前すぎる。。。いや全体から0の所を除いているのがスゴいのかな。うん。きっとそうだ。Jaccard距離の方は 1-JIndex。これも当たり前すぐる。
これを一般化した Tanimoto coefficientはJaccardの分子 - ANDをベクトル同士の内積で表し、分母 - OR を 各ベクトルのノルムから内積(重なり)を引いたもので表す、というなるほどなあ、という方法。
と断定的に書いてきて少しだけ不安になってきた。情けない。

def dot(a,b):
  len_a = len(a)
  if len_a != len(b): raise "INVALID"
  return sum([a[i]*b[i] for i in xrange(len_a)])

def tanimoto(a,b):
   d_ab = dot(a,b)
   return d_ab / (dot(a,a) + dot(b,b) - d_ab)
    
>>> tanimoto([1.0, 0.0, 0.0, 1.0], [1.0, 0.0, 1.0, 1.0])
0.66666666666666663

こういうとき内積が標準である言語はラクだよなあ。

> tanimoto <- function(a,b) {
+  (a%*%b) / (a%*%a + b%*%b - a%*%b)
+ }
> tanimoto(c(1, 0, 1, 1), c(1, 0, 0, 1))
          [,1]
[1,] 0.6666667

一瞬誤差ってると勘違いして更に自信をなくす(←バカ)