LoginSignup
22
24

More than 3 years have passed since last update.

Pythonの推薦システム向けライブラリSurpriseとFlaskでレコメンデーションエンジンを作成する

Last updated at Posted at 2019-07-01

まずはSurpriseというライブラリをインストールします。

pip install scikit-surprise

recommender.py
import json
from collections import defaultdict

from surprise import SVD
from surprise import Dataset


def get_top_n(predictions, n=10):
    '''
    予測セットに基いて各ユーザにトップN件のレコメンデーションを返す。
    '''

    # まず各ユーザに予測値をマップする。
    top_n = defaultdict(list)
    for uid, iid, true_r, est, _ in predictions:
        top_n[uid].append((iid, est))

    # そして各ユーザに対して予測値をソートして最も高いk個を返す。
    for uid, user_ratings in top_n.items():
        user_ratings.sort(key=lambda x: x[1], reverse=True)
        top_n[uid] = user_ratings[:n]

    return top_n


# まずmovielensデータセットでSVDアルゴリズムを学習させる。
data = Dataset.load_builtin('ml-100k')
trainset = data.build_full_trainset()
algo = SVD()
algo.fit(trainset)

# そして学習用データに含まれていない全ての(ユーザ、アイテムの)組み合わせに対して評価を予測する。
testset = trainset.build_anti_testset()
predictions = algo.test(testset)

top_n = get_top_n(predictions, n=10)

# 各ユーザにレコメンドされるアイテムを表示する。
for uid, user_ratings in top_n.items():
    print(uid, [iid for (iid, _) in user_ratings])

# json形式で結果を保存する。
with open('./results.json', 'w') as f:
    json.dump(top_n, f, indent=2, ensure_ascii=False)
api.py
import json

import flask
from flask import request, jsonify

app = flask.Flask(__name__)
app.config["DEBUG"] = True
app.config['JSON_AS_ASCII'] = False

# データの読み込み
with open('./results.json') as f:
    movies = json.loads(f.read())

# ホーム
# http://127.0.0.1:5000/

@app.route('/', methods=['GET'])
def home():
    return '''<h1>シンプルな推薦システム</h1>
<p>映画レコメンデーションのためのAPIプロトタイプ</p>'''

# 全てのアイテム
# http://127.0.0.1:5000/api/v1/resources/movies/all

@app.route('/api/v1/resources/movies/all', methods=['GET'])
def api_all():
    return jsonify(movies)

# 特定のユーザIDのアイテム
# http://127.0.0.1:5000/api/v1/resources/movies?id=1

@app.route('/api/v1/resources/movies', methods=['GET'])
def api_id():
    # URLにIDが含まれているか確認する。
    # IDが含まれていれば、変数に代入する。
    # IDが含まれていなければブラウザにエラーを表示する。
    if 'id' in request.args:
        id = str(request.args['id'])
    else:
        return "エラー: IDが含まれていません。IDを指定してください。"

    items = movies.get(id)

    # 結果のために空のリストを作成する。
    results = []

    # リストに映画を追加していく。
    for i in range(len(items)):
        item = items[i][0]
        results.append(item)

    # Pythonの辞書のリストをJSON形式に変換するためFlaskのjsonify関数を使う。
    return jsonify(results)

app.run()

ターミナルもしくはコマンドプロンプトで
python recommender.py
を実行して、レコメンドするアイテム一覧を作成。

python api.py
を実行してFlaskアプリケーションを起動。

ブラウザで

http://127.0.0.1:5000/
がホーム画面

http://127.0.0.1:5000/api/v1/resources/movies/all
が全てのアイテム

http://127.0.0.1:5000/api/v1/resources/movies?id=1
がIDが1のユーザに対して推薦するアイテムのID
となります。

何かおかしな点やアドバイス等がございましたらコメントいただけますと幸いです。

参考:
https://surprise.readthedocs.io/en/stable/FAQ.html
https://programminghistorian.org/en/lessons/creating-apis-with-python-and-flask

22
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
24