trybeetle

take it slow!!

recommender systemについて


Posted on Aug. 1, 2018, 7:50 a.m.



recommender systemについて記載します。今回は、映画に対するユーザ評価のrecommender systemです。
CourseraのMachine Learningコースを元にしています。

商品の特徴(X)とユーザの嗜好(θ)からユーザの商品に対する評価を求めます。また、recommender systemでは、θの初期値を決めることで、θ⇒X⇒θ⇒X⇒θ...というように、θとXでお互いに最適解を求めることができます。


データの読み込み

まず、データを読み込みます。Yは、映画数(m)とユーザ数(j)のmatrixです。Rは、matrix Yにratingがされている場合にr=1(ratingされていない場合はr=0)とするbinary matrixです。


    load ('ex8_movies.mat');

続いて、movieListを作成します。作成元となるmovie_ids.txtファイルは下記の様な形です。
1 Toy Story (1995)
2 GoldenEye (1995)
3 Four Rooms (1995)


    function movieList = loadMovieList()
    fid = fopen('movie_ids.txt');
    n = 1682;  % Total number of movies
    movieList = cell(n, 1);
    for i = 1:n
        % Read line
        line = fgets(fid);
        % Word Index (can ignore since it will be = i)
        [idx, movieName] = strtok(line, ' ');
        % Actual Word
        movieList{i} = strtrim(movieName);
    endfor
    fclose(fid);
    end

    movieList = loadMovieList();

ratingの追加

ex8_movies.matをロードした際に既に、rating表(縦:映画作品、横:ユーザ)が読み込まれますが、ユーザを新規に追加し、幾つかの映画に対してratingを行います。ここでは、1682作品中11作品に対してratingを行います。


    my_ratings = zeros(1682, 1);
    my_ratings(1) = 4;
    my_ratings(98) = 2;
    my_ratings(7) = 3;
    my_ratings(12)= 5;
    my_ratings(54) = 4;
    my_ratings(64)= 5;
    my_ratings(66)= 3;
    my_ratings(69) = 5;
    my_ratings(183) = 4;
    my_ratings(226) = 5;
    my_ratings(355)= 5;

    fprintf('\n\nNew user ratings:\n');
    for i = 1:length(my_ratings)
        if my_ratings(i) > 0
            fprintf('Rated %d for %s\n', my_ratings(i), ...
                     movieList{i});
        endif
    endfor

新規ユーザのratingデータを既存のrating表に追加します。


    Y = [my_ratings Y];
    R = [(my_ratings ~= 0) R];

    num_users = size(Y, 2);
    num_movies = size(Y, 1);
    num_features = 10;

データのnormalization

rating表を0を中心にnormalizationします。


    function [Ynorm, Ymean] = normalizeRatings(Y, R)
    [m, n] = size(Y);
    Ymean = zeros(m, 1);
    Ynorm = zeros(size(Y));
    for i = 1:m
        idx = find(R(i, :) == 1);
        Ymean(i) = mean(Y(i, idx));
        Ynorm(i, idx) = Y(i, idx) - Ymean(i);
    endfor
    end

    [Ynorm, Ymean] = normalizeRatings(Y, R);

XとThetaの初期値

続いて、XとThetaの初期値を設定します。ランダムな数値を割り当てます。Xは映画数(num_movies)と特徴数(num_features)のmatrixです。Thetaは、ユーザ数(num_users)と特徴数(num_features)のmatrixです。

後述のfmincg実行時に引数を1つしか指定できないので、XとThetaを一つのベクトルに纏めます。


    X = randn(num_movies, num_features);
    Theta = randn(num_users, num_features);

    initial_parameters = [X(:); Theta(:)];

Cost functionの定義

gradientを実行する際に使用する目的関数を定義します。この関数を実行することで、XとThetaのGradientを一つのベクトルに纏めたgradを求めます。


    function [J, grad] = cofiCostFunc(params, Y, R, num_users, num_movies, num_features, lambda)
    X = reshape(params(1:num_movies*num_features), num_movies, num_features);
    Theta = reshape(params(num_movies*num_features+1:end), num_users, num_features);
    J = 0;
    X_grad = zeros(size(X));
    Theta_grad = zeros(size(Theta));
    Rdiff= (X*Theta' - Y).*R;
    Jreg = lambda/2 * sum(sum(Theta.^2)) + lambda/2 * sum(sum(X.^2));
    J = 1/2 * sum(sum(Rdiff.^2)) + Jreg;
    Xreg = lambda * X;
    X_grad = Rdiff*Theta + Xreg;
    Thetareg = lambda * Theta;
    Theta_grad = Rdiff'*X + Thetareg;
    grad = [X_grad(:); Theta_grad(:)];

    end

Gradientの実行

fmincgでGradientを実行します。iteration回数は100回、lambdaの値は10としています。


    options = optimset('GradObj', 'on', 'MaxIter', 100);
    lambda = 10;
    theta = fmincg (@(t)(cofiCostFunc(t, Ynorm, R, num_users, num_movies, num_features, lambda)), initial_parameters, options);

上記で求めたthetaを、XとThetaに分解します。


    X = reshape(theta(1:num_movies*num_features), num_movies, num_features);
    Theta = reshape(theta(num_movies*num_features+1:end), num_users, num_features);

以上でXとThetaの最適解まで求まりました。


recommend機能の実行

上で求めたXとThetaを元に、ratingを推測します。
なお、Yの値はnormalizationしていたので、pの値には、Ymeanを加算します。


    p = X * Theta';
    my_predictions = p(:,1) + Ymean;

my_predictionsの値を評価の高い順でSortし、上位10作品をrecommendします。


    [r, ix] = sort(my_predictions, 'descend');
    fprintf('\nTop recommendations for you:\n');
    for i=1:10
        j = ix(i);
        fprintf('Predicting rating %.1f for movie %s\n', my_predictions(j), ...
                movieList{j});
    end

以上です。


Category:ML
Tag: ML Octave
Aug. 1, 2018, 7:50 a.m.

Comments