簡単な推薦システムを作ってみた

ある人の使用しているプログラミング言語から、次に学習すべきプログラミング言語の推薦システムを簡単に作った。

Python3.5でかいた。 参考書籍はこれ。

データサイエンティスト養成読本 機械学習入門編 (Software Design plus)

データサイエンティスト養成読本 機械学習入門編 (Software Design plus)

データ

データはこれ。

Ruby,Python,HTML/CSS/JS,C,C++,Java,PHP,C#
0,5,2,0,3,4,1,0
4,0,0,0,0,0,5,0
0,0,0,5,4,0,0,0
0,3,2,0,5,4,0,0
0,5,4,0,0,2,0,0
3,0,2,0,5,4,0,0
0,0,0,0,4,3,0,5
0,1,2,5,4,0,0,3
0,4,0,5,0,0,0,0
0,4,0,0,5,0,0,0
0,0,0,0,4,5,0,0
3,4,1,0,0,5,2,0
5,4,2,0,0,0,0,3
4,5,0,0,0,0,0,0
3,0,4,0,0,5,0,0
5,0,4,0,3,0,0,0
3,0,0,0,0,5,4,0
0,0,3,5,4,0,0,0
0,0,0,5,4,0,0,3
0,4,0,5,0,3,0,0
4,0,3,0,0,0,0,5
0,4,0,0,5,0,0,0

Twitterのフォロワーさんのプロフィールを元にデータを作りました。 プロフィールの一番左に書いてあるプログラミング言語を評価値を5として、右にいくにつれてデクリメント。

例えば、 C/C++/Ruby/JS なら Cの評価値を5、C++の評価値を4、Rubyの評価値を3、そしてJSの評価値を2みたいな感じで、最大5個まで評価値をつけていった。

書いていない言語は触ったことがないものとして、評価値を0にした。

コード

処理としては、推薦したい人が習得している言語と、似たような傾向を持った人が習得している言語を推薦している。

似てるか似てないかは、コサイン距離を用いて表現している。

# coding:utf-8

import numpy as np
import scipy as sp
from scipy.spatial.distance import cosine

def calc_item_score(target_user_index, user_rating_matrix):
    """
    指定したアイテムの評価値を計算する
    :param target_user_index: int: ユーザのIndex
    :param user_rating_matrix: numpy.ndarray: ユーザアイテムの評価値行列
    :return: float: 指定したアイテムの評価値
    """

    target_user_ratings = user_rating_matrix[target_user_index]
    item_similarity = np.zeros(len(target_user_ratings))

    for compare_user_index in np.arange(len(user_rating_matrix)):
        compare_user_ratings = user_rating_matrix[compare_user_index]
        if compare_user_index == target_user_index:
            # 同一ユーザのときは類似度計算はしない
            continue

        # ユーザの類似度をコサイン距離から求める
        user_similarity = 1.0 - cosine(target_user_ratings, compare_user_ratings)
        # 求めたコサイン距離をそのユーザの評価値に乗じて足しあわせる
        item_similarity += user_similarity * compare_user_ratings

    return item_similarity

# データ読み込み
data = sp.loadtxt("data.csv",delimiter=",",skiprows=1)

# 推薦計算
predict_ratings = calc_item_score(0,data)

# 推薦したい言語の取得
header = ['Ruby','Python','HTML/CSS/JS','C','C++','Java','PHP','C\#']
zero_index = np.nonzero(data[0,:] != 0)
for i in zero_index:
    predict_ratings[i] = 0.0
max_index = np.where(predict_ratings == predict_ratings.max())
print("次は ",end="")
print(header[max_index[0][0]],end="")
print(" をやるんやで")

実行結果

% python main.py
次は Ruby をやるんやで

となる。