読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

2人間の類似値を取得する

勉強 Scala アルゴリズム

ユークリッド距離で計算。

まずはデータソース

  val source = Map(
    "azalea" -> Map(
      "Java" -> 5,
      "C#" -> 5,
      "Python" -> 2,
      "Perl" -> 2,
      "Scala" -> 5,
      "C" -> 4,
      "C++" -> 4
    ),
    "nullpobug" -> Map(
      "Ruby" -> 4,
      "Python" -> 5,
      "Java" -> 4,
      "PHP" -> 4,
      "Delphi" -> 5,
      "C++" -> 4
    ),
    "delick" -> Map(
      "Java" -> 5,
      "C++" -> 3
    )
  )

で、ここから二者間で共通値を検索する

  def findCommonItem(left:Map[String, Int], right:Map[String, Int]):Iterable[(Int, Int)] = {
    left.filter(kv => {
      val (key, _) = kv
      right.contains(key)
    }).map(kv => {
      val (key, value) = kv
      (value, right(key))
    })
  }
  val commonValue = findCommonItem(source("azalea"), source("nullpobug"))

そしたらそのセットの距離を計算する

  def distance(values:Iterable[(Int, Int)]) = {
    def total = values.foldLeft(0.0){case (value, (left, right)) => {
      value + Math.pow(left - right, 2)
    }}
    Math.sqrt(total)
  }
  val distance = distance(commonValue)

距離が短いほど二者間の距離が近いことになる。が、類似度を計算するならその逆数が必要な筈なので。

  1.0 / (1.0 + distance(commonValue))

commonValue のセットがそもそも 0 だと成り立たないのでその時は 0 を返す。

  def exec(left:Map[String, Int], right:Map[String, Int]) = {
    val commonValue = findCommonItem(left, right)
    if (commonValue.isEmpty) {
      0.0
    } else {
      1.0 / (1.0 + distance(commonValue))
    }
  }

が、これでも欠点はある。 上記なんかが良い例で、一致するサンプル数が少ないと正確に比較ができない。