NORA

雑食気味なひよっこプログラミング記録

今週やったこと

2013/10/19

今日は環境構築をしました。
集合知プログラミングを勉強しようとして、同時にGAE,AngularJSの習熟も出来たら良いじゃないか?と思い立った。
GAE開発サーバーにてAngular-seedを動かすところまで完了。

f:id:hiro_m_18:20131019200847j:plain

2013/10/20

ユークリッド距離とピアソン相関係数について読み、AngularJSで表示、Pythonコード例をJavascriptに手直しして計算をした。
ユークリッド距離はレビュー評価値の付け方に値の大小があると類似性の有無を求められない。代わりに計算が楽。
ピアソン相関係数は値の大小があっても類似性を求められる。代わりに計算量が少々多い。

f:id:hiro_m_18:20131020192243p:plain

function RecommendationsCtrl($scope, recommendations) {
    // サクッと結果確認するための初期値
    $scope.person1 = "Lisa Rose";
    $scope.person2 = "Gene Seymour";

    $scope.critics = recommendations.getCritics();

    $scope.sim_distance = function() {
        // 2人共評価しているアイテムのリストを得る。
        var si = 0;
        var person1 = 0;
        var person2 = 0;
        for(var i=0; i<$scope.critics.length; i++) {
            if(person1==0 && $scope.critics[i].name==$scope.person1) {
                person1 = $scope.critics[i];
            }
            if(person2==0 && $scope.critics[i].name==$scope.person2) {
                person2 = $scope.critics[i];
            }
        }
        for(var i=0; i<person1.marks.length; i++) {
            for(var k=0; k<person2.marks.length; k++) {
                if(person1.marks[i].title==person2.marks[k].title) {
                    si++;
                }
            }
        }

        // 両者共に評価しているものが1つもなければ0を返す。
        if(si==0) {
            $scope.similarity_score = 0;
            return false;
        }

        // すべての差の平方を足し合わせる。
        var sum_of_squares = 0;
        for(var i=0; i<person1.marks.length; i++) {
            for(var k=0; k<person2.marks.length; k++) {
                if(person1.marks[i].title==person2.marks[k].title) {
                    sum_of_squares += Math.pow(person1.marks[i].score-person2.marks[k].score, 2);
                }
            }
        }

        $scope.similarity_score = 1/(1+sum_of_squares);
    };

    $scope.sim_pearson = function() {
        // 両者が互いに評価しているアイテムのリストを取得。
        var si = {}
        var p1 = 0;
        var p2 = 0;
        for(var i=0; i<$scope.critics.length; i++) {
            if(p1==0 && $scope.critics[i].name==$scope.person1) {
                p1 = $scope.critics[i];
            }
            if(p2==0 && $scope.critics[i].name==$scope.person2) {
                p2 = $scope.critics[i];
            }
        }

        for(var i=0; i<p1.marks.length; i++) {
            for(var k=0; k<p2.marks.length; k++) {
                if(p1.marks[i].title==p2.marks[k].title) {
                    si[p2.marks[k].title] = {"p1": p1.marks[i].score, "p2": p2.marks[k].score};
                }
            }
        }

        // 要素の数を調べる。
        var n = 0;
        for(var key in si) {
            n++;
        }

        // 共に評価しているアイテムがなければ0を返す。
        if(!n) {
            $scope.pearson_score = 0;
            return false;
        }

        // すべての嗜好を合計する。
        var sum1 = 0;
        var sum2 = 0;
        for(var key in si) {
            sum1 += si[key].p1;
            sum2 += si[key].p2;
        }

        // 平方を合計する。
        var sum1Sq = 0;
        var sum2Sq = 0;
        for(var key in si) {
            sum1Sq += Math.pow(si[key].p1, 2);
            sum2Sq += Math.pow(si[key].p2, 2);
        }

        // 積を合計する。
        var pSum = 0;
        for(var key in si) {
            pSum += si[key].p1*si[key].p2;
        }

        // ピアソンによるスコアを計算する。
        var num = pSum-(sum1*sum2/n);
        var den = Math.sqrt((sum1Sq-Math.pow(sum1,2)/n) * (sum2Sq-Math.pow(sum2,2)/n));
        if(den==0) {
            $scope.pearson_score = 0;
            return true;
        }

        $scope.pearson_score = num/den;
    }
}