集合知プログラミング 2章 ユークリッド距離

せっかくなのでJavaで書いてみた。
お気に入りのPerlでも書こうと思ったけど一緒に読む人間がPerl分からないのでまずはJavaで。
ていうかPerlで書いてる方がいるんですね。あとで真似してみよう。
集合知プログラミング 2章 その1 ユークリッド距離 - ケーズメモ


ユークリッド距離とは、要するに空間上の距離ということらしい。
座標(p_1,p_2,...p_n),(q_1,q_2,...q_n)を持つ2点のユークリッド距離d
d^2=\sum_{i=1}^n(p_i-q_i)^2
から計算される。


この章では、類似性スコアを求めて後で重み付けに使うためにこれに1を加えて逆数を取ったものを使うようだ。
こうすることで常に0から1の間の値を返すようになり、類似性が高ければ1に近くなる。


Common.java

package chapter2;

public class Common {
    final static String LisaRose        = "Lisa Rose";
    final static String GeneSeymour     = "Gene Seymour";
    final static String MichaelPhillips = "Michael Phillips";
    final static String ClaudiaPuig     = "Claudia Puig";
    final static String MickLassalle    = "Mick Lassalle";
    final static String JackMatthews    = "Jack Matthews";
    final static String Toby            = "Toby";
    
    final static String LadyInTheWater          = "Lady in the Water";
    final static String SnakesOnAPlane          = "Snakes on a plane";
    final static String JustMyLuck              = "Just My Luck";
    final static String SupermanReturns         = "Superman Returns";
    final static String YouMeAndDupree          = "You, Me and Dupree";
    final static String TheNightListener        = "The Night Listener";
}


Critics.java

package chapter2;

import java.util.HashMap;
import java.util.Map;

public class Critics {
    private Map<String, Map<String, Double>> data = new HashMap<String, Map<String, Double>>();
    
    /**
     * データ読み込みによる初期化
     */
    public Critics() {
        /* Lisa Rose */
        HashMap<String, Double> mapLisaRose = new HashMap<String, Double>();
        mapLisaRose.put(Common.LadyInTheWater, Double.valueOf(2.5));
        mapLisaRose.put(Common.SnakesOnAPlane, Double.valueOf(3.5));
        mapLisaRose.put(Common.JustMyLuck, Double.valueOf(3.0));
        mapLisaRose.put(Common.SupermanReturns, Double.valueOf(3.5));
        mapLisaRose.put(Common.YouMeAndDupree, Double.valueOf(2.5));
        mapLisaRose.put(Common.TheNightListener, Double.valueOf(3.0));
        data.put(Common.LisaRose, mapLisaRose);
        /* Gene Seymour */
        HashMap<String, Double> mapGeneSeymour = new HashMap<String, Double>();
        mapGeneSeymour.put(Common.LadyInTheWater, Double.valueOf(3.0));
        mapGeneSeymour.put(Common.SnakesOnAPlane, Double.valueOf(3.5));
        mapGeneSeymour.put(Common.JustMyLuck, Double.valueOf(1.5));
        mapGeneSeymour.put(Common.SupermanReturns, Double.valueOf(5.0));
        mapGeneSeymour.put(Common.TheNightListener, Double.valueOf(3.0));
        mapGeneSeymour.put(Common.YouMeAndDupree, Double.valueOf(3.5));
        data.put(Common.GeneSeymour, mapGeneSeymour);
        /* Michael Phillips */
        HashMap<String, Double> mapMichaelPhillips = new HashMap<String, Double>();
        mapMichaelPhillips.put(Common.LadyInTheWater, Double.valueOf(2.5));
        mapMichaelPhillips.put(Common.SnakesOnAPlane, Double.valueOf(3.0));
        mapMichaelPhillips.put(Common.SupermanReturns, Double.valueOf(3.5));
        mapMichaelPhillips.put(Common.TheNightListener, Double.valueOf(4.0));
        data.put(Common.MichaelPhillips, mapMichaelPhillips);
        /* Claudia Puig */
        HashMap<String, Double> mapClaudiaPuig = new HashMap<String, Double>();
        mapClaudiaPuig.put(Common.SnakesOnAPlane, Double.valueOf(3.5));
        mapClaudiaPuig.put(Common.JustMyLuck, Double.valueOf(3.0));
        mapClaudiaPuig.put(Common.TheNightListener, Double.valueOf(4.5));
        mapClaudiaPuig.put(Common.SupermanReturns, Double.valueOf(4.0));
        mapClaudiaPuig.put(Common.YouMeAndDupree, Double.valueOf(2.5));
        data.put(Common.ClaudiaPuig, mapClaudiaPuig);
        /* Mick Lasalle */
        HashMap<String, Double> mapMickLasalle = new HashMap<String, Double>();
        mapMickLasalle.put(Common.LadyInTheWater, Double.valueOf(3.0));
        mapMickLasalle.put(Common.SnakesOnAPlane, Double.valueOf(4.0));
        mapMickLasalle.put(Common.JustMyLuck, Double.valueOf(2.0));
        mapMickLasalle.put(Common.SupermanReturns, Double.valueOf(3.0));
        mapMickLasalle.put(Common.TheNightListener, Double.valueOf(3.0));
        mapMickLasalle.put(Common.YouMeAndDupree, Double.valueOf(2.0));
        data.put(Common.MickLassalle, mapMickLasalle);
        /* Jack Matthews */
        HashMap<String, Double> mapJackMatthews = new HashMap<String, Double>();
        mapJackMatthews.put(Common.LadyInTheWater, Double.valueOf(3.0));
        mapJackMatthews.put(Common.SnakesOnAPlane, Double.valueOf(4.0));
        mapJackMatthews.put(Common.TheNightListener, Double.valueOf(3.0));
        mapJackMatthews.put(Common.SupermanReturns, Double.valueOf(5.0));
        mapJackMatthews.put(Common.YouMeAndDupree, Double.valueOf(3.5));
        data.put(Common.JackMatthews, mapJackMatthews);
        /* Toby */
        HashMap<String, Double> mapToby = new HashMap<String, Double>();
        mapToby.put(Common.SnakesOnAPlane, Double.valueOf(4.5));
        mapToby.put(Common.YouMeAndDupree, Double.valueOf(1.0));
        mapToby.put(Common.SupermanReturns, Double.valueOf(4.0));
        data.put(Common.Toby, mapToby);
    }

    public Map<String, Double> getMap(String key) {
        return data.get(key);
    }
}


SimiralityCalculator.java

package chapter2;

public abstract class SimilarityCalculator {
    protected Critics data = new Critics();
    
    abstract double getSimilarity(String lhs, String rhs);
}


DistanceCalculator.java

package chapter2;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class DistanceCalculator extends SimilarityCalculator {

    /* (non-Javadoc)
     * @see chapter2.SimilarityCalculator#getSimilarity(java.lang.String, java.lang.String)
     */
    @Override
    double getSimilarity(String lhs, String rhs) {
        Map<String, Double> lhsMap = data.getMap(lhs);
        Map<String, Double> rhsMap = data.getMap(rhs);
        // どちらかでも存在していなければ0.0を返す
        if ((lhsMap == null) || (rhsMap == null)) {
            return 0.0;
        }
        
        // 共通しているものが一つもなければ0.0を返す
        List<String> commonKeyList = new LinkedList<String>();
        Iterator<String> iterKey = lhsMap.keySet().iterator();
        while (iterKey.hasNext()) {
            String key = iterKey.next();
            if (rhsMap.containsKey(key)) {
                commonKeyList.add(key);
            }
        }
        if (commonKeyList.size() == 0) {
            return 0.0;
        }
        
        // すべての差の平方を足し合わせる
        double sumOfSquares = 0.0;
        Iterator<String> iterList = commonKeyList.iterator();
        while (iterList.hasNext()) {
            String key = iterList.next();
            double difference = lhsMap.get(key).doubleValue() - rhsMap.get(key).doubleValue();
            sumOfSquares += difference * difference;
        }
        
        return 1.0 / (1.0 + sumOfSquares);
    }
}


Main.java

package chapter2;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        SimilarityCalculator simcal = new DistanceCalculator();
        System.out.println(simcal.getSimilarity(Common.LisaRose, Common.GeneSeymour));
    }

}


実行結果。

0.14814814814814814

うん、とりあえず本の例題と同じ結果は得られてるっぽい。